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 }