@@ -20,7 +20,7 @@ use sha3::{Digest as _, Keccak256};
2020use std:: { collections:: hash_map:: Entry , sync:: Arc } ;
2121use std:: {
2222 collections:: { BTreeMap , HashMap } ,
23- sync:: RwLock ,
23+ sync:: Mutex ,
2424} ;
2525use std:: { fmt:: Debug , path:: Path } ;
2626use tracing:: { debug, error, info, instrument} ;
@@ -34,7 +34,13 @@ pub const MAX_SNAPSHOT_READS: usize = 100;
3434pub struct Store {
3535 pub engine : Arc < dyn StoreEngine > ,
3636 pub chain_config : ChainConfig ,
37- pub latest_block_header : Arc < RwLock < BlockHeader > > ,
37+ /// Keeps the latest canonical block hash
38+ /// It's wrapped in an ArcSwap to allow for cheap lock-free reads with infrequent writes
39+ /// Reading an out-of-date value is acceptable, since it's only used as:
40+ /// - a cache of the (frequently requested) header
41+ /// - a Latest tag for RPC, where a small extra delay before the newest block is expected
42+ /// - sync-related operations, which must be idempotent in order to handle reorgs
43+ latest_block_header : LatestBlockHeaderCache ,
3844}
3945
4046pub type StorageTrieNodes = Vec < ( H256 , Vec < ( Nibbles , Vec < u8 > ) > ) > ;
@@ -81,12 +87,12 @@ impl Store {
8187 EngineType :: RocksDB => Self {
8288 engine : Arc :: new ( RocksDBStore :: new ( path) ?) ,
8389 chain_config : Default :: default ( ) ,
84- latest_block_header : Arc :: new ( RwLock :: new ( BlockHeader :: default ( ) ) ) ,
90+ latest_block_header : Default :: default ( ) ,
8591 } ,
8692 EngineType :: InMemory => Self {
8793 engine : Arc :: new ( InMemoryStore :: new ( ) ) ,
8894 chain_config : Default :: default ( ) ,
89- latest_block_header : Arc :: new ( RwLock :: new ( BlockHeader :: default ( ) ) ) ,
95+ latest_block_header : Default :: default ( ) ,
9096 } ,
9197 } ;
9298
@@ -175,13 +181,9 @@ impl Store {
175181 & self ,
176182 block_number : BlockNumber ,
177183 ) -> Result < Option < BlockHeader > , StoreError > {
178- let latest = self
179- . latest_block_header
180- . read ( )
181- . map_err ( |_| StoreError :: LockError ) ?
182- . clone ( ) ;
184+ let latest = self . latest_block_header . get ( ) ;
183185 if block_number == latest. number {
184- return Ok ( Some ( latest) ) ;
186+ return Ok ( Some ( ( * latest) . clone ( ) ) ) ;
185187 }
186188 self . engine . get_block_header ( block_number)
187189 }
@@ -191,12 +193,9 @@ impl Store {
191193 block_hash : BlockHash ,
192194 ) -> Result < Option < BlockHeader > , StoreError > {
193195 {
194- let latest = self
195- . latest_block_header
196- . read ( )
197- . map_err ( |_| StoreError :: LockError ) ?;
196+ let latest = self . latest_block_header . get ( ) ;
198197 if block_hash == latest. hash ( ) {
199- return Ok ( Some ( latest. clone ( ) ) ) ;
198+ return Ok ( Some ( ( * latest) . clone ( ) ) ) ;
200199 }
201200 }
202201
@@ -223,11 +222,7 @@ impl Store {
223222 block_number : BlockNumber ,
224223 ) -> Result < Option < BlockBody > , StoreError > {
225224 // FIXME (#4353)
226- let latest = self
227- . latest_block_header
228- . read ( )
229- . map_err ( |_| StoreError :: LockError ) ?
230- . clone ( ) ;
225+ let latest = self . latest_block_header . get ( ) ;
231226 if block_number == latest. number {
232227 // The latest may not be marked as canonical yet
233228 return self . engine . get_block_body_by_hash ( latest. hash ( ) ) . await ;
@@ -634,14 +629,13 @@ impl Store {
634629 // Set chain config
635630 self . set_chain_config ( & genesis. config ) . await ?;
636631
632+ // The cache can't be empty
637633 if let Some ( number) = self . engine . get_latest_block_number ( ) . await ? {
638- * self
639- . latest_block_header
640- . write ( )
641- . map_err ( |_| StoreError :: LockError ) ? = self
634+ let latest_block_header = self
642635 . engine
643636 . get_block_header ( number) ?
644637 . ok_or_else ( || StoreError :: MissingLatestBlockNumber ) ?;
638+ self . latest_block_header . update ( latest_block_header) ;
645639 }
646640
647641 match self . engine . get_block_header ( genesis_block_number) ? {
@@ -686,10 +680,7 @@ impl Store {
686680 . engine
687681 . get_block_header ( number) ?
688682 . ok_or_else ( || StoreError :: Custom ( "latest block header is missing" . to_string ( ) ) ) ?;
689- * self
690- . latest_block_header
691- . write ( )
692- . map_err ( |_| StoreError :: LockError ) ? = latest_block_header;
683+ self . latest_block_header . update ( latest_block_header) ;
693684 Ok ( ( ) )
694685 }
695686
@@ -781,11 +772,7 @@ impl Store {
781772 }
782773
783774 pub async fn get_latest_block_number ( & self ) -> Result < BlockNumber , StoreError > {
784- Ok ( self
785- . latest_block_header
786- . read ( )
787- . map_err ( |_| StoreError :: LockError ) ?
788- . number )
775+ Ok ( self . latest_block_header . get ( ) . number )
789776 }
790777
791778 pub async fn update_pending_block_number (
@@ -804,10 +791,7 @@ impl Store {
804791 block_number : BlockNumber ,
805792 ) -> Result < Option < BlockHash > , StoreError > {
806793 {
807- let last = self
808- . latest_block_header
809- . read ( )
810- . map_err ( |_| StoreError :: LockError ) ?;
794+ let last = self . latest_block_header . get ( ) ;
811795 if last. number == block_number {
812796 return Ok ( Some ( last. hash ( ) ) ) ;
813797 }
@@ -816,12 +800,7 @@ impl Store {
816800 }
817801
818802 pub async fn get_latest_canonical_block_hash ( & self ) -> Result < Option < BlockHash > , StoreError > {
819- Ok ( Some (
820- self . latest_block_header
821- . read ( )
822- . map_err ( |_| StoreError :: LockError ) ?
823- . hash ( ) ,
824- ) )
803+ Ok ( Some ( self . latest_block_header . get ( ) . hash ( ) ) )
825804 }
826805
827806 /// Updates the canonical chain.
@@ -836,15 +815,12 @@ impl Store {
836815 safe : Option < BlockNumber > ,
837816 finalized : Option < BlockNumber > ,
838817 ) -> Result < ( ) , StoreError > {
839- // Updates first the latest_block_header
840- // to avoid nonce inconsistencies #3927.
841- * self
842- . latest_block_header
843- . write ( )
844- . map_err ( |_| StoreError :: LockError ) ? = self
818+ // Updates first the latest_block_header to avoid nonce inconsistencies #3927.
819+ let latest_block_header = self
845820 . engine
846821 . get_block_header_by_hash ( head_hash) ?
847822 . ok_or_else ( || StoreError :: MissingLatestBlockNumber ) ?;
823+ self . latest_block_header . update ( latest_block_header) ;
848824 self . engine
849825 . forkchoice_update (
850826 new_canonical_blocks,
@@ -1324,10 +1300,7 @@ impl Store {
13241300 block_number : BlockNumber ,
13251301 ) -> Result < Option < BlockHash > , StoreError > {
13261302 {
1327- let last = self
1328- . latest_block_header
1329- . read ( )
1330- . map_err ( |_| StoreError :: LockError ) ?;
1303+ let last = self . latest_block_header . get ( ) ;
13311304 if last. number == block_number {
13321305 return Ok ( Some ( last. hash ( ) ) ) ;
13331306 }
@@ -1456,6 +1429,22 @@ pub fn hash_key(key: &H256) -> Vec<u8> {
14561429 . to_vec ( )
14571430}
14581431
1432+ #[ derive( Debug , Default , Clone ) ]
1433+ struct LatestBlockHeaderCache {
1434+ current : Arc < Mutex < Arc < BlockHeader > > > ,
1435+ }
1436+
1437+ impl LatestBlockHeaderCache {
1438+ pub fn get ( & self ) -> Arc < BlockHeader > {
1439+ self . current . lock ( ) . expect ( "poisoned mutex" ) . clone ( )
1440+ }
1441+
1442+ pub fn update ( & self , header : BlockHeader ) {
1443+ let new = Arc :: new ( header) ;
1444+ * self . current . lock ( ) . expect ( "poisoned mutex" ) = new;
1445+ }
1446+ }
1447+
14591448#[ cfg( test) ]
14601449mod tests {
14611450 use bytes:: Bytes ;
0 commit comments