mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
txscript: Cleanup and add tests for lshift opcode.
This cleans up the code for handling the left shift opcode to explicitly call out its semantics which are likely not otherwise obvious as well as improve its readability. It also adds several tests to the reference script tests which exercise the semantics of the left shift opcode including both positive and negative tests.
This commit is contained in:
parent
37fcf957dd
commit
f8d8dbcd19
@ -88,6 +88,16 @@
|
||||
["2147483648 1", "ROTL 1 EQUAL", "P2SH,STRICTENC", "ROTL must fail with input value >4 bytes"],
|
||||
["1 2147483648", "ROTL TRUE", "P2SH,STRICTENC", "ROTL must fail with rotation count >4 bytes"],
|
||||
|
||||
["Left bit shift related test coverage"],
|
||||
["", "LSHIFT NOT", "P2SH,STRICTENC", "LSHIFT requires an input value"],
|
||||
["1", "LSHIFT TRUE", "P2SH,STRICTENC", "LSHIFT requires a shift count"],
|
||||
["NOP 1", "LSHIFT NOT", "P2SH,STRICTENC", "LSHIFT input value must be numeric"],
|
||||
["1 NOP", "LSHIFT TRUE", "P2SH,STRICTENC", "LSHIFT shift count must be numeric"],
|
||||
["2 -1", "LSHIFT 1 EQUAL", "P2SH,STRICTENC", "LSHIFT must fail with negative shift count"],
|
||||
["1 33", "LSHIFT 0 EQUAL", "P2SH,STRICTENC", "LSHIFT must fail with shift count >32"],
|
||||
["2147483648 1", "LSHIFT TRUE", "P2SH,STRICTENC", "LSHIFT must fail with input value >4 bytes"],
|
||||
["1 2147483648", "LSHIFT TRUE", "P2SH,STRICTENC", "LSHIFT must fail with shift count >4 bytes"],
|
||||
|
||||
["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved"],
|
||||
["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"],
|
||||
["0","NOP", "P2SH,STRICTENC"],
|
||||
|
||||
@ -153,9 +153,44 @@
|
||||
["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC"],
|
||||
["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC"],
|
||||
["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC"],
|
||||
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC"],
|
||||
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC"],
|
||||
|
||||
["Left bit shift related test coverage"],
|
||||
["1 1", "LSHIFT 2 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 1"],
|
||||
["1 2", "LSHIFT 4 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 2"],
|
||||
["1 3", "LSHIFT 8 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 3"],
|
||||
["1 4", "LSHIFT 16 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 4"],
|
||||
["1 5", "LSHIFT 32 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 5"],
|
||||
["1 6", "LSHIFT 64 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 6"],
|
||||
["1 7", "LSHIFT 128 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 7"],
|
||||
["1 8", "LSHIFT 256 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 8"],
|
||||
["1 9", "LSHIFT 512 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 9"],
|
||||
["1 10", "LSHIFT 1024 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 10"],
|
||||
["1 11", "LSHIFT 2048 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 11"],
|
||||
["1 12", "LSHIFT 4096 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 12"],
|
||||
["1 13", "LSHIFT 8192 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 13"],
|
||||
["1 14", "LSHIFT 16384 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 14"],
|
||||
["1 15", "LSHIFT 32768 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 15"],
|
||||
["1 16", "LSHIFT 65536 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 16"],
|
||||
["1 17", "LSHIFT 131072 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 17"],
|
||||
["1 18", "LSHIFT 262144 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 18"],
|
||||
["1 19", "LSHIFT 524288 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 19"],
|
||||
["1 20", "LSHIFT 1048576 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 20"],
|
||||
["1 21", "LSHIFT 2097152 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 21"],
|
||||
["1 22", "LSHIFT 4194304 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 22"],
|
||||
["1 23", "LSHIFT 8388608 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 23"],
|
||||
["1 24", "LSHIFT 16777216 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 24"],
|
||||
["1 25", "LSHIFT 33554432 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 25"],
|
||||
["1 26", "LSHIFT 67108864 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 26"],
|
||||
["1 27", "LSHIFT 134217728 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 27"],
|
||||
["1 28", "LSHIFT 268435456 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 28"],
|
||||
["1 29", "LSHIFT 536870912 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 29"],
|
||||
["1 30", "LSHIFT 1073741824 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 30"],
|
||||
["1 31", "LSHIFT -2147483648 EQUAL", "P2SH,STRICTENC", "LSHIFT must be able to produce a 5-byte result (0x1 << 31)"],
|
||||
["1 32", "LSHIFT 0 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x1 << 32"],
|
||||
["-1431655766 1", "LSHIFT 1431655764 EQUAL", "P2SH,STRICTENC", "LSHIFT 0xaaaaaaaa << 1"],
|
||||
["1431655765 1", "LSHIFT -1431655766 EQUAL", "P2SH,STRICTENC", "LSHIFT 0x55555555 << 1"],
|
||||
|
||||
["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC"],
|
||||
["0x4d 0x0000","0 EQUAL", "P2SH,STRICTENC"],
|
||||
["0x4e 0x00000000","0 EQUAL", "P2SH,STRICTENC"],
|
||||
|
||||
@ -1994,34 +1994,47 @@ func opcodeMod(op *parsedOpcode, vm *Engine) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// opcodeLShift pushes the top two items off the stack as integers. Both ints are
|
||||
// interpreted as int32s. The first item becomes the depth to shift left, while
|
||||
// the second item is shifted that depth to the left. The shifted item is pushed
|
||||
// back to the stack as an integer.
|
||||
// opcodeLShift treats the top two items of the data stack as 32-bit integers
|
||||
// where the top item represents the number of bits to left shift (up to 32),
|
||||
// and the second item represents the value to shift, and replaces them both
|
||||
// with the result of the shift.
|
||||
//
|
||||
// Stack transformation: [... x1 x2] -> [... x1 << x2]
|
||||
func opcodeLShift(op *parsedOpcode, vm *Engine) error {
|
||||
// WARNING: Since scriptNums are signed, a standard 4-byte scriptNum only
|
||||
// supports up to a maximum of 2^31-1. The value (v1) really should allow
|
||||
// 5-byte scriptNums and have an overflow check later to clamp it to uint32,
|
||||
// so the full range of uint32 could be covered. This has undesirable
|
||||
// consequences on the semantics of left shift such that attempting to
|
||||
// do ((0x40000000 << 1) << 1) will fail due to the first shift producing
|
||||
// a value greater than the max int32 while (0x40000000 << 2) will work as
|
||||
// expected.
|
||||
//
|
||||
// Unfortunately, a 4-byte scriptNum is now part of consensus, so changing
|
||||
// it requires a consensus vote.
|
||||
v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x2
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v1, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) // x1
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v032 := v0.Int32()
|
||||
v132 := v1.Int32()
|
||||
// The count and value are limited to int32 via the above, so it is safe to
|
||||
// cast them.
|
||||
count := v0.Int32()
|
||||
value := v1.Int32()
|
||||
|
||||
// Don't allow invalid or pointless shifts.
|
||||
if v032 < 0 {
|
||||
if count < 0 {
|
||||
return ErrNegativeShift
|
||||
}
|
||||
if v032 > 32 {
|
||||
if count > 32 {
|
||||
return ErrShiftOverflow
|
||||
}
|
||||
|
||||
vm.dstack.PushInt(scriptNum(v132 << uint(v032)))
|
||||
vm.dstack.PushInt(scriptNum(value << uint(count)))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user