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  }