github.com/dim4egster/coreth@v0.10.2/plugin/evm/atomic_trie_iterator.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package evm 5 6 import ( 7 "encoding/binary" 8 "fmt" 9 10 "github.com/dim4egster/qmallgo/chains/atomic" 11 "github.com/dim4egster/qmallgo/codec" 12 "github.com/dim4egster/qmallgo/ids" 13 "github.com/dim4egster/qmallgo/utils/wrappers" 14 15 "github.com/dim4egster/coreth/trie" 16 "github.com/ethereum/go-ethereum/common" 17 ) 18 19 const atomicTrieKeyLen = wrappers.LongLen + common.HashLength 20 21 // atomicTrieIterator is an implementation of types.AtomicTrieIterator that serves 22 // parsed data with each iteration 23 type atomicTrieIterator struct { 24 trieIterator *trie.Iterator // underlying trie.Iterator 25 codec codec.Manager 26 key []byte 27 atomicOps *atomic.Requests // atomic operation entries at this iteration 28 blockchainID ids.ID // blockchain ID 29 blockNumber uint64 // block number at this iteration 30 err error // error if any has occurred 31 } 32 33 func NewAtomicTrieIterator(trieIterator *trie.Iterator, codec codec.Manager) AtomicTrieIterator { 34 return &atomicTrieIterator{trieIterator: trieIterator, codec: codec} 35 } 36 37 // Error returns error, if any encountered during this iteration 38 func (a *atomicTrieIterator) Error() error { 39 return a.err 40 } 41 42 // Next returns whether there are more nodes to iterate over 43 // On success, this function sets the blockNumber and atomicOps fields 44 // In case of an error during this iteration, it sets the error value and resets the above fields. 45 // It is the responsibility of the caller to check the result of Error() after an iterator reports 46 // having no more elements to iterate. 47 func (a *atomicTrieIterator) Next() bool { 48 if !a.trieIterator.Next() { 49 a.resetFields(a.trieIterator.Err) 50 return false 51 } 52 53 // if the underlying iterator has data to iterate over, parse and set the fields 54 // key is [blockNumberBytes]+[blockchainIDBytes] = 8+32=40 bytes 55 keyLen := len(a.trieIterator.Key) 56 // If the key has an unexpected length, set the error and stop the iteration since the data is 57 // no longer reliable. 58 if keyLen != atomicTrieKeyLen { 59 a.resetFields(fmt.Errorf("expected atomic trie key length to be %d but was %d", atomicTrieKeyLen, keyLen)) 60 return false 61 } 62 63 blockNumber := binary.BigEndian.Uint64(a.trieIterator.Key[:wrappers.LongLen]) 64 blockchainID, err := ids.ToID(a.trieIterator.Key[wrappers.LongLen:]) 65 if err != nil { 66 a.resetFields(err) 67 return false 68 } 69 70 // The value in the iterator should be the atomic requests serialized the the codec. 71 requests := new(atomic.Requests) 72 if _, err = a.codec.Unmarshal(a.trieIterator.Value, requests); err != nil { 73 a.resetFields(err) 74 return false 75 } 76 77 // Success, update the struct fields 78 a.blockNumber = blockNumber 79 a.blockchainID = blockchainID 80 a.atomicOps = requests 81 a.key = a.trieIterator.Key // trieIterator.Key is already newly allocated so copy is not needed here 82 return true 83 } 84 85 // resetFields resets the value fields of the iterator to their nil values and sets the error value to [err]. 86 func (a *atomicTrieIterator) resetFields(err error) { 87 a.err = err 88 a.blockNumber = 0 89 a.blockchainID = ids.ID{} 90 a.atomicOps = nil 91 a.key = nil 92 } 93 94 // BlockNumber returns the current block number 95 func (a *atomicTrieIterator) BlockNumber() uint64 { 96 return a.blockNumber 97 } 98 99 // BlockchainID returns the current blockchain ID at the current block number 100 func (a *atomicTrieIterator) BlockchainID() ids.ID { 101 return a.blockchainID 102 } 103 104 // AtomicOps returns atomic requests for the blockchainID at the current block number 105 // returned object can be freely modified 106 func (a *atomicTrieIterator) AtomicOps() *atomic.Requests { 107 return a.atomicOps 108 } 109 110 // Key returns the current database key that the iterator is iterating 111 // returned []byte can be freely modified 112 func (a *atomicTrieIterator) Key() []byte { 113 return a.key 114 }