diff --git a/pkg/compiler/assign_test.go b/pkg/compiler/assign_test.go index ed5b5fe4a..f521d3a4a 100644 --- a/pkg/compiler/assign_test.go +++ b/pkg/compiler/assign_test.go @@ -4,7 +4,7 @@ import ( "math/big" "testing" - "github.com/nspcc-dev/neo-go/pkg/vm" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) var assignTestCases = []testCase{ @@ -144,9 +144,9 @@ func TestManyAssignments(t *testing.T) { src2 := `return a }` - for i := 0; i < vm.MaxArraySize; i++ { + for i := 0; i < stackitem.MaxArraySize; i++ { src1 += "a += 1\n" } - eval(t, src1+src2, big.NewInt(vm.MaxArraySize)) + eval(t, src1+src2, big.NewInt(stackitem.MaxArraySize)) } diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 49ba04353..8fa7afd98 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -97,7 +97,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) { err = errNoInstParam } else { var n = binary.LittleEndian.Uint32(c.prog[c.nextip : c.nextip+4]) - if n > MaxItemSize { + if n > stackitem.MaxSize { return instr, nil, errors.New("parameter is too big") } numtoread = int(n) diff --git a/pkg/vm/contract_checks.go b/pkg/vm/contract_checks.go index 9622d2781..1c8bfc4ea 100644 --- a/pkg/vm/contract_checks.go +++ b/pkg/vm/contract_checks.go @@ -6,6 +6,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/opcode" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) var ( @@ -21,14 +22,14 @@ func getNumOfThingsFromInstr(instr opcode.Opcode, param []byte) (int, bool) { nthings = int(instr-opcode.PUSH1) + 1 case instr <= opcode.PUSHINT256: n := bigint.FromBytes(param) - if !n.IsInt64() || n.Int64() > MaxArraySize { + if !n.IsInt64() || n.Int64() > stackitem.MaxArraySize { return 0, false } nthings = int(n.Int64()) default: return 0, false } - if nthings < 1 || nthings > MaxArraySize { + if nthings < 1 || nthings > stackitem.MaxArraySize { return 0, false } return nthings, true @@ -69,7 +70,7 @@ func ParseMultiSigContract(script []byte) (int, [][]byte, bool) { } pubs = append(pubs, param) nkeys++ - if nkeys > MaxArraySize { + if nkeys > stackitem.MaxArraySize { return nsigs, nil, false } } diff --git a/pkg/vm/interop.go b/pkg/vm/interop.go index 7020124bb..f0dd90f35 100644 --- a/pkg/vm/interop.go +++ b/pkg/vm/interop.go @@ -93,7 +93,7 @@ func RuntimeSerialize(vm *VM) error { data, err := stackitem.SerializeItem(item.value) if err != nil { return err - } else if len(data) > MaxItemSize { + } else if len(data) > stackitem.MaxSize { return errors.New("too big item") } diff --git a/pkg/vm/stackitem/item.go b/pkg/vm/stackitem/item.go index 07304b037..5d141c7f2 100644 --- a/pkg/vm/stackitem/item.go +++ b/pkg/vm/stackitem/item.go @@ -18,6 +18,12 @@ import ( // MaxBigIntegerSizeBits is the maximum size of BigInt item in bits. const MaxBigIntegerSizeBits = 32 * 8 +// MaxArraySize is the maximum array size allowed in the VM. +const MaxArraySize = 1024 + +// MaxSize is the maximum item size allowed in the VM. +const MaxSize = 1024 * 1024 + // Item represents the "real" value that is pushed on the stack. type Item interface { fmt.Stringer diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 9cb456583..5bd960b62 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -46,12 +46,6 @@ type ScriptHashGetter interface { } const ( - // MaxArraySize is the maximum array size allowed in the VM. - MaxArraySize = 1024 - - // MaxItemSize is the maximum item size allowed in the VM. - MaxItemSize = 1024 * 1024 - // MaxInvocationStackSize is the maximum size of an invocation stack. MaxInvocationStackSize = 1024 @@ -653,7 +647,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.NEWBUFFER: n := toInt(v.estack.Pop().BigInt()) - if n < 0 || n > MaxItemSize { + if n < 0 || n > stackitem.MaxSize { panic("invalid size") } v.estack.PushVal(stackitem.NewBuffer(make([]byte, n))) @@ -684,7 +678,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.CAT: b := v.estack.Pop().Bytes() a := v.estack.Pop().Bytes() - if l := len(a) + len(b); l > MaxItemSize { + if l := len(a) + len(b); l > stackitem.MaxSize { panic(fmt.Sprintf("too big item: %d", l)) } ab := append(a, b...) @@ -1001,7 +995,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.NEWARRAY, opcode.NEWARRAYT: item := v.estack.Pop() n := item.BigInt().Int64() - if n > MaxArraySize { + if n > stackitem.MaxArraySize { panic("too long array") } typ := stackitem.AnyT @@ -1017,7 +1011,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.NEWSTRUCT: item := v.estack.Pop() n := item.BigInt().Int64() - if n > MaxArraySize { + if n > stackitem.MaxArraySize { panic("too long struct") } items := makeArrayOfType(int(n), stackitem.AnyT) @@ -1031,12 +1025,12 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro switch t := arrElem.value.(type) { case *stackitem.Array: - if t.Len() >= MaxArraySize { + if t.Len() >= stackitem.MaxArraySize { panic("too long array") } t.Append(val) case *stackitem.Struct: - if t.Len() >= MaxArraySize { + if t.Len() >= stackitem.MaxArraySize { panic("too long struct") } t.Append(val) @@ -1048,7 +1042,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case opcode.PACK: n := int(v.estack.Pop().BigInt().Int64()) - if n < 0 || n > v.estack.Len() || n > MaxArraySize { + if n < 0 || n > v.estack.Len() || n > stackitem.MaxArraySize { panic("OPACK: invalid length") } @@ -1119,7 +1113,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro case *stackitem.Map: if i := t.Index(key.value); i >= 0 { v.refs.Remove(t.Value().([]stackitem.MapElement)[i].Value) - } else if t.Len() >= MaxArraySize { + } else if t.Len() >= stackitem.MaxArraySize { panic("too big map") } t.Add(key.value, item) diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 185848275..83fa9f04c 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -489,9 +489,9 @@ func TestPUSHDATA4(t *testing.T) { } func TestPushData4BigN(t *testing.T) { - prog := make([]byte, 1+4+MaxItemSize+1) + prog := make([]byte, 1+4+stackitem.MaxSize+1) prog[0] = byte(opcode.PUSHDATA4) - binary.LittleEndian.PutUint32(prog[1:], MaxItemSize+1) + binary.LittleEndian.PutUint32(prog[1:], stackitem.MaxSize+1) vm := load(prog) checkVMFailed(t, vm) @@ -1222,7 +1222,7 @@ func TestNEWBUFFER(t *testing.T) { prog := makeProgram(opcode.NEWBUFFER) t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte{0, 0, 0}), 3)) t.Run("Negative", getTestFuncForVM(prog, nil, -1)) - t.Run("TooBig", getTestFuncForVM(prog, nil, MaxItemSize+1)) + t.Run("TooBig", getTestFuncForVM(prog, nil, stackitem.MaxSize+1)) } func TestMEMCPY(t *testing.T) { @@ -1251,7 +1251,7 @@ func TestNEWSTRUCT0(t *testing.T) { func TestNEWARRAYArray(t *testing.T) { prog := makeProgram(opcode.NEWARRAY) t.Run("ByteArray", getTestFuncForVM(prog, stackitem.NewArray([]stackitem.Item{}), []byte{})) - t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1)) + t.Run("BadSize", getTestFuncForVM(prog, nil, stackitem.MaxArraySize+1)) t.Run("Integer", getTestFuncForVM(prog, []stackitem.Item{stackitem.Null{}}, 1)) } @@ -1302,7 +1302,7 @@ func TestNEWARRAYT(t *testing.T) { func TestNEWSTRUCT(t *testing.T) { prog := makeProgram(opcode.NEWSTRUCT) t.Run("ByteArray", getTestFuncForVM(prog, stackitem.NewStruct([]stackitem.Item{}), []byte{})) - t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1)) + t.Run("BadSize", getTestFuncForVM(prog, nil, stackitem.MaxArraySize+1)) t.Run("Integer", getTestFuncForVM(prog, stackitem.NewStruct([]stackitem.Item{stackitem.Null{}}), 1)) } @@ -1330,15 +1330,15 @@ func TestAPPENDBad(t *testing.T) { func TestAPPENDGoodSizeLimit(t *testing.T) { prog := makeProgram(opcode.NEWARRAY, opcode.DUP, opcode.PUSH0, opcode.APPEND) vm := load(prog) - vm.estack.PushVal(MaxArraySize - 1) + vm.estack.PushVal(stackitem.MaxArraySize - 1) runVM(t, vm) assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, MaxArraySize, len(vm.estack.Pop().Array())) + assert.Equal(t, stackitem.MaxArraySize, len(vm.estack.Pop().Array())) } func TestAPPENDBadSizeLimit(t *testing.T) { prog := makeProgram(opcode.NEWARRAY, opcode.DUP, opcode.PUSH0, opcode.APPEND) - runWithArgs(t, prog, nil, MaxArraySize) + runWithArgs(t, prog, nil, stackitem.MaxArraySize) } func TestPICKITEM(t *testing.T) { @@ -1399,11 +1399,11 @@ func TestSETITEMMap(t *testing.T) { func TestSETITEMBigMapBad(t *testing.T) { prog := makeProgram(opcode.SETITEM) m := stackitem.NewMap() - for i := 0; i < MaxArraySize; i++ { + for i := 0; i < stackitem.MaxArraySize; i++ { m.Add(stackitem.Make(i), stackitem.Make(i)) } - runWithArgs(t, prog, nil, m, MaxArraySize, 0) + runWithArgs(t, prog, nil, m, stackitem.MaxArraySize, 0) } // This test checks is SETITEM properly updates reference counter. @@ -1411,7 +1411,7 @@ func TestSETITEMBigMapBad(t *testing.T) { // 2. SETITEM each of them to a map. // 3. Replace each of them with a scalar value. func TestSETITEMMapStackLimit(t *testing.T) { - size := MaxArraySize - 3 + size := stackitem.MaxArraySize - 3 m := stackitem.NewMap() m.Add(stackitem.NewBigInteger(big.NewInt(1)), stackitem.NewArray(makeArrayOfType(size, stackitem.BooleanT))) m.Add(stackitem.NewBigInteger(big.NewInt(2)), stackitem.NewArray(makeArrayOfType(size, stackitem.BooleanT))) @@ -1431,7 +1431,7 @@ func TestSETITEMBigMapGood(t *testing.T) { vm := load(prog) m := stackitem.NewMap() - for i := 0; i < MaxArraySize; i++ { + for i := 0; i < stackitem.MaxArraySize; i++ { m.Add(stackitem.Make(i), stackitem.Make(i)) } vm.estack.Push(&Element{value: m}) @@ -1842,7 +1842,7 @@ func TestCAT(t *testing.T) { t.Run("NoArgument", getTestFuncForVM(prog, nil)) t.Run("OneArgument", getTestFuncForVM(prog, nil, []byte("abc"))) t.Run("BigItem", func(t *testing.T) { - arg := make([]byte, MaxItemSize/2+1) + arg := make([]byte, stackitem.MaxSize/2+1) runWithArgs(t, prog, nil, arg, arg) }) t.Run("Good", getTestFuncForVM(prog, stackitem.NewBuffer([]byte("abcdef")), []byte("abc"), []byte("def"))) @@ -1900,10 +1900,10 @@ func TestPACK(t *testing.T) { func TestPACKBigLen(t *testing.T) { prog := makeProgram(opcode.PACK) vm := load(prog) - for i := 0; i <= MaxArraySize; i++ { + for i := 0; i <= stackitem.MaxArraySize; i++ { vm.estack.PushVal(0) } - vm.estack.PushVal(MaxArraySize + 1) + vm.estack.PushVal(stackitem.MaxArraySize + 1) checkVMFailed(t, vm) }