vm/encoding: move bigint from vm to encoding package

This commit is contained in:
Anna Shaleva 2020-06-04 21:11:27 +03:00
parent 783f5ecb01
commit 7ca2807875
16 changed files with 55 additions and 47 deletions

View file

@ -18,6 +18,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -606,7 +607,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
if !ok {
continue
}
amount = emit.BytesToInt(bs)
amount = bigint.FromBytes(bs)
}
bc.processNEP5Transfer(cache, tx, block, note.ScriptHash, from, to, amount.Int64())
}

View file

@ -7,10 +7,10 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
@ -107,11 +107,11 @@ func (c *nep5TokenNative) getTotalSupply(ic *interop.Context) *big.Int {
if si == nil {
return big.NewInt(0)
}
return emit.BytesToInt(si.Value)
return bigint.FromBytes(si.Value)
}
func (c *nep5TokenNative) saveTotalSupply(ic *interop.Context, supply *big.Int) error {
si := &state.StorageItem{Value: emit.IntToBytes(supply)}
si := &state.StorageItem{Value: bigint.ToBytes(supply)}
return ic.DAO.PutStorageItem(c.Hash, totalSupplyKey, si)
}

View file

@ -3,8 +3,8 @@ package native
import (
"math/big"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
)
// MaxValidatorsVoted limits the number of validators that one can vote for.
@ -42,7 +42,7 @@ func (vc *ValidatorsCount) Bytes() []byte {
// EncodeBinary implements io.Serializable interface.
func (vc *ValidatorsCount) EncodeBinary(w *io.BinWriter) {
for i := range vc {
w.WriteVarBytes(emit.IntToBytes(&vc[i]))
w.WriteVarBytes(bigint.ToBytes(&vc[i]))
}
}
@ -53,7 +53,7 @@ func (vc *ValidatorsCount) DecodeBinary(r *io.BinReader) {
if r.Err != nil {
return
}
vc[i] = *emit.BytesToInt(buf)
vc[i] = *bigint.FromBytes(buf)
}
}

View file

@ -4,8 +4,8 @@ import (
"math/big"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
)
// NEP5BalanceState represents balance state of a NEP5-token.
@ -46,7 +46,7 @@ func (s *NEP5BalanceState) Bytes() []byte {
// EncodeBinary implements io.Serializable interface.
func (s *NEP5BalanceState) EncodeBinary(w *io.BinWriter) {
w.WriteVarBytes(emit.IntToBytes(&s.Balance))
w.WriteVarBytes(bigint.ToBytes(&s.Balance))
}
// DecodeBinary implements io.Serializable interface.
@ -55,7 +55,7 @@ func (s *NEP5BalanceState) DecodeBinary(r *io.BinReader) {
if r.Err != nil {
return
}
s.Balance = *emit.BytesToInt(buf)
s.Balance = *bigint.FromBytes(buf)
}
// NEOBalanceStateFromBytes converts serialized NEOBalanceState to structure.

View file

@ -1,4 +1,4 @@
package emit
package bigint
import (
"encoding/binary"
@ -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
// FromBytes converts data in little-endian format to
// an integer.
func BytesToInt(data []byte) *big.Int {
func FromBytes(data []byte) *big.Int {
n := new(big.Int)
size := len(data)
if size == 0 {
@ -79,15 +79,17 @@ func getEffectiveSize(buf []byte, isNeg bool) int {
return size
}
// IntToBytes converts integer to a slice in little-endian format.
// ToBytes converts integer to a slice in little-endian format.
// Note: NEO3 serialization differs from default C# BigInteger.ToByteArray()
// when n == 0. For zero is equal to empty slice in NEO3.
// https://github.com/neo-project/neo-vm/blob/master/src/neo-vm/Types/Integer.cs#L16
func IntToBytes(n *big.Int) []byte {
return intToBytes(n, []byte{})
func ToBytes(n *big.Int) []byte {
return ToPreallocatedBytes(n, []byte{})
}
func intToBytes(n *big.Int, data []byte) []byte {
// ToPreallocatedBytes converts integer to a slice in little-endian format using given
// byte array for conversion result.
func ToPreallocatedBytes(n *big.Int, data []byte) []byte {
sign := n.Sign()
if sign == 0 {
return data

View file

@ -1,4 +1,4 @@
package emit
package bigint
import (
"math"
@ -106,19 +106,19 @@ var testCases = []struct {
func TestIntToBytes(t *testing.T) {
for _, tc := range testCases {
buf := IntToBytes(big.NewInt(tc.number))
buf := ToBytes(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 := FromBytes(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, FromBytes([]byte{}).Int64())
})
}
@ -131,7 +131,7 @@ func TestEquivalentRepresentations(t *testing.T) {
buf = append(buf, 0xFF, 0xFF, 0xFF)
}
num := BytesToInt(buf)
num := FromBytes(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 := FromBytes(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, ToBytes(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 := FromBytes(util.ArrayReverse(tc.buf))
assert.Equal(t, num, result, "error while converting %s from bytes", tc.numStr)
}
}

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -180,7 +181,7 @@ func topIntFromStack(st []smartcontract.Parameter) (int64, error) {
if !ok {
return 0, errors.New("invalid ByteArray item")
}
decimals = emit.BytesToInt(data).Int64()
decimals = bigint.FromBytes(data).Int64()
default:
return 0, fmt.Errorf("invalid stack item type: %s", typ)
}

View file

@ -21,6 +21,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/network"
"github.com/nspcc-dev/neo-go/pkg/rpc"
@ -29,7 +30,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/pkg/errors"
"go.uber.org/zap"
)
@ -625,7 +625,7 @@ func (s *Server) getDecimals(h util.Uint160, cache map[util.Uint160]int64) (int6
case smartcontract.IntegerType:
d = item.Value.(int64)
case smartcontract.ByteArrayType:
d = emit.BytesToInt(item.Value.([]byte)).Int64()
d = bigint.FromBytes(item.Value.([]byte)).Int64()
default:
return 0, response.NewInternalServerError("invalid result", errors.New("not an integer"))
}

View file

@ -3,6 +3,7 @@ package vm
import (
"encoding/binary"
"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"
)
@ -19,7 +20,7 @@ func getNumOfThingsFromInstr(instr opcode.Opcode, param []byte) (int, bool) {
case opcode.PUSH1 <= instr && instr <= opcode.PUSH16:
nthings = int(instr-opcode.PUSH1) + 1
case instr <= opcode.PUSHINT256:
n := emit.BytesToInt(param)
n := bigint.FromBytes(param)
if !n.IsInt64() || n.Int64() > MaxArraySize {
return 0, false
}

View file

@ -8,6 +8,7 @@ import (
"math/big"
"math/bits"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
@ -54,7 +55,7 @@ func Int(w *io.BinWriter, i int64) {
val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i))
Opcode(w, val)
default:
buf := intToBytes(big.NewInt(i), make([]byte, 0, 32))
buf := bigint.ToPreallocatedBytes(big.NewInt(i), make([]byte, 0, 32))
// l != 0 becase of switch
padSize := byte(8 - bits.LeadingZeros8(byte(len(buf)-1)))
Opcode(w, opcode.PUSHINT8+opcode.Opcode(padSize))

View file

@ -5,6 +5,7 @@ import (
"errors"
"testing"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
@ -49,7 +50,7 @@ func TestEmitInt(t *testing.T) {
result := buf.Bytes()
assert.Equal(t, 3, len(result))
assert.EqualValues(t, opcode.PUSHINT16, result[0])
assert.EqualValues(t, 300, BytesToInt(result[1:]).Int64())
assert.EqualValues(t, 300, bigint.FromBytes(result[1:]).Int64())
})
t.Run("3-byte int", func(t *testing.T) {
@ -58,7 +59,7 @@ func TestEmitInt(t *testing.T) {
result := buf.Bytes()
assert.Equal(t, 5, len(result))
assert.EqualValues(t, opcode.PUSHINT32, result[0])
assert.EqualValues(t, 1<<20, BytesToInt(result[1:]).Int64())
assert.EqualValues(t, 1<<20, bigint.FromBytes(result[1:]).Int64())
})
t.Run("4-byte int", func(t *testing.T) {
@ -67,7 +68,7 @@ func TestEmitInt(t *testing.T) {
result := buf.Bytes()
assert.Equal(t, 5, len(result))
assert.EqualValues(t, opcode.PUSHINT32, result[0])
assert.EqualValues(t, 1<<28, BytesToInt(result[1:]).Int64())
assert.EqualValues(t, 1<<28, bigint.FromBytes(result[1:]).Int64())
})
t.Run("negative 3-byte int with padding", func(t *testing.T) {
@ -77,7 +78,7 @@ func TestEmitInt(t *testing.T) {
result := buf.Bytes()
assert.Equal(t, 5, len(result))
assert.EqualValues(t, opcode.PUSHINT32, result[0])
assert.EqualValues(t, num, BytesToInt(result[1:]).Int64())
assert.EqualValues(t, num, bigint.FromBytes(result[1:]).Int64())
})
}

View file

@ -16,7 +16,7 @@ import (
"strings"
"testing"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
@ -183,7 +183,7 @@ func compareItems(t *testing.T, a, b stackitem.Item) {
case *stackitem.BigInteger:
require.Equal(t, val, ac.Value().(*big.Int).Int64())
case *stackitem.ByteArray:
require.Equal(t, val, emit.BytesToInt(ac.Value().([]byte)).Int64())
require.Equal(t, val, bigint.FromBytes(ac.Value().([]byte)).Int64())
case *stackitem.Bool:
if ac.Value().(bool) {
require.Equal(t, val, int64(1))

View file

@ -11,8 +11,8 @@ import (
"reflect"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
)
// MaxBigIntegerSizeBits is the maximum size of BigInt item in bits.
@ -324,7 +324,7 @@ func NewBigInteger(value *big.Int) *BigInteger {
// Bytes converts i to a slice of bytes.
func (i *BigInteger) Bytes() []byte {
return emit.IntToBytes(i.value)
return bigint.ToBytes(i.value)
}
// Bool implements Item interface.
@ -514,7 +514,7 @@ func (i *ByteArray) TryInteger() (*big.Int, error) {
if len(i.value) > MaxBigIntegerSizeBits/8 {
return nil, errors.New("integer is too big")
}
return emit.BytesToInt(i.value), nil
return bigint.FromBytes(i.value), nil
}
// Equals implements Item interface.
@ -998,7 +998,7 @@ func (i *Buffer) Convert(typ Type) (Item, error) {
if len(i.value) > MaxBigIntegerSizeBits/8 {
return nil, errInvalidConversion
}
return NewBigInteger(emit.BytesToInt(i.value)), nil
return NewBigInteger(bigint.FromBytes(i.value)), nil
default:
return nil, errInvalidConversion
}

View file

@ -4,8 +4,8 @@ import (
"errors"
"math/big"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
)
// SerializeItem encodes given Item into the byte slice.
@ -43,7 +43,7 @@ func serializeItemTo(item Item, w *io.BinWriter, seen map[Item]bool) {
w.WriteBool(t.Value().(bool))
case *BigInteger:
w.WriteBytes([]byte{byte(IntegerT)})
w.WriteVarBytes(emit.IntToBytes(t.Value().(*big.Int)))
w.WriteVarBytes(bigint.ToBytes(t.Value().(*big.Int)))
case *Interop:
w.Err = errors.New("interop item can't be serialized")
case *Array, *Struct:
@ -102,7 +102,7 @@ func DecodeBinaryStackItem(r *io.BinReader) Item {
return NewBool(b)
case IntegerT:
data := r.ReadVarBytes()
num := emit.BytesToInt(data)
num := bigint.FromBytes(data)
return NewBigInteger(num)
case ArrayT, StructT:
size := int(r.ReadVarUint())

View file

@ -12,8 +12,8 @@ import (
"unicode/utf8"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/util"
"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"
"github.com/pkg/errors"
@ -511,7 +511,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
}
if op <= opcode.PUSHINT256 {
v.estack.PushVal(emit.BytesToInt(parameter))
v.estack.PushVal(bigint.FromBytes(parameter))
return
}

View file

@ -9,6 +9,7 @@ import (
"math/rand"
"testing"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/internal/random"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -181,7 +182,7 @@ func TestPUSHINT(t *testing.T) {
t.Run(op.String(), func(t *testing.T) {
buf := random.Bytes((8 << i) / 8)
prog := append([]byte{byte(op)}, buf...)
runWithArgs(t, prog, emit.BytesToInt(buf))
runWithArgs(t, prog, bigint.FromBytes(buf))
})
}
}
@ -295,7 +296,7 @@ func TestCONVERT(t *testing.T) {
t.Run("primitive -> Integer/ByteArray", func(t *testing.T) {
n := big.NewInt(42)
b := emit.IntToBytes(n)
b := bigint.ToBytes(n)
itemInt := stackitem.NewBigInteger(n)
itemBytes := stackitem.NewByteArray(b)