mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
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 {
|
func makeProgram(opcodes ...opcode.Opcode) []byte {
|
||||||
prog := make([]byte, len(opcodes)+1) // RET
|
prog := make([]byte, len(opcodes)+1) // RET
|
||||||
for i := 0; i < len(opcodes); i++ {
|
for i := 0; i < len(opcodes); i++ {
|
||||||
|
|
Loading…
Reference in a new issue