github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/state/tokens.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"math/big"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/config/limits"
     8  	"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
     9  	"github.com/nspcc-dev/neo-go/pkg/io"
    10  	"github.com/nspcc-dev/neo-go/pkg/util"
    11  )
    12  
    13  // TokenTransferBatchSize is the maximum number of entries for TokenTransferLog.
    14  const TokenTransferBatchSize = 128
    15  
    16  // TokenTransferLog is a serialized log of token transfers.
    17  type TokenTransferLog struct {
    18  	Raw []byte
    19  	buf *bytes.Buffer
    20  	iow *io.BinWriter
    21  }
    22  
    23  // NEP17Transfer represents a single NEP-17 Transfer event.
    24  type NEP17Transfer struct {
    25  	// Asset is a NEP-17 contract ID.
    26  	Asset int32
    27  	// Counterparty is the address of the sender/receiver (the other side of the transfer).
    28  	Counterparty util.Uint160
    29  	// Amount is the amount of tokens transferred.
    30  	// It is negative when tokens are sent and positive if they are received.
    31  	Amount *big.Int
    32  	// Block is a number of block when the event occurred.
    33  	Block uint32
    34  	// Timestamp is the timestamp of the block where transfer occurred.
    35  	Timestamp uint64
    36  	// Tx is a hash the transaction.
    37  	Tx util.Uint256
    38  }
    39  
    40  // NEP11Transfer represents a single NEP-11 Transfer event.
    41  type NEP11Transfer struct {
    42  	NEP17Transfer
    43  
    44  	// ID is a NEP-11 token ID.
    45  	ID []byte
    46  }
    47  
    48  // TokenTransferInfo stores a map of the contract IDs to the balance's last updated
    49  // block trackers along with the information about NEP-17 and NEP-11 transfer batch.
    50  type TokenTransferInfo struct {
    51  	LastUpdated map[int32]uint32
    52  	// NextNEP11Batch stores the index of the next NEP-11 transfer batch.
    53  	NextNEP11Batch uint32
    54  	// NextNEP17Batch stores the index of the next NEP-17 transfer batch.
    55  	NextNEP17Batch uint32
    56  	// NextNEP11NewestTimestamp stores the block timestamp of the first NEP-11 transfer in raw.
    57  	NextNEP11NewestTimestamp uint64
    58  	// NextNEP17NewestTimestamp stores the block timestamp of the first NEP-17 transfer in raw.
    59  	NextNEP17NewestTimestamp uint64
    60  	// NewNEP11Batch is true if batch with the `NextNEP11Batch` index should be created.
    61  	NewNEP11Batch bool
    62  	// NewNEP17Batch is true if batch with the `NextNEP17Batch` index should be created.
    63  	NewNEP17Batch bool
    64  }
    65  
    66  // NewTokenTransferInfo returns new TokenTransferInfo.
    67  func NewTokenTransferInfo() *TokenTransferInfo {
    68  	return &TokenTransferInfo{
    69  		NewNEP11Batch: true,
    70  		NewNEP17Batch: true,
    71  		LastUpdated:   make(map[int32]uint32),
    72  	}
    73  }
    74  
    75  // DecodeBinary implements the io.Serializable interface.
    76  func (bs *TokenTransferInfo) DecodeBinary(r *io.BinReader) {
    77  	bs.NextNEP11Batch = r.ReadU32LE()
    78  	bs.NextNEP17Batch = r.ReadU32LE()
    79  	bs.NextNEP11NewestTimestamp = r.ReadU64LE()
    80  	bs.NextNEP17NewestTimestamp = r.ReadU64LE()
    81  	bs.NewNEP11Batch = r.ReadBool()
    82  	bs.NewNEP17Batch = r.ReadBool()
    83  	lenBalances := r.ReadVarUint()
    84  	m := make(map[int32]uint32, lenBalances)
    85  	for i := 0; i < int(lenBalances); i++ {
    86  		key := int32(r.ReadU32LE())
    87  		m[key] = r.ReadU32LE()
    88  	}
    89  	bs.LastUpdated = m
    90  }
    91  
    92  // EncodeBinary implements the io.Serializable interface.
    93  func (bs *TokenTransferInfo) EncodeBinary(w *io.BinWriter) {
    94  	w.WriteU32LE(bs.NextNEP11Batch)
    95  	w.WriteU32LE(bs.NextNEP17Batch)
    96  	w.WriteU64LE(bs.NextNEP11NewestTimestamp)
    97  	w.WriteU64LE(bs.NextNEP17NewestTimestamp)
    98  	w.WriteBool(bs.NewNEP11Batch)
    99  	w.WriteBool(bs.NewNEP17Batch)
   100  	w.WriteVarUint(uint64(len(bs.LastUpdated)))
   101  	for k, v := range bs.LastUpdated {
   102  		w.WriteU32LE(uint32(k))
   103  		w.WriteU32LE(v)
   104  	}
   105  }
   106  
   107  // Append appends a single transfer to a log.
   108  func (lg *TokenTransferLog) Append(tr io.Serializable) error {
   109  	// The first entry, set up counter.
   110  	if len(lg.Raw) == 0 {
   111  		lg.Raw = append(lg.Raw, 0)
   112  	}
   113  
   114  	if lg.buf == nil {
   115  		lg.buf = bytes.NewBuffer(lg.Raw)
   116  	}
   117  	if lg.iow == nil {
   118  		lg.iow = io.NewBinWriterFromIO(lg.buf)
   119  	}
   120  
   121  	tr.EncodeBinary(lg.iow)
   122  	if lg.iow.Err != nil {
   123  		return lg.iow.Err
   124  	}
   125  	lg.Raw = lg.buf.Bytes()
   126  	lg.Raw[0]++
   127  	return nil
   128  }
   129  
   130  // Reset resets the state of the log, clearing all entries, but keeping existing
   131  // buffer for future writes.
   132  func (lg *TokenTransferLog) Reset() {
   133  	lg.Raw = lg.Raw[:0]
   134  	lg.buf = nil
   135  	lg.iow = nil
   136  }
   137  
   138  // ForEachNEP11 iterates over a transfer log returning on the first error.
   139  func (lg *TokenTransferLog) ForEachNEP11(f func(*NEP11Transfer) (bool, error)) (bool, error) {
   140  	if lg == nil || len(lg.Raw) == 0 {
   141  		return true, nil
   142  	}
   143  	transfers := make([]NEP11Transfer, lg.Size())
   144  	r := io.NewBinReaderFromBuf(lg.Raw[1:])
   145  	for i := 0; i < lg.Size(); i++ {
   146  		transfers[i].DecodeBinary(r)
   147  	}
   148  	if r.Err != nil {
   149  		return false, r.Err
   150  	}
   151  	for i := len(transfers) - 1; i >= 0; i-- {
   152  		cont, err := f(&transfers[i])
   153  		if err != nil || !cont {
   154  			return false, err
   155  		}
   156  	}
   157  	return true, nil
   158  }
   159  
   160  // ForEachNEP17 iterates over a transfer log returning on the first error.
   161  func (lg *TokenTransferLog) ForEachNEP17(f func(*NEP17Transfer) (bool, error)) (bool, error) {
   162  	if lg == nil || len(lg.Raw) == 0 {
   163  		return true, nil
   164  	}
   165  	transfers := make([]NEP17Transfer, lg.Size())
   166  	r := io.NewBinReaderFromBuf(lg.Raw[1:])
   167  	for i := 0; i < lg.Size(); i++ {
   168  		transfers[i].DecodeBinary(r)
   169  	}
   170  	if r.Err != nil {
   171  		return false, r.Err
   172  	}
   173  	for i := len(transfers) - 1; i >= 0; i-- {
   174  		cont, err := f(&transfers[i])
   175  		if err != nil || !cont {
   176  			return false, err
   177  		}
   178  	}
   179  	return true, nil
   180  }
   181  
   182  // Size returns the amount of the transfer written in the log.
   183  func (lg *TokenTransferLog) Size() int {
   184  	if len(lg.Raw) == 0 {
   185  		return 0
   186  	}
   187  	return int(lg.Raw[0])
   188  }
   189  
   190  // EncodeBinary implements the io.Serializable interface.
   191  func (t *NEP17Transfer) EncodeBinary(w *io.BinWriter) {
   192  	var buf [bigint.MaxBytesLen]byte
   193  
   194  	w.WriteU32LE(uint32(t.Asset))
   195  	w.WriteBytes(t.Tx[:])
   196  	w.WriteBytes(t.Counterparty[:])
   197  	w.WriteU32LE(t.Block)
   198  	w.WriteU64LE(t.Timestamp)
   199  	amount := bigint.ToPreallocatedBytes(t.Amount, buf[:])
   200  	w.WriteVarBytes(amount)
   201  }
   202  
   203  // DecodeBinary implements the io.Serializable interface.
   204  func (t *NEP17Transfer) DecodeBinary(r *io.BinReader) {
   205  	t.Asset = int32(r.ReadU32LE())
   206  	r.ReadBytes(t.Tx[:])
   207  	r.ReadBytes(t.Counterparty[:])
   208  	t.Block = r.ReadU32LE()
   209  	t.Timestamp = r.ReadU64LE()
   210  	amount := r.ReadVarBytes(bigint.MaxBytesLen)
   211  	t.Amount = bigint.FromBytes(amount)
   212  }
   213  
   214  // EncodeBinary implements the io.Serializable interface.
   215  func (t *NEP11Transfer) EncodeBinary(w *io.BinWriter) {
   216  	t.NEP17Transfer.EncodeBinary(w)
   217  	w.WriteVarBytes(t.ID)
   218  }
   219  
   220  // DecodeBinary implements the io.Serializable interface.
   221  func (t *NEP11Transfer) DecodeBinary(r *io.BinReader) {
   222  	t.NEP17Transfer.DecodeBinary(r)
   223  	t.ID = r.ReadVarBytes(limits.MaxStorageKeyLen)
   224  }