1- package jsonrpcindex
1+ package jsonrpc
22
33import (
44 "errors"
@@ -20,16 +20,16 @@ import (
2020 "github.com/iotaledger/wasp/packages/vm/core/governance"
2121)
2222
23+ // Index allows efficient retrieval of EVM blocks and transactions given the block number.
24+ // The indexed information is stored in a database (either persisted or in-memory).
2325type Index struct {
2426 store kvstore.KVStore
25- blockchainDB func (chainState state.State ) * emulator.BlockchainDB
2627 stateByTrieRoot func (trieRoot trie.Hash ) (state.State , error )
2728
28- mu sync.Mutex
29+ mu sync.RWMutex
2930}
3031
31- func New (
32- blockchainDB func (chainState state.State ) * emulator.BlockchainDB ,
32+ func NewIndex (
3333 stateByTrieRoot func (trieRoot trie.Hash ) (state.State , error ),
3434 indexDbEngine hivedb.Engine ,
3535 indexDbPath string ,
@@ -40,26 +40,31 @@ func New(
4040 }
4141 return & Index {
4242 store : db .KVStore (),
43- blockchainDB : blockchainDB ,
4443 stateByTrieRoot : stateByTrieRoot ,
45- mu : sync.Mutex {},
44+ mu : sync.RWMutex {},
4645 }
4746}
4847
49- func (c * Index ) IndexBlock (trieRoot trie.Hash ) {
48+ // IndexBlock is called only in an archive node, whenever a block is published.
49+ //
50+ // It walks back following the previous trie root until the latest cached
51+ // block, associating the EVM block and transaction hashes with the
52+ // corresponding block index.
53+ func (c * Index ) IndexBlock (trieRoot trie.Hash ) error {
5054 c .mu .Lock ()
5155 defer c .mu .Unlock ()
56+
5257 state , err := c .stateByTrieRoot (trieRoot )
5358 if err != nil {
54- panic ( err )
59+ return fmt . Errorf ( "stateByTrieRoot: %w" , err )
5560 }
5661 blockKeepAmount := governance .NewStateReaderFromChainState (state ).GetBlockKeepAmount ()
5762 if blockKeepAmount == - 1 {
58- return // pruning disabled, never cache anything
63+ return nil // pruning disabled, never cache anything
5964 }
6065 // cache the block that will be pruned next (this way reorgs are okay, as long as it never reorgs more than `blockKeepAmount`, which would be catastrophic)
6166 if state .BlockIndex () < uint32 (blockKeepAmount - 1 ) {
62- return
67+ return nil
6368 }
6469 blockIndexToCache := state .BlockIndex () - uint32 (blockKeepAmount - 1 )
6570 cacheUntil := uint32 (0 )
@@ -71,24 +76,24 @@ func (c *Index) IndexBlock(trieRoot trie.Hash) {
7176 // we need to look at the next block to get the trie commitment of the block we want to cache
7277 nextBlockInfo , found := blocklog .NewStateReaderFromChainState (state ).GetBlockInfo (blockIndexToCache + 1 )
7378 if ! found {
74- panic ( fmt .Errorf ("block %d not found on active state %d" , blockIndexToCache , state .BlockIndex () ))
79+ return fmt .Errorf ("block %d not found on active state %d" , blockIndexToCache , state .BlockIndex ())
7580 }
7681
7782 // start in the active state of the block to cache
7883 activeStateToCache , err := c .stateByTrieRoot (nextBlockInfo .PreviousL1Commitment ().TrieRoot ())
7984 if err != nil {
80- panic ( err )
85+ return fmt . Errorf ( "stateByTrieRoot: %w" , err )
8186 }
8287
8388 for i := blockIndexToCache ; i >= cacheUntil ; i -- {
8489 // walk back and save all blocks between [lastBlockIndexCached...blockIndexToCache]
8590
8691 blockinfo , found := blocklog .NewStateReaderFromChainState (activeStateToCache ).GetBlockInfo (i )
8792 if ! found {
88- panic ( fmt .Errorf ("block %d not found on active state %d" , i , state .BlockIndex () ))
93+ return fmt .Errorf ("block %d not found on active state %d" , i , state .BlockIndex ())
8994 }
9095
91- db := c . blockchainDB (activeStateToCache )
96+ db := blockchainDB (activeStateToCache )
9297 blockTrieRoot := activeStateToCache .TrieRoot ()
9398 c .setBlockTrieRootByIndex (i , blockTrieRoot )
9499
@@ -106,17 +111,22 @@ func (c *Index) IndexBlock(trieRoot trie.Hash) {
106111 }
107112 activeStateToCache , err = c .stateByTrieRoot (blockinfo .PreviousL1Commitment ().TrieRoot ())
108113 if err != nil {
109- panic ( err )
114+ return fmt . Errorf ( "stateByTrieRoot: %w" , err )
110115 }
111116 }
112117 c .setLastBlockIndexed (blockIndexToCache )
113118 c .store .Flush ()
119+ return nil
114120}
115121
116122func (c * Index ) BlockByNumber (n * big.Int ) * types.Block {
117123 if n == nil {
118124 return nil
119125 }
126+
127+ c .mu .RLock ()
128+ defer c .mu .RUnlock ()
129+
120130 db := c .evmDBFromBlockIndex (uint32 (n .Uint64 ()))
121131 if db == nil {
122132 return nil
@@ -125,6 +135,9 @@ func (c *Index) BlockByNumber(n *big.Int) *types.Block {
125135}
126136
127137func (c * Index ) BlockByHash (hash common.Hash ) * types.Block {
138+ c .mu .RLock ()
139+ defer c .mu .RUnlock ()
140+
128141 blockIndex := c .blockIndexByHash (hash )
129142 if blockIndex == nil {
130143 return nil
@@ -133,10 +146,16 @@ func (c *Index) BlockByHash(hash common.Hash) *types.Block {
133146}
134147
135148func (c * Index ) BlockTrieRootByIndex (n uint32 ) * trie.Hash {
149+ c .mu .RLock ()
150+ defer c .mu .RUnlock ()
151+
136152 return c .blockTrieRootByIndex (n )
137153}
138154
139155func (c * Index ) TxByHash (hash common.Hash ) (tx * types.Transaction , blockHash common.Hash , blockNumber , txIndex uint64 ) {
156+ c .mu .RLock ()
157+ defer c .mu .RUnlock ()
158+
140159 blockIndex := c .blockIndexByTxHash (hash )
141160 if blockIndex == nil {
142161 return nil , common.Hash {}, 0 , 0
@@ -149,6 +168,9 @@ func (c *Index) TxByHash(hash common.Hash) (tx *types.Transaction, blockHash com
149168}
150169
151170func (c * Index ) GetReceiptByTxHash (hash common.Hash ) * types.Receipt {
171+ c .mu .RLock ()
172+ defer c .mu .RUnlock ()
173+
152174 blockIndex := c .blockIndexByTxHash (hash )
153175 if blockIndex == nil {
154176 return nil
@@ -157,6 +179,9 @@ func (c *Index) GetReceiptByTxHash(hash common.Hash) *types.Receipt {
157179}
158180
159181func (c * Index ) TxByBlockHashAndIndex (blockHash common.Hash , txIndex uint64 ) (tx * types.Transaction , blockNumber uint64 ) {
182+ c .mu .RLock ()
183+ defer c .mu .RUnlock ()
184+
160185 blockIndex := c .blockIndexByHash (blockHash )
161186 if blockIndex == nil {
162187 return nil , 0
@@ -173,6 +198,9 @@ func (c *Index) TxByBlockHashAndIndex(blockHash common.Hash, txIndex uint64) (tx
173198}
174199
175200func (c * Index ) TxByBlockNumberAndIndex (blockNumber * big.Int , txIndex uint64 ) (tx * types.Transaction , blockHash common.Hash ) {
201+ c .mu .RLock ()
202+ defer c .mu .RUnlock ()
203+
176204 if blockNumber == nil {
177205 return nil , common.Hash {}
178206 }
@@ -192,6 +220,9 @@ func (c *Index) TxByBlockNumberAndIndex(blockNumber *big.Int, txIndex uint64) (t
192220}
193221
194222func (c * Index ) TxsByBlockNumber (blockNumber * big.Int ) types.Transactions {
223+ c .mu .RLock ()
224+ defer c .mu .RUnlock ()
225+
195226 if blockNumber == nil {
196227 return nil
197228 }
@@ -209,10 +240,10 @@ func (c *Index) TxsByBlockNumber(blockNumber *big.Int) types.Transactions {
209240// internals
210241
211242const (
212- prefixLastBlockIndexed = iota
213- prefixBlockTrieRootByIndex
214- prefixBlockIndexByTxHash
215- prefixBlockIndexByHash
243+ prefixLastBlockIndexed = iota // ISC block index (uint32)
244+ prefixBlockTrieRootByIndex // ISC block index (uint32) => ISC trie root
245+ prefixBlockIndexByTxHash // EVM tx hash => ISC block index (uint32)
246+ prefixBlockIndexByHash // EVM block hash => ISC block index (uint32)
216247)
217248
218249func keyLastBlockIndexed () kvstore.Key {
@@ -221,7 +252,7 @@ func keyLastBlockIndexed() kvstore.Key {
221252
222253func keyBlockTrieRootByIndex (i uint32 ) kvstore.Key {
223254 key := []byte {prefixBlockTrieRootByIndex }
224- key = append (key , codec.Encode [ uint32 ] (i )... )
255+ key = append (key , codec .Encode (i )... )
225256 return key
226257}
227258
@@ -256,7 +287,7 @@ func (c *Index) set(key kvstore.Key, value []byte) {
256287}
257288
258289func (c * Index ) setLastBlockIndexed (n uint32 ) {
259- c .set (keyLastBlockIndexed (), codec.Encode [ uint32 ] (n ))
290+ c .set (keyLastBlockIndexed (), codec .Encode (n ))
260291}
261292
262293func (c * Index ) lastBlockIndexed () * uint32 {
@@ -285,7 +316,7 @@ func (c *Index) blockTrieRootByIndex(i uint32) *trie.Hash {
285316}
286317
287318func (c * Index ) setBlockIndexByTxHash (txHash common.Hash , blockIndex uint32 ) {
288- c .set (keyBlockIndexByTxHash (txHash ), codec.Encode [ uint32 ] (blockIndex ))
319+ c .set (keyBlockIndexByTxHash (txHash ), codec .Encode (blockIndex ))
289320}
290321
291322func (c * Index ) blockIndexByTxHash (txHash common.Hash ) * uint32 {
@@ -298,7 +329,7 @@ func (c *Index) blockIndexByTxHash(txHash common.Hash) *uint32 {
298329}
299330
300331func (c * Index ) setBlockIndexByHash (hash common.Hash , blockIndex uint32 ) {
301- c .set (keyBlockIndexByHash (hash ), codec.Encode [ uint32 ] (blockIndex ))
332+ c .set (keyBlockIndexByHash (hash ), codec .Encode (blockIndex ))
302333}
303334
304335func (c * Index ) blockIndexByHash (hash common.Hash ) * uint32 {
@@ -319,5 +350,5 @@ func (c *Index) evmDBFromBlockIndex(n uint32) *emulator.BlockchainDB {
319350 if err != nil {
320351 panic (err )
321352 }
322- return c . blockchainDB (state )
353+ return blockchainDB (state )
323354}
0 commit comments