From f15ceff59274dd847955dd481eea49ab8e4554cc Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 28 Jan 2020 11:58:06 +0300 Subject: [PATCH 1/2] vm: make IntToBytes, BytesToInt public VM serialization format should be able to be reused. --- pkg/vm/bigint.go | 8 ++++---- pkg/vm/bigint_test.go | 14 +++++++------- pkg/vm/json_test.go | 2 +- pkg/vm/serialization.go | 4 ++-- pkg/vm/stack.go | 2 +- pkg/vm/stack_item.go | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pkg/vm/bigint.go b/pkg/vm/bigint.go index a99fbf383..f0698c87e 100644 --- a/pkg/vm/bigint.go +++ b/pkg/vm/bigint.go @@ -9,9 +9,9 @@ import ( // wordSizeBytes is a size of a big.Word (uint) in bytes.` const wordSizeBytes = bits.UintSize / 8 -// bytesToInt converts data in little-endian format to +// BytesToInt converts data in little-endian format to // an integer. -func bytesToInt(data []byte) *big.Int { +func BytesToInt(data []byte) *big.Int { n := new(big.Int) size := len(data) if size == 0 { @@ -79,8 +79,8 @@ func getEffectiveSize(buf []byte, isNeg bool) int { return size } -// intToBytes converts integer to a slice in little-endian format. -func intToBytes(n *big.Int) []byte { +// IntToBytes converts integer to a slice in little-endian format. +func IntToBytes(n *big.Int) []byte { sign := n.Sign() if sign == 0 { return []byte{0} diff --git a/pkg/vm/bigint_test.go b/pkg/vm/bigint_test.go index 4554875b5..756accf62 100644 --- a/pkg/vm/bigint_test.go +++ b/pkg/vm/bigint_test.go @@ -106,19 +106,19 @@ var testCases = []struct { func TestIntToBytes(t *testing.T) { for _, tc := range testCases { - buf := intToBytes(big.NewInt(tc.number)) + buf := IntToBytes(big.NewInt(tc.number)) assert.Equal(t, tc.buf, buf, "error while converting %d", tc.number) } } func TestBytesToInt(t *testing.T) { for _, tc := range testCases { - num := bytesToInt(tc.buf) + num := BytesToInt(tc.buf) assert.Equal(t, tc.number, num.Int64(), "error while converting %d", tc.number) } t.Run("empty array", func(t *testing.T) { - require.EqualValues(t, 0, bytesToInt([]byte{}).Int64()) + require.EqualValues(t, 0, BytesToInt([]byte{}).Int64()) }) } @@ -131,7 +131,7 @@ func TestEquivalentRepresentations(t *testing.T) { buf = append(buf, 0xFF, 0xFF, 0xFF) } - num := bytesToInt(buf) + num := BytesToInt(buf) assert.Equal(t, tc.number, num.Int64(), "error while converting %d", tc.number) } } @@ -170,16 +170,16 @@ func TestVeryBigInts(t *testing.T) { num, ok := new(big.Int).SetString(tc.numStr, 10) assert.True(t, ok) - result := bytesToInt(tc.buf) + result := BytesToInt(tc.buf) assert.Equal(t, num, result, "error while converting %s from bytes", tc.numStr) - assert.Equal(t, tc.buf, intToBytes(result), "error while converting %s to bytes", tc.numStr) + assert.Equal(t, tc.buf, IntToBytes(result), "error while converting %s to bytes", tc.numStr) } for _, tc := range stdlibCases { num, ok := new(big.Int).SetString(tc.numStr, 10) assert.True(t, ok) - result := bytesToInt(util.ArrayReverse(tc.buf)) + result := BytesToInt(util.ArrayReverse(tc.buf)) assert.Equal(t, num, result, "error while converting %s from bytes", tc.numStr) } } diff --git a/pkg/vm/json_test.go b/pkg/vm/json_test.go index 1cc33681c..d459f3d14 100644 --- a/pkg/vm/json_test.go +++ b/pkg/vm/json_test.go @@ -196,7 +196,7 @@ func compareItems(t *testing.T, a, b StackItem) { case *BigIntegerItem: require.Equal(t, val, ac.value.Int64()) case *ByteArrayItem: - require.Equal(t, val, bytesToInt(ac.value).Int64()) + require.Equal(t, val, BytesToInt(ac.value).Int64()) case *BoolItem: if ac.value { require.Equal(t, val, int64(1)) diff --git a/pkg/vm/serialization.go b/pkg/vm/serialization.go index c3adf299b..245102f20 100644 --- a/pkg/vm/serialization.go +++ b/pkg/vm/serialization.go @@ -48,7 +48,7 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) { w.WriteBool(t.value) case *BigIntegerItem: w.WriteBytes([]byte{byte(integerT)}) - w.WriteVarBytes(intToBytes(t.value)) + w.WriteVarBytes(IntToBytes(t.value)) case *InteropItem: w.Err = errors.New("not supported") case *ArrayItem, *StructItem: @@ -106,7 +106,7 @@ func DecodeBinaryStackItem(r *io.BinReader) StackItem { return NewBoolItem(b) case integerT: data := r.ReadVarBytes() - num := bytesToInt(data) + num := BytesToInt(data) return &BigIntegerItem{ value: num, } diff --git a/pkg/vm/stack.go b/pkg/vm/stack.go index 9cdf551ac..2b8596414 100644 --- a/pkg/vm/stack.go +++ b/pkg/vm/stack.go @@ -81,7 +81,7 @@ func (e *Element) BigInt() *big.Int { return big.NewInt(0) default: b := t.Value().([]uint8) - return bytesToInt(b) + return BytesToInt(b) } } diff --git a/pkg/vm/stack_item.go b/pkg/vm/stack_item.go index d5ea56cc6..21db4a785 100644 --- a/pkg/vm/stack_item.go +++ b/pkg/vm/stack_item.go @@ -142,7 +142,7 @@ func NewBigIntegerItem(value int) *BigIntegerItem { // Bytes converts i to a slice of bytes. func (i *BigIntegerItem) Bytes() []byte { - return intToBytes(i.value) + return IntToBytes(i.value) } // Value implements StackItem interface. From d190b3a2e0e01a767a69188c63ab5d706cd8ca6d Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 28 Jan 2020 11:59:57 +0300 Subject: [PATCH 2/2] compiler: emit integers correctly A while ago VM serialization format for Integer items was changed but compiler continued to emit Integers in old format. This commit changes compiler behaviour to be compatible with VM. --- pkg/compiler/emit.go | 4 ++-- pkg/compiler/limit_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 pkg/compiler/limit_test.go diff --git a/pkg/compiler/emit.go b/pkg/compiler/emit.go index 56cffb237..c27a06701 100644 --- a/pkg/compiler/emit.go +++ b/pkg/compiler/emit.go @@ -7,7 +7,7 @@ import ( "math/big" "github.com/CityOfZion/neo-go/pkg/io" - "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/vm" "github.com/CityOfZion/neo-go/pkg/vm/opcode" ) @@ -47,7 +47,7 @@ func emitInt(w *io.BinWriter, i int64) { } bInt := big.NewInt(i) - val := util.ArrayReverse(bInt.Bytes()) + val := vm.IntToBytes(bInt) emitBytes(w, val) } diff --git a/pkg/compiler/limit_test.go b/pkg/compiler/limit_test.go new file mode 100644 index 000000000..b80282dd5 --- /dev/null +++ b/pkg/compiler/limit_test.go @@ -0,0 +1,26 @@ +package compiler_test + +import ( + "bytes" + "fmt" + "math/big" + "testing" +) + +// Test for #605, #623. +// Codegen should emit integers in proper format. +func TestManyVariables(t *testing.T) { + // any number with MSB=1 is suitable + // 155 was in the contract where this bug was first found. + const count = 155 + + buf := bytes.NewBufferString("package main\n") + for i := 0; i < count; i++ { + buf.WriteString(fmt.Sprintf("var a%d = %d\n", i, i)) + } + buf.WriteString("func Main() int {\nreturn 7\n}\n") + + src := buf.String() + + eval(t, src, big.NewInt(7)) +}