Skip to content

Commit ade5603

Browse files
committed
Merge branch 'main' of github.com:decipherhub/cipherbft into feat/weighted-proposer
2 parents e4b75ba + 62efa15 commit ade5603

10 files changed

Lines changed: 478 additions & 106 deletions

File tree

crates/execution/src/database.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,25 @@ pub trait Provider: Send + Sync {
100100
/// # Returns
101101
/// A BTreeMap of all storage slots (slot -> value) for the account.
102102
fn get_all_storage(&self, address: Address) -> Result<BTreeMap<U256, U256>>;
103+
104+
/// Get the current block number (last executed block).
105+
///
106+
/// This method retrieves the persisted block number for execution engine recovery.
107+
/// Returns `None` if no block has been executed yet (first startup).
108+
///
109+
/// # Returns
110+
/// * `Ok(Some(block_number))` - The last executed block number
111+
/// * `Ok(None)` - No block has been executed yet
112+
fn get_current_block(&self) -> Result<Option<u64>>;
113+
114+
/// Set the current block number (last executed block).
115+
///
116+
/// This method persists the block number after each block execution to enable
117+
/// proper recovery after node restart.
118+
///
119+
/// # Arguments
120+
/// * `block_number` - The block number to persist
121+
fn set_current_block(&self, block_number: u64) -> Result<()>;
103122
}
104123

105124
/// In-memory provider for testing and development.
@@ -112,6 +131,8 @@ pub struct InMemoryProvider {
112131
code: Arc<DashMap<B256, Bytecode>>,
113132
storage: Arc<DashMap<(Address, U256), U256>>,
114133
block_hashes: Arc<DashMap<u64, B256>>,
134+
/// Current block number (last executed block). Uses RwLock for atomic u64 access.
135+
current_block: Arc<RwLock<Option<u64>>>,
115136
}
116137

117138
impl InMemoryProvider {
@@ -122,6 +143,7 @@ impl InMemoryProvider {
122143
code: Arc::new(DashMap::new()),
123144
storage: Arc::new(DashMap::new()),
124145
block_hashes: Arc::new(DashMap::new()),
146+
current_block: Arc::new(RwLock::new(None)),
125147
}
126148
}
127149

@@ -204,6 +226,15 @@ impl Provider for InMemoryProvider {
204226
}
205227
Ok(result)
206228
}
229+
230+
fn get_current_block(&self) -> Result<Option<u64>> {
231+
Ok(*self.current_block.read())
232+
}
233+
234+
fn set_current_block(&self, block_number: u64) -> Result<()> {
235+
*self.current_block.write() = Some(block_number);
236+
Ok(())
237+
}
207238
}
208239

209240
/// Blanket implementation of Provider for Arc<P> where P: Provider.
@@ -254,6 +285,14 @@ impl<P: Provider> Provider for Arc<P> {
254285
fn get_all_storage(&self, address: Address) -> Result<BTreeMap<U256, U256>> {
255286
(**self).get_all_storage(address)
256287
}
288+
289+
fn get_current_block(&self) -> Result<Option<u64>> {
290+
(**self).get_current_block()
291+
}
292+
293+
fn set_current_block(&self, block_number: u64) -> Result<()> {
294+
(**self).set_current_block(block_number)
295+
}
257296
}
258297

259298
/// CipherBFT database implementation that implements revm's Database trait.
@@ -779,6 +818,22 @@ mod tests {
779818
// Verify cache contains the entry
780819
assert!(db.cache_accounts.write().contains(&addr));
781820
}
821+
822+
#[test]
823+
fn test_in_memory_provider_current_block() {
824+
let provider = InMemoryProvider::new();
825+
826+
// Initially no current block
827+
assert!(provider.get_current_block().unwrap().is_none());
828+
829+
// Set current block
830+
provider.set_current_block(100).unwrap();
831+
assert_eq!(provider.get_current_block().unwrap(), Some(100));
832+
833+
// Update current block
834+
provider.set_current_block(200).unwrap();
835+
assert_eq!(provider.get_current_block().unwrap(), Some(200));
836+
}
782837
}
783838

784839
// =============================================================================
@@ -798,6 +853,7 @@ pub mod mdbx_provider {
798853
///
799854
/// This provider wraps `MdbxEvmStore` from the storage layer and implements
800855
/// the `Provider` trait to integrate with the execution layer.
856+
#[derive(Clone)]
801857
pub struct MdbxProvider {
802858
store: MdbxEvmStore,
803859
}
@@ -923,6 +979,18 @@ pub mod mdbx_provider {
923979
})
924980
.map_err(|e| DatabaseError::mdbx(e.to_string()).into())
925981
}
982+
983+
fn get_current_block(&self) -> Result<Option<u64>> {
984+
self.store
985+
.get_current_block()
986+
.map_err(|e| DatabaseError::mdbx(e.to_string()).into())
987+
}
988+
989+
fn set_current_block(&self, block_number: u64) -> Result<()> {
990+
self.store
991+
.set_current_block(block_number)
992+
.map_err(|e| DatabaseError::mdbx(e.to_string()).into())
993+
}
926994
}
927995

928996
#[cfg(test)]

crates/execution/src/engine.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ impl<P: Provider + Clone> ExecutionEngine<P> {
166166
/// staking precompile with the validator set from the genesis file, ensuring
167167
/// the validator state is correctly populated on node startup.
168168
///
169+
/// The engine will attempt to restore `current_block` from persistent storage
170+
/// to survive node restarts. If no persisted state exists (first startup),
171+
/// it defaults to 0.
172+
///
169173
/// # Arguments
170174
/// * `chain_config` - Chain configuration parameters
171175
/// * `provider` - Storage provider (factory pattern)
@@ -185,6 +189,29 @@ impl<P: Provider + Clone> ExecutionEngine<P> {
185189
chain_config.base_fee_per_gas,
186190
);
187191

192+
// Restore current_block from persistent storage if available
193+
// This is critical for correct block validation after node restart
194+
let current_block = match provider.get_current_block() {
195+
Ok(Some(block)) => {
196+
tracing::info!(
197+
current_block = block,
198+
"Restored current block from persistent storage"
199+
);
200+
block
201+
}
202+
Ok(None) => {
203+
tracing::info!("No persisted current block found, starting from 0");
204+
0
205+
}
206+
Err(e) => {
207+
tracing::warn!(
208+
error = %e,
209+
"Failed to read current block from storage, starting from 0"
210+
);
211+
0
212+
}
213+
};
214+
188215
let database = CipherBftDatabase::new(provider.clone());
189216
let state_manager = StateManager::new(provider);
190217

@@ -209,7 +236,7 @@ impl<P: Provider + Clone> ExecutionEngine<P> {
209236
evm_config,
210237
staking_precompile,
211238
block_hashes: RwLock::new(lru::LruCache::new(BLOCK_HASH_CACHE_SIZE)),
212-
current_block: 0,
239+
current_block,
213240
}
214241
}
215242

@@ -505,9 +532,24 @@ impl<P: Provider + Clone> ExecutionLayer for ExecutionEngine<P> {
505532
.unwrap_or(B256::ZERO)
506533
};
507534

508-
// Update current block number
535+
// Update current block number and persist to storage
509536
self.current_block = input.block_number;
510537

538+
// Persist current_block to storage for recovery after restart
539+
if let Err(e) = self
540+
.database
541+
.provider()
542+
.set_current_block(input.block_number)
543+
{
544+
tracing::error!(
545+
block_number = input.block_number,
546+
error = %e,
547+
"Failed to persist current block number"
548+
);
549+
// Continue execution - we don't want to fail the block for persistence errors
550+
// The worst case is having to re-execute some blocks after restart
551+
}
552+
511553
tracing::info!(
512554
block_number = input.block_number,
513555
gas_used,

crates/execution/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ pub mod types;
6565

6666
// Re-export main types for convenience
6767
pub use bridge::{BatchFetcher, ExecutionBridge};
68+
#[cfg(feature = "mdbx")]
69+
pub use database::MdbxProvider;
6870
pub use database::{Account, CipherBftDatabase, InMemoryProvider, Provider};
6971
pub use engine::{ExecutionEngine, ExecutionLayer as ExecutionLayerTrait};
7072
pub use error::{DatabaseError, ExecutionError, Result};

crates/node/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ cipherbft-types = { path = "../types" }
1616
cipherbft-crypto = { path = "../crypto" }
1717
cipherbft-data-chain = { path = "../data-chain" }
1818
cipherbft-storage = { path = "../storage", features = ["mdbx"] }
19-
cipherbft-execution = { path = "../execution" }
19+
cipherbft-execution = { path = "../execution", features = ["mdbx"] }
2020
cipherbft-consensus = { path = "../consensus", features = ["malachite"] }
2121
cipherbft-rpc = { path = "../rpc" }
2222
cipherbft-mempool = { path = "../mempool" }

0 commit comments

Comments
 (0)