diff --git a/pkg/core/state/native_state.go b/pkg/core/state/native_state.go index 605dc1691..d4bd0208d 100644 --- a/pkg/core/state/native_state.go +++ b/pkg/core/state/native_state.go @@ -25,12 +25,25 @@ type NEOBalance struct { // NEP17BalanceFromBytes converts serialized NEP17Balance to structure. func NEP17BalanceFromBytes(b []byte) (*NEP17Balance, error) { - balance := new(NEP17Balance) - err := balanceFromBytes(b, balance) - if err != nil { - return nil, err + if len(b) < 4 { + if len(b) == 0 { + return new(NEP17Balance), nil + } + return nil, errors.New("invalid format") } - return balance, nil + if b[0] != byte(stackitem.StructT) { + return nil, errors.New("not a struct") + } + if b[1] != 1 { + return nil, errors.New("invalid item count") + } + if st := stackitem.Type(b[2]); st != stackitem.IntegerT { + return nil, fmt.Errorf("invalid balance: %s", st) + } + if int(b[3]) != len(b[4:]) { + return nil, errors.New("invalid balance format") + } + return &NEP17Balance{Balance: *bigint.FromBytes(b[4:])}, nil } // Bytes returns serialized NEP17Balance. diff --git a/pkg/core/state/native_state_test.go b/pkg/core/state/native_state_test.go index b590f93b1..6cb6f4a61 100644 --- a/pkg/core/state/native_state_test.go +++ b/pkg/core/state/native_state_test.go @@ -20,6 +20,31 @@ func TestNEP17Balance_Bytes(t *testing.T) { ret := b.Bytes(buf[:0]) require.Equal(t, ret, buf[:len(ret)]) }) + + actual, err := NEP17BalanceFromBytes(data) + require.NoError(t, err) + require.Equal(t, &b, actual) +} + +func TestNEP17BalanceFromBytesInvalid(t *testing.T) { + b, err := NEP17BalanceFromBytes(nil) // 0 is ok + require.NoError(t, err) + require.Equal(t, int64(0), b.Balance.Int64()) + + _, err = NEP17BalanceFromBytes([]byte{byte(stackitem.StructT)}) + require.Error(t, err) + + _, err = NEP17BalanceFromBytes([]byte{byte(stackitem.IntegerT), 4, 0, 1, 2, 3}) + require.Error(t, err) + + _, err = NEP17BalanceFromBytes([]byte{byte(stackitem.StructT), 0, byte(stackitem.IntegerT), 1, 1}) + require.Error(t, err) + + _, err = NEP17BalanceFromBytes([]byte{byte(stackitem.StructT), 1, byte(stackitem.ByteArrayT), 1, 1}) + require.Error(t, err) + + _, err = NEP17BalanceFromBytes([]byte{byte(stackitem.StructT), 1, byte(stackitem.IntegerT), 2, 1}) + require.Error(t, err) } func BenchmarkNEP17BalanceBytes(b *testing.B) { @@ -48,3 +73,23 @@ func BenchmarkNEP17BalanceBytes(b *testing.B) { } }) } + +func BenchmarkNEP17BalanceFromBytes(b *testing.B) { + var bl NEP17Balance + bl.Balance.SetInt64(0x12345678910) + + buf := bl.Bytes(nil) + + b.Run("stackitem", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _ = stackitem.DeserializeConvertible(buf, new(NEP17Balance)) + } + }) + b.Run("from bytes", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = NEP17BalanceFromBytes(buf) + } + }) +}