@@ -6,8 +6,6 @@ use super::{
66 index:: { ChainIndex , ResolveNullTipset } ,
77 tipset_tracker:: TipsetTracker ,
88} ;
9- use crate :: db:: { EthMappingsStore , EthMappingsStoreExt } ;
10- use crate :: interpreter:: { BlockMessages , VMTrace } ;
119use crate :: libp2p_bitswap:: { BitswapStoreRead , BitswapStoreReadWrite } ;
1210use crate :: message:: { ChainMessage , Message as MessageTrait , SignedMessage } ;
1311use crate :: networks:: { ChainConfig , Height } ;
@@ -23,7 +21,15 @@ use crate::{
2321 blocks:: { CachingBlockHeader , Tipset , TipsetKey , TxMeta } ,
2422 db:: HeaviestTipsetKeyProvider ,
2523} ;
24+ use crate :: {
25+ db:: { EthMappingsStore , EthMappingsStoreExt } ,
26+ rpc:: chain:: PathChange ,
27+ } ;
2628use crate :: { fil_cns, utils:: cache:: SizeTrackingLruCache } ;
29+ use crate :: {
30+ interpreter:: { BlockMessages , VMTrace } ,
31+ rpc:: chain:: PathChanges ,
32+ } ;
2733use ahash:: { HashMap , HashMapExt , HashSet } ;
2834use anyhow:: Context as _;
2935use cid:: Cid ;
@@ -47,17 +53,16 @@ pub type ChainEpochDelta = ChainEpoch;
4753
4854/// `Enum` for `pubsub` channel that defines message type variant and data
4955/// contained in message type.
50- #[ derive( Clone , Debug ) ]
51- pub enum HeadChange {
52- Apply ( Tipset ) ,
53- }
56+ pub type HeadChange = PathChange < Tipset > ;
57+
58+ pub type HeadChanges = PathChanges < Tipset > ;
5459
5560/// Stores chain data such as heaviest tipset and cached tipset info at each
5661/// epoch. This structure is thread-safe, and all caches are wrapped in a mutex
5762/// to allow a consistent `ChainStore` to be shared across tasks.
5863pub struct ChainStore < DB > {
5964 /// Publisher for head change events
60- publisher : Publisher < HeadChange > ,
65+ publisher : Publisher < HeadChanges > ,
6166
6267 /// key-value `datastore`.
6368 db : Arc < DB > ,
@@ -66,7 +71,7 @@ pub struct ChainStore<DB> {
6671 heaviest_tipset_key_provider : Arc < dyn HeaviestTipsetKeyProvider + Sync + Send > ,
6772
6873 /// Heaviest tipset cache
69- heaviest_tipset_cache : Arc < RwLock < Option < Tipset > > > ,
74+ heaviest_tipset_cache : Arc < RwLock < Tipset > > ,
7075
7176 /// Used as a cache for tipset `lookbacks`.
7277 chain_index : Arc < ChainIndex < Arc < DB > > > ,
@@ -124,14 +129,24 @@ where
124129 let ( publisher, _) = broadcast:: channel ( SINK_CAP ) ;
125130 let chain_index = Arc :: new ( ChainIndex :: new ( Arc :: clone ( & db) ) ) ;
126131 let validated_blocks = Mutex :: new ( HashSet :: default ( ) ) ;
127-
132+ let head = if let Some ( head_tsk) = heaviest_tipset_key_provider
133+ . heaviest_tipset_key ( )
134+ . context ( "failed to load head tipset key" ) ?
135+ && let Some ( head) = chain_index
136+ . load_tipset ( & head_tsk)
137+ . context ( "failed to load head tipset" ) ?
138+ {
139+ head
140+ } else {
141+ Tipset :: from ( & genesis_block_header)
142+ } ;
128143 let cs = Self {
129144 publisher,
130145 chain_index,
131146 tipset_tracker : TipsetTracker :: new ( Arc :: clone ( & db) , chain_config. clone ( ) ) ,
132147 db,
133148 heaviest_tipset_key_provider,
134- heaviest_tipset_cache : Default :: default ( ) ,
149+ heaviest_tipset_cache : Arc :: new ( RwLock :: new ( head ) ) ,
135150 genesis_block_header,
136151 validated_blocks,
137152 eth_mappings,
@@ -142,14 +157,31 @@ where
142157 }
143158
144159 /// Sets heaviest tipset
145- pub fn set_heaviest_tipset ( & self , ts : Tipset ) -> Result < ( ) , Error > {
160+ pub fn set_heaviest_tipset ( & self , head : Tipset ) -> Result < ( ) , Error > {
161+ head. key ( ) . save ( self . blockstore ( ) ) ?;
146162 self . heaviest_tipset_key_provider
147- . set_heaviest_tipset_key ( ts. key ( ) ) ?;
148- * self . heaviest_tipset_cache . write ( ) = Some ( ts. clone ( ) ) ;
149- ts. key ( ) . save ( self . blockstore ( ) ) ?;
150- if self . publisher . send ( HeadChange :: Apply ( ts) ) . is_err ( ) {
151- debug ! ( "did not publish head change, no active receivers" ) ;
163+ . set_heaviest_tipset_key ( head. key ( ) ) ?;
164+ let old_head = std:: mem:: replace ( & mut * self . heaviest_tipset_cache . write ( ) , head. clone ( ) ) ;
165+
166+ let changes = match crate :: rpc:: chain:: chain_get_path ( self , old_head. key ( ) , head. key ( ) ) {
167+ Ok ( changes) => changes,
168+ Err ( e) => {
169+ // Do not warn when the old head is genesis
170+ if old_head. epoch ( ) > 0 {
171+ warn ! ( "failed to get chain path changes: {e}" ) ;
172+ }
173+ // Fallback to single apply
174+ PathChanges {
175+ applies : vec ! [ head] ,
176+ reverts : vec ! [ ] ,
177+ }
178+ }
179+ } ;
180+
181+ if self . publisher . send ( changes) . is_err ( ) {
182+ debug ! ( "did not publish changes, no active receivers" ) ;
152183 }
184+
153185 Ok ( ( ) )
154186 }
155187
@@ -200,16 +232,7 @@ where
200232
201233 /// Returns the currently tracked heaviest tipset.
202234 pub fn heaviest_tipset ( & self ) -> Tipset {
203- if let Some ( ts) = & * self . heaviest_tipset_cache . read ( ) {
204- return ts. clone ( ) ;
205- }
206- let tsk = self
207- . heaviest_tipset_key_provider
208- . heaviest_tipset_key ( )
209- . unwrap_or_else ( |_| TipsetKey :: from ( nunny:: vec![ * self . genesis_block_header. cid( ) ] ) ) ;
210- self . chain_index
211- . load_required_tipset ( & tsk)
212- . expect ( "failed to load heaviest tipset" )
235+ self . heaviest_tipset_cache . read ( ) . clone ( )
213236 }
214237
215238 /// Returns the genesis tipset.
@@ -218,7 +241,7 @@ where
218241 }
219242
220243 /// Returns a reference to the publisher of head changes.
221- pub fn publisher ( & self ) -> & Publisher < HeadChange > {
244+ pub fn publisher ( & self ) -> & Publisher < HeadChanges > {
222245 & self . publisher
223246 }
224247
0 commit comments