2020-03-05 07:45:50 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
2021-08-05 09:59:08 +00:00
|
|
|
"bytes"
|
2020-07-09 09:57:24 +00:00
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
2020-03-05 07:45:50 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-03-05 14:11:58 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-03-05 07:45:50 +00:00
|
|
|
)
|
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
// NEP17TransferBatchSize is the maximum number of entries for NEP17TransferLog.
|
|
|
|
const NEP17TransferBatchSize = 128
|
2020-09-21 18:46:40 +00:00
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
// NEP17TransferLog is a log of NEP17 token transfers for the specific command.
|
|
|
|
type NEP17TransferLog struct {
|
2020-03-05 14:11:58 +00:00
|
|
|
Raw []byte
|
|
|
|
}
|
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
// NEP17Transfer represents a single NEP17 Transfer event.
|
|
|
|
type NEP17Transfer struct {
|
|
|
|
// Asset is a NEP17 contract ID.
|
2020-07-28 16:05:16 +00:00
|
|
|
Asset int32
|
2020-03-05 14:11:58 +00:00
|
|
|
// Address is the address of the sender.
|
|
|
|
From util.Uint160
|
|
|
|
// To is the address of the receiver.
|
|
|
|
To util.Uint160
|
|
|
|
// Amount is the amount of tokens transferred.
|
|
|
|
// It is negative when tokens are sent and positive if they are received.
|
2020-07-09 09:57:24 +00:00
|
|
|
Amount big.Int
|
2020-08-14 09:16:24 +00:00
|
|
|
// Block is a number of block when the event occurred.
|
2020-03-05 14:11:58 +00:00
|
|
|
Block uint32
|
2020-08-14 09:16:24 +00:00
|
|
|
// Timestamp is the timestamp of the block where transfer occurred.
|
2020-04-21 11:26:57 +00:00
|
|
|
Timestamp uint64
|
2020-03-05 14:11:58 +00:00
|
|
|
// Tx is a hash the transaction.
|
|
|
|
Tx util.Uint256
|
|
|
|
}
|
|
|
|
|
2021-07-25 12:00:44 +00:00
|
|
|
// NEP17TransferInfo stores map of the NEP17 contract IDs to the balance's last updated
|
|
|
|
// block trackers along with information about NEP17 transfer batch.
|
2021-07-25 10:48:50 +00:00
|
|
|
type NEP17TransferInfo struct {
|
2021-07-25 12:00:44 +00:00
|
|
|
LastUpdated map[int32]uint32
|
2020-03-12 09:43:21 +00:00
|
|
|
// NextTransferBatch stores an index of the next transfer batch.
|
|
|
|
NextTransferBatch uint32
|
2021-02-26 11:08:48 +00:00
|
|
|
// NewBatch is true if batch with the `NextTransferBatch` index should be created.
|
|
|
|
NewBatch bool
|
2020-03-11 15:22:46 +00:00
|
|
|
}
|
|
|
|
|
2021-07-25 10:48:50 +00:00
|
|
|
// NewNEP17TransferInfo returns new NEP17TransferInfo.
|
|
|
|
func NewNEP17TransferInfo() *NEP17TransferInfo {
|
|
|
|
return &NEP17TransferInfo{
|
2021-07-25 12:00:44 +00:00
|
|
|
LastUpdated: make(map[int32]uint32),
|
2020-03-11 15:22:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DecodeBinary implements io.Serializable interface.
|
2021-07-25 10:48:50 +00:00
|
|
|
func (bs *NEP17TransferInfo) DecodeBinary(r *io.BinReader) {
|
2020-03-12 09:43:21 +00:00
|
|
|
bs.NextTransferBatch = r.ReadU32LE()
|
2021-02-26 11:08:48 +00:00
|
|
|
bs.NewBatch = r.ReadBool()
|
2020-03-11 15:22:46 +00:00
|
|
|
lenBalances := r.ReadVarUint()
|
2021-07-25 12:00:44 +00:00
|
|
|
m := make(map[int32]uint32, lenBalances)
|
2020-03-11 15:22:46 +00:00
|
|
|
for i := 0; i < int(lenBalances); i++ {
|
2020-07-28 09:23:58 +00:00
|
|
|
key := int32(r.ReadU32LE())
|
2021-07-25 12:00:44 +00:00
|
|
|
m[key] = r.ReadU32LE()
|
2020-03-11 15:22:46 +00:00
|
|
|
}
|
2021-07-25 10:48:50 +00:00
|
|
|
bs.LastUpdated = m
|
2020-03-11 15:22:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// EncodeBinary implements io.Serializable interface.
|
2021-07-25 10:48:50 +00:00
|
|
|
func (bs *NEP17TransferInfo) EncodeBinary(w *io.BinWriter) {
|
2020-03-12 09:43:21 +00:00
|
|
|
w.WriteU32LE(bs.NextTransferBatch)
|
2021-02-26 11:08:48 +00:00
|
|
|
w.WriteBool(bs.NewBatch)
|
2021-07-25 10:48:50 +00:00
|
|
|
w.WriteVarUint(uint64(len(bs.LastUpdated)))
|
|
|
|
for k, v := range bs.LastUpdated {
|
2020-07-28 09:23:58 +00:00
|
|
|
w.WriteU32LE(uint32(k))
|
2021-07-25 12:00:44 +00:00
|
|
|
w.WriteU32LE(v)
|
2020-03-11 15:22:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-05 14:11:58 +00:00
|
|
|
// Append appends single transfer to a log.
|
2020-11-24 08:14:25 +00:00
|
|
|
func (lg *NEP17TransferLog) Append(tr *NEP17Transfer) error {
|
2020-09-21 18:46:40 +00:00
|
|
|
// The first entry, set up counter.
|
|
|
|
if len(lg.Raw) == 0 {
|
2021-08-05 09:59:08 +00:00
|
|
|
lg.Raw = append(lg.Raw, 0)
|
2020-09-21 18:46:40 +00:00
|
|
|
}
|
2021-08-05 09:59:08 +00:00
|
|
|
|
|
|
|
b := bytes.NewBuffer(lg.Raw)
|
|
|
|
w := io.NewBinWriterFromIO(b)
|
|
|
|
|
|
|
|
tr.EncodeBinary(w)
|
2020-03-05 14:11:58 +00:00
|
|
|
if w.Err != nil {
|
|
|
|
return w.Err
|
|
|
|
}
|
2021-08-05 09:59:08 +00:00
|
|
|
lg.Raw = b.Bytes()
|
|
|
|
lg.Raw[0]++
|
2020-03-05 14:11:58 +00:00
|
|
|
return nil
|
2020-03-05 12:16:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ForEach iterates over transfer log returning on first error.
|
2020-11-24 08:14:25 +00:00
|
|
|
func (lg *NEP17TransferLog) ForEach(f func(*NEP17Transfer) (bool, error)) (bool, error) {
|
2020-09-08 09:57:45 +00:00
|
|
|
if lg == nil || len(lg.Raw) == 0 {
|
2020-09-08 12:29:07 +00:00
|
|
|
return true, nil
|
2020-03-05 12:16:03 +00:00
|
|
|
}
|
2020-11-24 08:14:25 +00:00
|
|
|
transfers := make([]NEP17Transfer, lg.Size())
|
2020-09-08 09:57:45 +00:00
|
|
|
r := io.NewBinReaderFromBuf(lg.Raw[1:])
|
|
|
|
for i := 0; i < lg.Size(); i++ {
|
|
|
|
transfers[i].DecodeBinary(r)
|
|
|
|
}
|
|
|
|
if r.Err != nil {
|
2020-09-08 12:29:07 +00:00
|
|
|
return false, r.Err
|
2020-09-08 09:57:45 +00:00
|
|
|
}
|
|
|
|
for i := len(transfers) - 1; i >= 0; i-- {
|
2020-09-08 12:29:07 +00:00
|
|
|
cont, err := f(&transfers[i])
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
if !cont {
|
|
|
|
return false, nil
|
2020-03-05 12:16:03 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-08 12:29:07 +00:00
|
|
|
return true, nil
|
2020-03-05 14:11:58 +00:00
|
|
|
}
|
|
|
|
|
2020-03-12 09:32:24 +00:00
|
|
|
// Size returns an amount of transfer written in log.
|
2020-11-24 08:14:25 +00:00
|
|
|
func (lg *NEP17TransferLog) Size() int {
|
2020-09-21 18:46:40 +00:00
|
|
|
if len(lg.Raw) == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return int(lg.Raw[0])
|
2020-03-12 09:32:24 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 14:11:58 +00:00
|
|
|
// EncodeBinary implements io.Serializable interface.
|
2020-11-24 08:14:25 +00:00
|
|
|
func (t *NEP17Transfer) EncodeBinary(w *io.BinWriter) {
|
2020-07-28 16:05:16 +00:00
|
|
|
w.WriteU32LE(uint32(t.Asset))
|
2020-03-05 14:11:58 +00:00
|
|
|
w.WriteBytes(t.Tx[:])
|
|
|
|
w.WriteBytes(t.From[:])
|
|
|
|
w.WriteBytes(t.To[:])
|
|
|
|
w.WriteU32LE(t.Block)
|
2020-04-21 11:26:57 +00:00
|
|
|
w.WriteU64LE(t.Timestamp)
|
2020-09-21 18:51:33 +00:00
|
|
|
amount := bigint.ToBytes(&t.Amount)
|
|
|
|
w.WriteVarBytes(amount)
|
2020-03-05 14:11:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DecodeBinary implements io.Serializable interface.
|
2020-11-24 08:14:25 +00:00
|
|
|
func (t *NEP17Transfer) DecodeBinary(r *io.BinReader) {
|
2020-07-28 16:05:16 +00:00
|
|
|
t.Asset = int32(r.ReadU32LE())
|
2020-03-05 14:11:58 +00:00
|
|
|
r.ReadBytes(t.Tx[:])
|
|
|
|
r.ReadBytes(t.From[:])
|
|
|
|
r.ReadBytes(t.To[:])
|
|
|
|
t.Block = r.ReadU32LE()
|
2020-04-21 11:26:57 +00:00
|
|
|
t.Timestamp = r.ReadU64LE()
|
2020-09-21 18:51:33 +00:00
|
|
|
amount := r.ReadVarBytes(bigint.MaxBytesLen)
|
|
|
|
t.Amount = *bigint.FromBytes(amount)
|
2020-03-05 14:11:58 +00:00
|
|
|
}
|