state: make NEP5Transfer log more generic

This commit is contained in:
Evgenii Stratonikov 2020-08-04 16:55:45 +03:00
parent 49f9c4ad7e
commit e4fcd90b6d
8 changed files with 35 additions and 34 deletions

View file

@ -972,12 +972,12 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, tx *transaction.Tra
} }
// GetNEP5TransferLog returns NEP5 transfer log for the acc. // GetNEP5TransferLog returns NEP5 transfer log for the acc.
func (bc *Blockchain) GetNEP5TransferLog(acc util.Uint160) *state.NEP5TransferLog { func (bc *Blockchain) GetNEP5TransferLog(acc util.Uint160) *state.TransferLog {
balances, err := bc.dao.GetNEP5Balances(acc) balances, err := bc.dao.GetNEP5Balances(acc)
if err != nil { if err != nil {
return nil return nil
} }
result := new(state.NEP5TransferLog) result := new(state.TransferLog)
for i := uint32(0); i <= balances.NextTransferBatch; i++ { for i := uint32(0); i <= balances.NextTransferBatch; i++ {
lg, err := bc.dao.GetNEP5TransferLog(acc, i) lg, err := bc.dao.GetNEP5TransferLog(acc, i)
if err != nil { if err != nil {

View file

@ -36,7 +36,7 @@ type Blockchainer interface {
GetAccountState(util.Uint160) *state.Account GetAccountState(util.Uint160) *state.Account
GetAppExecResult(util.Uint256) (*state.AppExecResult, error) GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error) GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error)
GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog GetNEP5TransferLog(util.Uint160) *state.TransferLog
GetNEP5Balances(util.Uint160) *state.NEP5Balances GetNEP5Balances(util.Uint160) *state.NEP5Balances
GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error) GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error)
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error) GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)

View file

@ -20,7 +20,7 @@ type Cached struct {
contracts map[util.Uint160]*state.Contract contracts map[util.Uint160]*state.Contract
unspents map[util.Uint256]*state.UnspentCoin unspents map[util.Uint256]*state.UnspentCoin
balances map[util.Uint160]*state.NEP5Balances balances map[util.Uint160]*state.NEP5Balances
nep5transfers map[util.Uint160]map[uint32]*state.NEP5TransferLog nep5transfers map[util.Uint160]map[uint32]*state.TransferLog
storage *itemCache storage *itemCache
dropNEP5Cache bool dropNEP5Cache bool
@ -32,7 +32,7 @@ func NewCached(d DAO) *Cached {
ctrs := make(map[util.Uint160]*state.Contract) ctrs := make(map[util.Uint160]*state.Contract)
unspents := make(map[util.Uint256]*state.UnspentCoin) unspents := make(map[util.Uint256]*state.UnspentCoin)
balances := make(map[util.Uint160]*state.NEP5Balances) balances := make(map[util.Uint160]*state.NEP5Balances)
nep5transfers := make(map[util.Uint160]map[uint32]*state.NEP5TransferLog) nep5transfers := make(map[util.Uint160]map[uint32]*state.TransferLog)
st := newItemCache() st := newItemCache()
dao := d.GetWrapped() dao := d.GetWrapped()
if cd, ok := dao.(*Cached); ok { if cd, ok := dao.(*Cached); ok {
@ -120,8 +120,8 @@ func (cd *Cached) PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) erro
return nil return nil
} }
// GetNEP5TransferLog retrieves NEP5TransferLog for the acc. // GetNEP5TransferLog retrieves TransferLog for the acc.
func (cd *Cached) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) { func (cd *Cached) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.TransferLog, error) {
ts := cd.nep5transfers[acc] ts := cd.nep5transfers[acc]
if ts != nil && ts[index] != nil { if ts != nil && ts[index] != nil {
return ts[index], nil return ts[index], nil
@ -129,11 +129,11 @@ func (cd *Cached) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP
return cd.DAO.GetNEP5TransferLog(acc, index) return cd.DAO.GetNEP5TransferLog(acc, index)
} }
// PutNEP5TransferLog saves NEP5TransferLog for the acc. // PutNEP5TransferLog saves TransferLog for the acc.
func (cd *Cached) PutNEP5TransferLog(acc util.Uint160, index uint32, bs *state.NEP5TransferLog) error { func (cd *Cached) PutNEP5TransferLog(acc util.Uint160, index uint32, bs *state.TransferLog) error {
ts := cd.nep5transfers[acc] ts := cd.nep5transfers[acc]
if ts == nil { if ts == nil {
ts = make(map[uint32]*state.NEP5TransferLog, 2) ts = make(map[uint32]*state.TransferLog, 2)
cd.nep5transfers[acc] = ts cd.nep5transfers[acc] = ts
} }
ts[index] = bs ts[index] = bs

View file

@ -36,7 +36,7 @@ type DAO interface {
GetHeaderHashes() ([]util.Uint256, error) GetHeaderHashes() ([]util.Uint256, error)
GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error) GetNEP5Balances(acc util.Uint160) (*state.NEP5Balances, error)
GetNEP5Metadata(h util.Uint160) (*state.NEP5Metadata, error) GetNEP5Metadata(h util.Uint160) (*state.NEP5Metadata, error)
GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.TransferLog, error)
GetStateRoot(height uint32) (*state.MPTRootState, error) GetStateRoot(height uint32) (*state.MPTRootState, error)
PutStateRoot(root *state.MPTRootState) error PutStateRoot(root *state.MPTRootState) error
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
@ -60,7 +60,7 @@ type DAO interface {
PutCurrentHeader(hashAndIndex []byte) error PutCurrentHeader(hashAndIndex []byte) error
PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error PutNEP5Balances(acc util.Uint160, bs *state.NEP5Balances) error
PutNEP5Metadata(h util.Uint160, meta *state.NEP5Metadata) error PutNEP5Metadata(h util.Uint160, meta *state.NEP5Metadata) error
PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.TransferLog) error
PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error PutStorageItem(scripthash util.Uint160, key []byte, si *state.StorageItem) error
PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) error PutUnspentCoinState(hash util.Uint256, ucs *state.UnspentCoin) error
PutValidatorState(vs *state.Validator) error PutValidatorState(vs *state.Validator) error
@ -262,7 +262,7 @@ func (dao *Simple) putNEP5Balances(acc util.Uint160, bs *state.NEP5Balances, buf
// -- start transfer log. // -- start transfer log.
const nep5TransferBatchSize = 128 const nep5TransferBatchSize = 128 * state.NEP5TransferSize
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)
@ -273,20 +273,20 @@ func getNEP5TransferLogKey(acc util.Uint160, index uint32) []byte {
} }
// GetNEP5TransferLog retrieves transfer log from the cache. // GetNEP5TransferLog retrieves transfer log from the cache.
func (dao *Simple) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.NEP5TransferLog, error) { func (dao *Simple) GetNEP5TransferLog(acc util.Uint160, index uint32) (*state.TransferLog, error) {
key := getNEP5TransferLogKey(acc, index) key := getNEP5TransferLogKey(acc, index)
value, err := dao.Store.Get(key) value, err := dao.Store.Get(key)
if err != nil { if err != nil {
if err == storage.ErrKeyNotFound { if err == storage.ErrKeyNotFound {
return new(state.NEP5TransferLog), nil return new(state.TransferLog), nil
} }
return nil, err return nil, err
} }
return &state.NEP5TransferLog{Raw: value}, nil return &state.TransferLog{Raw: value}, nil
} }
// PutNEP5TransferLog saves given transfer log in the cache. // PutNEP5TransferLog saves given transfer log in the cache.
func (dao *Simple) PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.NEP5TransferLog) error { func (dao *Simple) PutNEP5TransferLog(acc util.Uint160, index uint32, lg *state.TransferLog) error {
key := getNEP5TransferLogKey(acc, index) key := getNEP5TransferLogKey(acc, index)
return dao.Store.Put(key, lg.Raw) return dao.Store.Put(key, lg.Raw)
} }
@ -299,7 +299,7 @@ func (dao *Simple) AppendNEP5Transfer(acc util.Uint160, index uint32, tr *state.
if err != storage.ErrKeyNotFound { if err != storage.ErrKeyNotFound {
return false, err return false, err
} }
lg = new(state.NEP5TransferLog) lg = new(state.TransferLog)
} }
if err := lg.Append(tr); err != nil { if err := lg.Append(tr); err != nil {
return false, err return false, err

View file

@ -14,8 +14,8 @@ type NEP5Tracker struct {
LastUpdatedBlock uint32 LastUpdatedBlock uint32
} }
// NEP5TransferLog is a log of NEP5 token transfers for the specific command. // TransferLog is a log of NEP5 token transfers for the specific command.
type NEP5TransferLog struct { type TransferLog struct {
Raw []byte Raw []byte
} }
@ -99,7 +99,7 @@ func (bs *NEP5Metadata) 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 *TransferLog) Append(tr io.Serializable) error {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
tr.EncodeBinary(w.BinWriter) tr.EncodeBinary(w.BinWriter)
if w.Err != nil { if w.Err != nil {
@ -110,26 +110,25 @@ func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
} }
// ForEach iterates over transfer log returning on first error. // ForEach iterates over transfer log returning on first error.
func (lg *NEP5TransferLog) ForEach(f func(*NEP5Transfer) error) error { func (lg *TransferLog) ForEach(size int, tr io.Serializable, f func() error) error {
if lg == nil { if lg == nil {
return nil return nil
} }
tr := new(NEP5Transfer) for i := 0; i < len(lg.Raw); i += size {
for i := 0; i < len(lg.Raw); i += NEP5TransferSize { r := io.NewBinReaderFromBuf(lg.Raw[i : i+size])
r := io.NewBinReaderFromBuf(lg.Raw[i : i+NEP5TransferSize])
tr.DecodeBinary(r) tr.DecodeBinary(r)
if r.Err != nil { if r.Err != nil {
return r.Err return r.Err
} else if err := f(tr); err != nil { } else if err := f(); err != nil {
return nil return nil
} }
} }
return nil return nil
} }
// Size returns an amount of transfer written in log. // Size returns an amount of transfer written in log provided size of a single transfer.
func (lg *NEP5TransferLog) Size() int { func (lg *TransferLog) Size() int {
return len(lg.Raw) / NEP5TransferSize return len(lg.Raw)
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.

View file

@ -21,15 +21,16 @@ func TestNEP5TransferLog_Append(t *testing.T) {
randomTransfer(r), randomTransfer(r),
} }
lg := new(NEP5TransferLog) lg := new(TransferLog)
for _, tr := range expected { for _, tr := range expected {
require.NoError(t, lg.Append(tr)) require.NoError(t, lg.Append(tr))
} }
require.Equal(t, len(expected), lg.Size()) require.Equal(t, len(expected), lg.Size()/NEP5TransferSize)
i := 0 i := 0
err := lg.ForEach(func(tr *NEP5Transfer) error { tr := new(NEP5Transfer)
err := lg.ForEach(NEP5TransferSize, tr, func() error {
require.Equal(t, expected[i], tr) require.Equal(t, expected[i], tr)
i++ i++
return nil return nil

View file

@ -96,7 +96,7 @@ func (chain testChain) GetAccountState(util.Uint160) *state.Account {
func (chain testChain) GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error) { func (chain testChain) GetNEP5Metadata(util.Uint160) (*state.NEP5Metadata, error) {
panic("TODO") panic("TODO")
} }
func (chain testChain) GetNEP5TransferLog(util.Uint160) *state.NEP5TransferLog { func (chain testChain) GetNEP5TransferLog(util.Uint160) *state.TransferLog {
panic("TODO") panic("TODO")
} }
func (chain testChain) GetNEP5Balances(util.Uint160) *state.NEP5Balances { func (chain testChain) GetNEP5Balances(util.Uint160) *state.NEP5Balances {

View file

@ -598,7 +598,8 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
Sent: []result.NEP5Transfer{}, Sent: []result.NEP5Transfer{},
} }
lg := s.chain.GetNEP5TransferLog(u) lg := s.chain.GetNEP5TransferLog(u)
err = lg.ForEach(func(tr *state.NEP5Transfer) error { tr := new(state.NEP5Transfer)
err = lg.ForEach(state.NEP5TransferSize, tr, func() error {
transfer := result.NEP5Transfer{ transfer := result.NEP5Transfer{
Timestamp: tr.Timestamp, Timestamp: tr.Timestamp,
Asset: tr.Asset, Asset: tr.Asset,