state: store the length of NEP5TransferLog in the first byte

We lose `size` field after serialization/deserialization which can lead to
adding more than NEP5TransferBatchSize elements into the NEP5TransferLog.
This commit is contained in:
Roman Khimov 2020-09-21 21:46:40 +03:00
parent 6902003044
commit 806b89db76
3 changed files with 17 additions and 9 deletions

View file

@ -95,7 +95,7 @@ func (cd *Cached) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.N
if err := lg.Append(tr); err != nil { if err := lg.Append(tr); err != nil {
return false, err return false, err
} }
return lg.Size() >= nep5TransferBatchSize, cd.PutNEP5TransferLog(acc, index, lg) return lg.Size() >= state.NEP5TransferBatchSize, cd.PutNEP5TransferLog(acc, index, lg)
} }
// Persist flushes all the changes made into the (supposedly) persistent // Persist flushes all the changes made into the (supposedly) persistent

View file

@ -208,8 +208,6 @@ func (dao *Simple) putNEP5Balances(acc util.Uint160, bs *state.NEP5Balances, buf
// -- start transfer log. // -- start transfer log.
const nep5TransferBatchSize = 128
func getNEP5TransferLogKey(acc util.Uint160, index uint32) []byte { func getNEP5TransferLogKey(acc util.Uint160, index uint32) []byte {
key := make([]byte, 1+util.Uint160Size+4) key := make([]byte, 1+util.Uint160Size+4)
key[0] = byte(storage.STNEP5Transfers) key[0] = byte(storage.STNEP5Transfers)
@ -250,7 +248,7 @@ func (dao *Simple) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.
if err := lg.Append(tr); err != nil { if err := lg.Append(tr); err != nil {
return false, err return false, err
} }
return lg.Size() >= nep5TransferBatchSize, dao.PutNEP5TransferLog(acc, index, lg) return lg.Size() >= state.NEP5TransferBatchSize, dao.PutNEP5TransferLog(acc, index, lg)
} }
// -- end transfer log. // -- end transfer log.

View file

@ -8,6 +8,9 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
) )
// NEP5TransferBatchSize is the maximum number of entries for NEP5TransferLog.
const NEP5TransferBatchSize = 128
// NEP5Tracker contains info about a single account in a NEP5 contract. // NEP5Tracker contains info about a single account in a NEP5 contract.
type NEP5Tracker struct { type NEP5Tracker struct {
// Balance is the current balance of the account. // Balance is the current balance of the account.
@ -20,8 +23,6 @@ type NEP5Tracker struct {
// NEP5TransferLog is a log of NEP5 token transfers for the specific command. // NEP5TransferLog is a log of NEP5 token transfers for the specific command.
type NEP5TransferLog struct { type NEP5TransferLog struct {
Raw []byte Raw []byte
// size is the number of NEP5Transfers written into Raw
size int
} }
// NEP5Transfer represents a single NEP5 Transfer event. // NEP5Transfer represents a single NEP5 Transfer event.
@ -85,12 +86,18 @@ func (bs *NEP5Balances) EncodeBinary(w *io.BinWriter) {
// Append appends single transfer to a log. // Append appends single transfer to a log.
func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error { func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
// The first entry, set up counter.
if len(lg.Raw) == 0 {
w.WriteB(1)
}
tr.EncodeBinary(w.BinWriter) tr.EncodeBinary(w.BinWriter)
if w.Err != nil { if w.Err != nil {
return w.Err return w.Err
} }
if len(lg.Raw) != 0 {
lg.Raw[0]++
}
lg.Raw = append(lg.Raw, w.Bytes()...) lg.Raw = append(lg.Raw, w.Bytes()...)
lg.size++
return nil return nil
} }
@ -101,7 +108,7 @@ func (lg *NEP5TransferLog) ForEach(f func(*NEP5Transfer) error) error {
} }
tr := new(NEP5Transfer) tr := new(NEP5Transfer)
var bytesRead int var bytesRead int
for i := 0; i < len(lg.Raw); i += bytesRead { for i := 1; i < len(lg.Raw); i += bytesRead {
r := io.NewBinReaderFromBuf(lg.Raw[i:]) r := io.NewBinReaderFromBuf(lg.Raw[i:])
bytesRead = tr.DecodeBinaryReturnCount(r) bytesRead = tr.DecodeBinaryReturnCount(r)
if r.Err != nil { if r.Err != nil {
@ -115,7 +122,10 @@ func (lg *NEP5TransferLog) ForEach(f func(*NEP5Transfer) error) error {
// Size returns an amount of transfer written in log. // Size returns an amount of transfer written in log.
func (lg *NEP5TransferLog) Size() int { func (lg *NEP5TransferLog) Size() int {
return lg.size if len(lg.Raw) == 0 {
return 0
}
return int(lg.Raw[0])
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.