parent
495c1b0565
commit
9f0bc2aaf5
1 changed files with 149 additions and 0 deletions
|
@ -3331,6 +3331,155 @@ func TestBitAndNumericOpcodes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
var stackIsolationTestCases = map[opcode.Opcode][]struct {
|
||||
name string
|
||||
params []interface{}
|
||||
}{
|
||||
opcode.CALLE: {
|
||||
{
|
||||
name: "no_params",
|
||||
},
|
||||
{
|
||||
name: "with_params",
|
||||
params: []interface{}{big.NewInt(5), true, []byte{1, 2, 3}},
|
||||
},
|
||||
},
|
||||
opcode.CALLED: {
|
||||
{
|
||||
name: "no_paranms",
|
||||
},
|
||||
{
|
||||
name: "with_params",
|
||||
params: []interface{}{big.NewInt(5), true, []byte{1, 2, 3}},
|
||||
},
|
||||
},
|
||||
opcode.CALLET: {
|
||||
{
|
||||
name: "no_params",
|
||||
},
|
||||
{
|
||||
name: "with_params",
|
||||
params: []interface{}{big.NewInt(5), true, []byte{1, 2, 3}},
|
||||
},
|
||||
},
|
||||
opcode.CALLEDT: {
|
||||
{
|
||||
name: "no_params",
|
||||
},
|
||||
{
|
||||
name: "with_params",
|
||||
params: []interface{}{big.NewInt(5), true, []byte{1, 2, 3}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestStackIsolationOpcodes(t *testing.T) {
|
||||
scriptHash := util.Uint160{1, 2, 3}
|
||||
for code, codeTestCases := range stackIsolationTestCases {
|
||||
t.Run(code.String(), func(t *testing.T) {
|
||||
for _, testCase := range codeTestCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
rvcount := len(testCase.params) + 1 // parameters + DEPTH
|
||||
pcount := len(testCase.params)
|
||||
prog := []byte{byte(code), byte(rvcount), byte(pcount)}
|
||||
if code == opcode.CALLE || code == opcode.CALLET {
|
||||
prog = append(prog, scriptHash.BytesBE()...)
|
||||
}
|
||||
prog = append(prog, byte(opcode.RET))
|
||||
|
||||
vm := load(prog)
|
||||
vm.SetScriptGetter(func(in util.Uint160) ([]byte, bool) {
|
||||
if in.Equals(scriptHash) {
|
||||
return makeProgram(opcode.DEPTH), true
|
||||
}
|
||||
return nil, false
|
||||
})
|
||||
if code == opcode.CALLED || code == opcode.CALLEDT {
|
||||
vm.Context().hasDynamicInvoke = true
|
||||
}
|
||||
if code == opcode.CALLET || code == opcode.CALLEDT {
|
||||
vm.Context().rvcount = rvcount
|
||||
}
|
||||
// add extra parameter just to check that it won't appear on new estack
|
||||
vm.estack.PushVal(7)
|
||||
for _, param := range testCase.params {
|
||||
vm.estack.PushVal(param)
|
||||
}
|
||||
if code == opcode.CALLED || code == opcode.CALLEDT {
|
||||
vm.estack.PushVal(scriptHash.BytesBE())
|
||||
}
|
||||
|
||||
runVM(t, vm)
|
||||
elem := vm.estack.Pop() // depth should be equal to params count, as it's a separate execution context
|
||||
assert.Equal(t, int64(pcount), elem.BigInt().Int64())
|
||||
for i := pcount; i > 0; i-- {
|
||||
p := vm.estack.Pop()
|
||||
assert.Equal(t, testCase.params[i-1], p.value.Value())
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCALLIAltStack(t *testing.T) {
|
||||
prog := []byte{
|
||||
byte(opcode.PUSH1),
|
||||
byte(opcode.DUP),
|
||||
byte(opcode.TOALTSTACK),
|
||||
byte(opcode.JMP), 0x5, 0, // to CALLI (+5 including JMP parameters)
|
||||
byte(opcode.FROMALTSTACK), // altstack is empty, so panic here
|
||||
byte(opcode.RET),
|
||||
byte(opcode.CALLI), byte(0), byte(0), 0xfc, 0xff, // to FROMALTSTACK (-4) with clean stacks
|
||||
byte(opcode.RET),
|
||||
}
|
||||
|
||||
vm := load(prog)
|
||||
checkVMFailed(t, vm)
|
||||
}
|
||||
|
||||
func TestCALLIDEPTH(t *testing.T) {
|
||||
prog := []byte{
|
||||
byte(opcode.PUSH3),
|
||||
byte(opcode.PUSH2),
|
||||
byte(opcode.PUSH1),
|
||||
byte(opcode.JMP), 0x5, 0, // to CALLI (+5 including JMP parameters)
|
||||
byte(opcode.DEPTH), // depth is 2, put it on stack
|
||||
byte(opcode.RET),
|
||||
byte(opcode.CALLI), byte(3), byte(2), 0xfc, 0xff, // to DEPTH (-4) with [21 on stack
|
||||
byte(opcode.RET),
|
||||
}
|
||||
|
||||
vm := load(prog)
|
||||
|
||||
runVM(t, vm)
|
||||
assert.Equal(t, 4, vm.estack.Len())
|
||||
assert.Equal(t, int64(2), vm.estack.Pop().BigInt().Int64()) // depth was 2
|
||||
for i := 1; i < 4; i++ {
|
||||
assert.Equal(t, int64(i), vm.estack.Pop().BigInt().Int64())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCALLI(t *testing.T) {
|
||||
prog := []byte{
|
||||
byte(opcode.PUSH3),
|
||||
byte(opcode.PUSH2),
|
||||
byte(opcode.PUSH1),
|
||||
byte(opcode.JMP), 0x5, 0, // to CALLI (+5 including JMP parameters)
|
||||
byte(opcode.SUB), // 2 - 1
|
||||
byte(opcode.RET),
|
||||
byte(opcode.CALLI), byte(1), byte(2), 0xfc, 0xff, // to SUB (-4) with [21 on stack
|
||||
byte(opcode.MUL), // 3 * 1
|
||||
byte(opcode.RET),
|
||||
}
|
||||
|
||||
vm := load(prog)
|
||||
|
||||
runVM(t, vm)
|
||||
assert.Equal(t, 1, vm.estack.Len())
|
||||
assert.Equal(t, int64(3), vm.estack.Pop().BigInt().Int64())
|
||||
}
|
||||
|
||||
func makeProgram(opcodes ...opcode.Opcode) []byte {
|
||||
prog := make([]byte, len(opcodes)+1) // RET
|
||||
for i := 0; i < len(opcodes); i++ {
|
||||
|
|
Loading…
Reference in a new issue