feat(storage, tree): respect Transaction Lookup pruning in the blockchain tree (#4410)

This commit is contained in:
Alexey Shekhirin
2023-09-01 13:51:34 +01:00
committed by GitHub
parent 39a6fa1b57
commit e66e3e3556
29 changed files with 118 additions and 49 deletions

1
Cargo.lock generated
View File

@ -5817,6 +5817,7 @@ dependencies = [
name = "reth-provider"
version = "0.1.0-alpha.8"
dependencies = [
"assert_matches",
"auto_impl",
"derive_more",
"itertools 0.11.0",

View File

@ -156,3 +156,4 @@ c-kzg = { git = "https://github.com/ethereum/c-kzg-4844" }
### misc-testing
proptest = "1.0"
arbitrary = "1.1"
assert_matches = "1.5.0"

View File

@ -193,7 +193,7 @@ impl Command {
let provider_rw = factory.provider_rw()?;
// Insert block, state and hashes
provider_rw.insert_block(block.clone(), None)?;
provider_rw.insert_block(block.clone(), None, None)?;
block_state.write_to_db(provider_rw.tx_ref(), block.number)?;
let storage_lists = provider_rw.changed_storages_with_range(block.number..=block.number)?;
let storages = provider_rw.plainstate_storages(storage_lists)?;

View File

@ -185,7 +185,7 @@ impl Command {
continue
}
};
provider_rw.insert_block(sealed_block.block, Some(sealed_block.senders))?;
provider_rw.insert_block(sealed_block.block, Some(sealed_block.senders), None)?;
}
// Check if any of hashing or merkle stages aren't on the same block number as

View File

@ -267,6 +267,9 @@ impl<Ext: RethCliExt> NodeCommand<Ext> {
let metrics_listener = MetricsListener::new(metrics_rx);
ctx.task_executor.spawn_critical("metrics listener task", metrics_listener);
let prune_config =
self.pruning.prune_config(Arc::clone(&self.chain))?.or(config.prune.clone());
// configure blockchain tree
let tree_externals = TreeExternals::new(
db.clone(),
@ -284,6 +287,7 @@ impl<Ext: RethCliExt> NodeCommand<Ext> {
tree_externals,
canon_state_notification_sender.clone(),
tree_config,
prune_config.clone().map(|config| config.parts),
)?
.with_sync_metrics_tx(metrics_tx.clone()),
);
@ -365,9 +369,6 @@ impl<Ext: RethCliExt> NodeCommand<Ext> {
None
};
let prune_config =
self.pruning.prune_config(Arc::clone(&self.chain))?.or(config.prune.clone());
// Configure the pipeline
let (mut pipeline, client) = if self.dev.dev {
info!(target: "reth::cli", "Starting Reth in dev mode");

View File

@ -40,7 +40,7 @@ reth-interfaces = { workspace = true, features = ["test-utils"] }
reth-primitives = { workspace = true , features = ["test-utils"] }
reth-provider = { workspace = true, features = ["test-utils"] }
parking_lot.workspace = true
assert_matches = "1.5"
assert_matches.workspace = true
tokio = { workspace = true, features = ["macros", "sync"] }
[features]

View File

@ -16,7 +16,7 @@ use reth_interfaces::{
Error,
};
use reth_primitives::{
BlockHash, BlockNumHash, BlockNumber, ForkBlock, Hardfork, Receipt, SealedBlock,
BlockHash, BlockNumHash, BlockNumber, ForkBlock, Hardfork, PruneModes, Receipt, SealedBlock,
SealedBlockWithSenders, SealedHeader, U256,
};
use reth_provider::{
@ -93,6 +93,7 @@ pub struct BlockchainTree<DB: Database, C: Consensus, EF: ExecutorFactory> {
metrics: TreeMetrics,
/// Metrics for sync stages.
sync_metrics_tx: Option<MetricEventsSender>,
prune_modes: Option<PruneModes>,
}
/// A container that wraps chains and block indices to allow searching for block hashes across all
@ -110,6 +111,7 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
externals: TreeExternals<DB, C, EF>,
canon_state_notification_sender: CanonStateNotificationSender,
config: BlockchainTreeConfig,
prune_modes: Option<PruneModes>,
) -> Result<Self, Error> {
let max_reorg_depth = config.max_reorg_depth();
@ -145,6 +147,7 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
canon_state_notification_sender,
metrics: Default::default(),
sync_metrics_tx: None,
prune_modes,
})
}
@ -1048,7 +1051,11 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
let (blocks, state) = chain.into_inner();
provider
.append_blocks_with_post_state(blocks.into_blocks().collect(), state)
.append_blocks_with_post_state(
blocks.into_blocks().collect(),
state,
self.prune_modes.as_ref(),
)
.map_err(|e| BlockExecutionError::CanonicalCommit { inner: e.to_string() })?;
provider.commit()?;
@ -1173,7 +1180,7 @@ mod tests {
let factory = ProviderFactory::new(&db, MAINNET.clone());
let provider = factory.provider_rw().unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
// insert first 10 blocks
for i in 0..10 {
@ -1279,7 +1286,7 @@ mod tests {
let config = BlockchainTreeConfig::new(1, 2, 3, 2);
let (sender, mut canon_notif) = tokio::sync::broadcast::channel(10);
let mut tree =
BlockchainTree::new(externals, sender, config).expect("failed to create tree");
BlockchainTree::new(externals, sender, config, None).expect("failed to create tree");
// genesis block 10 is already canonical
assert!(tree.make_canonical(&H256::zero()).is_ok());

View File

@ -46,4 +46,4 @@ reth-tracing = { path = "../../tracing" }
reth-revm = { path = "../../revm" }
reth-downloaders = { path = "../../net/downloaders" }
assert_matches = "1.5"
assert_matches.workspace = true

View File

@ -1880,7 +1880,9 @@ mod tests {
BeaconForkChoiceUpdateError,
};
use assert_matches::assert_matches;
use reth_primitives::{stage::StageCheckpoint, ChainSpec, ChainSpecBuilder, H256, MAINNET};
use reth_primitives::{
stage::StageCheckpoint, ChainSpec, ChainSpecBuilder, PruneModes, H256, MAINNET,
};
use reth_provider::{BlockWriter, ProviderFactory};
use reth_rpc_types::engine::{
ExecutionPayloadV1, ForkchoiceState, ForkchoiceUpdated, PayloadStatus,
@ -2056,7 +2058,7 @@ mod tests {
let factory = ProviderFactory::new(db, chain);
let provider = factory.provider_rw().unwrap();
blocks
.try_for_each(|b| provider.insert_block(b.clone(), None).map(|_| ()))
.try_for_each(|b| provider.insert_block(b.clone(), None, None).map(|_| ()))
.expect("failed to insert");
provider.commit().unwrap();
}

View File

@ -463,7 +463,7 @@ where
let config = BlockchainTreeConfig::new(1, 2, 3, 2);
let (canon_state_notification_sender, _) = tokio::sync::broadcast::channel(3);
let tree = ShareableBlockchainTree::new(
BlockchainTree::new(externals, canon_state_notification_sender, config)
BlockchainTree::new(externals, canon_state_notification_sender, config, None)
.expect("failed to create tree"),
);
let shareable_db = ProviderFactory::new(db.clone(), self.base_config.chain_spec.clone());

View File

@ -16,5 +16,5 @@ reth-provider.workspace = true
[dev-dependencies]
reth-interfaces = { workspace = true, features = ["test-utils"] }
reth-provider = { workspace = true, features = ["test-utils"] }
assert_matches = "1.5.0"
assert_matches.workspace = true
mockall = "0.11.3"

View File

@ -42,7 +42,7 @@ reth-db = { path = "../../storage/db", features = ["test-utils"] }
reth-interfaces = { workspace = true, features = ["test-utils"] }
reth-tracing = { path = "../../tracing" }
assert_matches = "1.5.0"
assert_matches.workspace = true
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
reth-rlp.workspace = true
itertools.workspace = true

View File

@ -85,7 +85,7 @@ revm-primitives = { workspace = true, features = ["arbitrary"] }
arbitrary = { workspace = true, features = ["derive"] }
proptest.workspace = true
proptest-derive = "0.3"
assert_matches = "1.5.0"
assert_matches.workspace = true
toml = "0.7.4"
# necessary so we don't hit a "undeclared 'std'":

View File

@ -49,6 +49,11 @@ impl PruneMode {
PruneMode::Before(n) => *n > block,
}
}
/// Returns true if the prune mode is [`PruneMode::Full`].
pub fn is_full(&self) -> bool {
matches!(self, Self::Full)
}
}
#[cfg(test)]

View File

@ -34,4 +34,4 @@ reth-stages = { path = "../stages", features = ["test-utils"] }
# misc
assert_matches = "1.5.0"
assert_matches.workspace = true

View File

@ -34,4 +34,4 @@ reth-rlp.workspace = true
reth-interfaces = { workspace = true, features = ["test-utils"] }
reth-provider = { workspace = true, features = ["test-utils"] }
reth-payload-builder = { workspace = true, features = ["test-utils"] }
assert_matches = "1.5.0"
assert_matches.workspace = true

View File

@ -70,6 +70,6 @@ futures.workspace = true
[dev-dependencies]
jsonrpsee = { workspace = true, features = ["client"] }
assert_matches = "1.5.0"
assert_matches.workspace = true
tempfile = "3.5.0"
reth-interfaces = { workspace = true, features = ["test-utils"] }

View File

@ -61,7 +61,7 @@ reth-trie = { path = "../trie", features = ["test-utils"] }
itertools.workspace = true
tokio = { workspace = true, features = ["rt", "sync", "macros"] }
assert_matches = "1.5.0"
assert_matches.workspace = true
rand.workspace = true
paste = "1.0"

View File

@ -526,8 +526,8 @@ mod tests {
let genesis = SealedBlock::decode(&mut genesis_rlp).unwrap();
let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(block.clone(), None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
provider.insert_block(block.clone(), None, None).unwrap();
provider.commit().unwrap();
let previous_stage_checkpoint = ExecutionCheckpoint {
@ -562,8 +562,8 @@ mod tests {
let genesis = SealedBlock::decode(&mut genesis_rlp).unwrap();
let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(block.clone(), None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
provider.insert_block(block.clone(), None, None).unwrap();
provider.commit().unwrap();
let previous_stage_checkpoint = ExecutionCheckpoint {
@ -598,8 +598,8 @@ mod tests {
let genesis = SealedBlock::decode(&mut genesis_rlp).unwrap();
let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(block.clone(), None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
provider.insert_block(block.clone(), None, None).unwrap();
provider.commit().unwrap();
let previous_checkpoint = StageCheckpoint { block_number: 1, stage_checkpoint: None };
@ -632,8 +632,8 @@ mod tests {
let genesis = SealedBlock::decode(&mut genesis_rlp).unwrap();
let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(block.clone(), None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
provider.insert_block(block.clone(), None, None).unwrap();
provider.commit().unwrap();
// insert pre state
@ -742,8 +742,8 @@ mod tests {
let genesis = SealedBlock::decode(&mut genesis_rlp).unwrap();
let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(block.clone(), None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
provider.insert_block(block.clone(), None, None).unwrap();
provider.commit().unwrap();
// variables
@ -820,8 +820,8 @@ mod tests {
let genesis = SealedBlock::decode(&mut genesis_rlp).unwrap();
let mut block_rlp = hex!("f9025ff901f7a0c86e8cc0310ae7c531c758678ddbfd16fc51c8cef8cec650b032de9869e8b94fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa050554882fbbda2c2fd93fdc466db9946ea262a67f7a76cc169e714f105ab583da00967f09ef1dfed20c0eacfaa94d5cd4002eda3242ac47eae68972d07b106d192a0e3c8b47fbfc94667ef4cceb17e5cc21e3b1eebd442cebb27f07562b33836290db90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001830f42408238108203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f862f860800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d8780801ba072ed817487b84ba367d15d2f039b5fc5f087d0a8882fbdf73e8cb49357e1ce30a0403d800545b8fc544f92ce8124e2255f8c3c6af93f28243a120585d4c4c6a2a3c0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(block.clone(), None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
provider.insert_block(block.clone(), None, None).unwrap();
provider.commit().unwrap();
// variables

View File

@ -95,7 +95,7 @@ impl AccountHashingStage {
let blocks = random_block_range(&mut rng, opts.blocks.clone(), H256::zero(), opts.txs);
for block in blocks {
provider.insert_block(block, None).unwrap();
provider.insert_block(block, None, None).unwrap();
}
let mut accounts = random_eoa_account_range(&mut rng, opts.accounts);
{

View File

@ -81,8 +81,8 @@ mod tests {
let genesis = SealedBlock::decode(&mut genesis_rlp).unwrap();
let mut block_rlp = hex!("f90262f901f9a075c371ba45999d87f4542326910a11af515897aebce5265d3f6acd1f1161f82fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa098f2dcd87c8ae4083e7017a05456c14eea4b1db2032126e27b3b1563d57d7cc0a08151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcba03f4e5c2ec5b2170b711d97ee755c160457bb58d8daa338e835ec02ae6860bbabb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018502540be40082a8798203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f863f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509bc0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
provider.insert_block(genesis, None).unwrap();
provider.insert_block(block.clone(), None).unwrap();
provider.insert_block(genesis, None, None).unwrap();
provider.insert_block(block.clone(), None, None).unwrap();
// Fill with bogus blocks to respect PruneMode distance.
let mut head = block.hash;
@ -90,7 +90,7 @@ mod tests {
for block_number in 2..=tip {
let nblock = random_block(&mut rng, block_number, Some(head), Some(0), Some(0));
head = nblock.hash;
provider.insert_block(nblock, None).unwrap();
provider.insert_block(nblock, None, None).unwrap();
}
provider.commit().unwrap();

View File

@ -76,7 +76,7 @@ serde_json.workspace = true
paste = "1.0"
assert_matches = "1.5.0"
assert_matches.workspace = true
[build-dependencies]
vergen = { version = "8.0.0", features = ["git", "gitcl"] }

View File

@ -40,6 +40,7 @@ reth-rlp.workspace = true
reth-trie = { path = "../../trie", features = ["test-utils"] }
parking_lot.workspace = true
tempfile = "3.3"
assert_matches.workspace = true
[features]
test-utils = ["reth-rlp"]

View File

@ -393,12 +393,16 @@ impl<DB: Database> PruneCheckpointReader for ProviderFactory<DB> {
#[cfg(test)]
mod tests {
use super::ProviderFactory;
use crate::{BlockHashReader, BlockNumReader};
use crate::{BlockHashReader, BlockNumReader, BlockWriter, TransactionsProvider};
use assert_matches::assert_matches;
use reth_db::{
test_utils::{create_test_rw_db, ERROR_TEMPDIR},
DatabaseEnv,
};
use reth_primitives::{ChainSpecBuilder, H256};
use reth_primitives::{
hex_literal::hex, ChainSpecBuilder, PruneMode, PruneModes, SealedBlock, H256,
};
use reth_rlp::Decodable;
use std::sync::Arc;
#[test]
@ -449,4 +453,36 @@ mod tests {
provider_rw.block_hash(0).unwrap();
provider.block_hash(0).unwrap();
}
#[test]
fn insert_block_with_prune_modes() {
let chain_spec = ChainSpecBuilder::mainnet().build();
let db = create_test_rw_db();
let factory = ProviderFactory::new(db, Arc::new(chain_spec));
let mut block_rlp = hex!("f9025ff901f7a0c86e8cc0310ae7c531c758678ddbfd16fc51c8cef8cec650b032de9869e8b94fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa050554882fbbda2c2fd93fdc466db9946ea262a67f7a76cc169e714f105ab583da00967f09ef1dfed20c0eacfaa94d5cd4002eda3242ac47eae68972d07b106d192a0e3c8b47fbfc94667ef4cceb17e5cc21e3b1eebd442cebb27f07562b33836290db90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001830f42408238108203e800a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f862f860800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d8780801ba072ed817487b84ba367d15d2f039b5fc5f087d0a8882fbdf73e8cb49357e1ce30a0403d800545b8fc544f92ce8124e2255f8c3c6af93f28243a120585d4c4c6a2a3c0").as_slice();
let block = SealedBlock::decode(&mut block_rlp).unwrap();
{
let provider = factory.provider_rw().unwrap();
assert_matches!(provider.insert_block(block.clone(), None, None), Ok(_));
assert_matches!(provider.transaction_id(block.body[0].hash), Ok(Some(0)));
}
{
let provider = factory.provider_rw().unwrap();
assert_matches!(
provider.insert_block(
block.clone(),
None,
Some(&PruneModes {
transaction_lookup: Some(PruneMode::Full),
..PruneModes::none()
})
),
Ok(_)
);
assert_matches!(provider.transaction_id(block.body[0].hash), Ok(None));
}
}
}

View File

@ -31,10 +31,10 @@ use reth_primitives::{
stage::{StageCheckpoint, StageId},
trie::Nibbles,
Account, Address, Block, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithSenders,
ChainInfo, ChainSpec, Hardfork, Head, Header, PruneCheckpoint, PrunePart, Receipt, SealedBlock,
SealedBlockWithSenders, SealedHeader, StorageEntry, TransactionMeta, TransactionSigned,
TransactionSignedEcRecovered, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, H256,
U256,
ChainInfo, ChainSpec, Hardfork, Head, Header, PruneCheckpoint, PruneModes, PrunePart, Receipt,
SealedBlock, SealedBlockWithSenders, SealedHeader, StorageEntry, TransactionMeta,
TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxHash, TxNumber,
Withdrawal, H256, U256,
};
use reth_revm_primitives::{
config::revm_spec,
@ -1871,6 +1871,7 @@ impl<'this, TX: DbTxMut<'this> + DbTx<'this>> BlockWriter for DatabaseProvider<'
&self,
block: SealedBlock,
senders: Option<Vec<Address>>,
prune_modes: Option<&PruneModes>,
) -> Result<StoredBlockBodyIndices> {
let block_number = block.number;
self.tx.put::<tables::CanonicalHeaders>(block.number, block.hash())?;
@ -1922,7 +1923,14 @@ impl<'this, TX: DbTxMut<'this> + DbTx<'this>> BlockWriter for DatabaseProvider<'
let hash = transaction.hash();
self.tx.put::<tables::TxSenders>(next_tx_num, sender)?;
self.tx.put::<tables::Transactions>(next_tx_num, transaction.into())?;
self.tx.put::<tables::TxHashNumber>(hash, next_tx_num)?;
if prune_modes
.and_then(|modes| modes.transaction_lookup)
.filter(|prune_mode| prune_mode.is_full())
.is_none()
{
self.tx.put::<tables::TxHashNumber>(hash, next_tx_num)?;
}
next_tx_num += 1;
}
@ -1949,6 +1957,7 @@ impl<'this, TX: DbTxMut<'this> + DbTx<'this>> BlockWriter for DatabaseProvider<'
&self,
blocks: Vec<SealedBlockWithSenders>,
state: PostState,
prune_modes: Option<&PruneModes>,
) -> Result<()> {
if blocks.is_empty() {
return Ok(())
@ -1966,7 +1975,7 @@ impl<'this, TX: DbTxMut<'this> + DbTx<'this>> BlockWriter for DatabaseProvider<'
// Insert the blocks
for block in blocks {
let (block, senders) = block.into_components();
self.insert_block(block, Some(senders))?;
self.insert_block(block, Some(senders), prune_modes)?;
}
// Write state and changesets to the database.

View File

@ -7,7 +7,8 @@ use reth_db::models::StoredBlockBodyIndices;
use reth_interfaces::Result;
use reth_primitives::{
Address, Block, BlockHashOrNumber, BlockId, BlockNumber, BlockNumberOrTag, BlockWithSenders,
ChainSpec, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, H256,
ChainSpec, Header, PruneModes, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader,
H256,
};
use std::ops::RangeInclusive;
@ -242,6 +243,7 @@ pub trait BlockWriter: Send + Sync {
&self,
block: SealedBlock,
senders: Option<Vec<Address>>,
prune_modes: Option<&PruneModes>,
) -> Result<StoredBlockBodyIndices>;
/// Appends a batch of sealed blocks to the blockchain, including sender information, and
@ -254,6 +256,7 @@ pub trait BlockWriter: Send + Sync {
///
/// - `blocks`: Vector of `SealedBlockWithSenders` instances to append.
/// - `state`: Post-state information to update after appending.
/// - `prune_modes`: Optional pruning configuration.
///
/// # Returns
///
@ -263,5 +266,6 @@ pub trait BlockWriter: Send + Sync {
&self,
blocks: Vec<SealedBlockWithSenders>,
state: PostState,
prune_modes: Option<&PruneModes>,
) -> Result<()>;
}

View File

@ -55,7 +55,7 @@ paste = "1.0"
rand = "0.8"
proptest.workspace = true
criterion = "0.5"
assert_matches = "1.5"
assert_matches.workspace = true
[features]
default = ["serde"]

View File

@ -48,6 +48,7 @@ async fn main() -> eyre::Result<()> {
externals,
canon_state_notification_sender,
tree_config,
None,
)?);
BlockchainProvider::new(factory, tree)?

View File

@ -81,6 +81,7 @@ impl Case for BlockchainTestCase {
provider.insert_block(
SealedBlock::new(case.genesis_block_header.clone().into(), BlockBody::default()),
None,
None,
)?;
case.pre.write_to_db(provider.tx_ref())?;
@ -88,7 +89,7 @@ impl Case for BlockchainTestCase {
for block in case.blocks.iter() {
let decoded = SealedBlock::decode(&mut block.rlp.as_ref())?;
last_block = Some(decoded.number);
provider.insert_block(decoded, None)?;
provider.insert_block(decoded, None, None)?;
}
// Call execution stage