1717package filtermaps
1818
1919import (
20+ "sync"
21+
2022 "github.com/ethereum/go-ethereum/common"
2123 "github.com/ethereum/go-ethereum/core/types"
2224 "github.com/ethereum/go-ethereum/log"
@@ -39,6 +41,7 @@ type blockchain interface {
3941// of the underlying blockchain, it should only possess the block headers
4042// and receipts up until the expected chain view head.
4143type ChainView struct {
44+ lock sync.Mutex
4245 chain blockchain
4346 headNumber uint64
4447 hashes []common.Hash // block hashes starting backwards from headNumber until first canonical hash
@@ -55,55 +58,83 @@ func NewChainView(chain blockchain, number uint64, hash common.Hash) *ChainView
5558 return cv
5659}
5760
58- // getBlockHash returns the block hash belonging to the given block number.
61+ // HeadNumber returns the head block number of the chain view.
62+ func (cv * ChainView ) HeadNumber () uint64 {
63+ return cv .headNumber
64+ }
65+
66+ // BlockHash returns the block hash belonging to the given block number.
5967// Note that the hash of the head block is not returned because ChainView might
6068// represent a view where the head block is currently being created.
61- func (cv * ChainView ) getBlockHash (number uint64 ) common.Hash {
62- if number >= cv .headNumber {
69+ func (cv * ChainView ) BlockHash (number uint64 ) common.Hash {
70+ cv .lock .Lock ()
71+ defer cv .lock .Unlock ()
72+
73+ if number > cv .headNumber {
6374 panic ("invalid block number" )
6475 }
6576 return cv .blockHash (number )
6677}
6778
68- // getBlockId returns the unique block id belonging to the given block number.
79+ // BlockId returns the unique block id belonging to the given block number.
6980// Note that it is currently equal to the block hash. In the future it might
7081// be a different id for future blocks if the log index root becomes part of
7182// consensus and therefore rendering the index with the new head will happen
7283// before the hash of that new head is available.
73- func (cv * ChainView ) getBlockId (number uint64 ) common.Hash {
84+ func (cv * ChainView ) BlockId (number uint64 ) common.Hash {
85+ cv .lock .Lock ()
86+ defer cv .lock .Unlock ()
87+
7488 if number > cv .headNumber {
7589 panic ("invalid block number" )
7690 }
7791 return cv .blockHash (number )
7892}
7993
80- // getReceipts returns the set of receipts belonging to the block at the given
94+ // Header returns the block header at the given block number.
95+ func (cv * ChainView ) Header (number uint64 ) * types.Header {
96+ return cv .chain .GetHeader (cv .BlockHash (number ), number )
97+ }
98+
99+ // Receipts returns the set of receipts belonging to the block at the given
81100// block number.
82- func (cv * ChainView ) getReceipts (number uint64 ) types.Receipts {
83- if number > cv .headNumber {
84- panic ("invalid block number" )
85- }
86- blockHash := cv .blockHash (number )
101+ func (cv * ChainView ) Receipts (number uint64 ) types.Receipts {
102+ blockHash := cv .BlockHash (number )
87103 if blockHash == (common.Hash {}) {
88104 log .Error ("Chain view: block hash unavailable" , "number" , number , "head" , cv .headNumber )
89105 }
90106 return cv .chain .GetReceiptsByHash (blockHash )
91107}
92108
109+ // SharedRange returns the block range shared by two chain views.
110+ func (cv * ChainView ) SharedRange (cv2 * ChainView ) common.Range [uint64 ] {
111+ cv .lock .Lock ()
112+ defer cv .lock .Unlock ()
113+
114+ if cv == nil || cv2 == nil || ! cv .extendNonCanonical () || ! cv2 .extendNonCanonical () {
115+ return common.Range [uint64 ]{}
116+ }
117+ var sharedLen uint64
118+ for n := min (cv .headNumber + 1 - uint64 (len (cv .hashes )), cv2 .headNumber + 1 - uint64 (len (cv2 .hashes ))); n <= cv .headNumber && n <= cv2 .headNumber && cv .blockHash (n ) == cv2 .blockHash (n ); n ++ {
119+ sharedLen = n + 1
120+ }
121+ return common .NewRange (0 , sharedLen )
122+ }
123+
93124// limitedView returns a new chain view that is a truncated version of the parent view.
94125func (cv * ChainView ) limitedView (newHead uint64 ) * ChainView {
95126 if newHead >= cv .headNumber {
96127 return cv
97128 }
98- return NewChainView (cv .chain , newHead , cv .blockHash (newHead ))
129+ return NewChainView (cv .chain , newHead , cv .BlockHash (newHead ))
99130}
100131
101132// equalViews returns true if the two chain views are equivalent.
102133func equalViews (cv1 , cv2 * ChainView ) bool {
103134 if cv1 == nil || cv2 == nil {
104135 return false
105136 }
106- return cv1 .headNumber == cv2 .headNumber && cv1 .getBlockId (cv1 .headNumber ) == cv2 .getBlockId (cv2 .headNumber )
137+ return cv1 .headNumber == cv2 .headNumber && cv1 .BlockId (cv1 .headNumber ) == cv2 .BlockId (cv2 .headNumber )
107138}
108139
109140// matchViews returns true if the two chain views are equivalent up until the
@@ -117,9 +148,9 @@ func matchViews(cv1, cv2 *ChainView, number uint64) bool {
117148 return false
118149 }
119150 if number == cv1 .headNumber || number == cv2 .headNumber {
120- return cv1 .getBlockId (number ) == cv2 .getBlockId (number )
151+ return cv1 .BlockId (number ) == cv2 .BlockId (number )
121152 }
122- return cv1 .getBlockHash (number ) == cv2 .getBlockHash (number )
153+ return cv1 .BlockHash (number ) == cv2 .BlockHash (number )
123154}
124155
125156// extendNonCanonical checks whether the previously known reverse list of head
0 commit comments