Skip to content

Commit 3ad7fe0

Browse files
authored
feat: only bridge newly created contracts (#1559)
1 parent 47fdf1e commit 3ad7fe0

File tree

4 files changed

+59
-35
lines changed

4 files changed

+59
-35
lines changed

portal-bridge/src/bridge/state.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use ethportal_api::{
1111
ContentValue, Enr, OverlayContentKey, StateContentKey, StateContentValue,
1212
StateNetworkApiClient,
1313
};
14-
use revm::Database;
1514
use revm_primitives::{keccak256, Bytecode, SpecId, B256};
1615
use tokio::{
1716
sync::{OwnedSemaphorePermit, Semaphore},
@@ -104,7 +103,7 @@ impl StateBridge {
104103

105104
// Enable contract storage changes caching required for gossiping the storage trie
106105
let state_config = StateConfig {
107-
cache_contract_storage_changes: true,
106+
cache_contract_changes: true,
108107
block_to_trace: BlockToTrace::None,
109108
};
110109
let mut trin_execution = TrinExecution::new(temp_directory.path(), state_config).await?;
@@ -115,7 +114,7 @@ impl StateBridge {
115114
.process_range_of_blocks(start_block - 1, None)
116115
.await?;
117116
// flush the database cache
118-
trin_execution.database.storage_cache.lock().clear();
117+
trin_execution.database.clear_contract_cache();
119118
}
120119

121120
info!("Gossiping state data from block {start_block} to {end_block} (inclusively)");
@@ -194,17 +193,21 @@ impl StateBridge {
194193
// if the code_hash is empty then then don't try to gossip the contract bytecode
195194
if account.code_hash != keccak256([]) {
196195
// gossip contract bytecode
197-
let code = trin_execution.database.code_by_hash(account.code_hash)?;
198-
self.gossip_contract_bytecode(
199-
address_hash,
200-
&account_proof,
201-
block_hash,
202-
account.code_hash,
203-
code,
204-
content_idx,
205-
)
206-
.await?;
207-
content_idx += 1;
196+
if let Some(code) = trin_execution
197+
.database
198+
.get_newly_created_contract(account.code_hash)
199+
{
200+
self.gossip_contract_bytecode(
201+
address_hash,
202+
&account_proof,
203+
block_hash,
204+
account.code_hash,
205+
code,
206+
content_idx,
207+
)
208+
.await?;
209+
content_idx += 1;
210+
}
208211
}
209212

210213
// gossip contract storage
@@ -227,8 +230,8 @@ impl StateBridge {
227230
}
228231

229232
// flush the database cache
230-
// This is used for gossiping storage trie diffs
231-
trin_execution.database.storage_cache.lock().clear();
233+
// This is used for gossiping storage trie diffs and newly created contracts
234+
trin_execution.database.clear_contract_cache();
232235

233236
Ok(())
234237
}

trin-execution/src/config.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ use crate::{cli::TrinExecutionConfig, types::block_to_trace::BlockToTrace};
33
#[derive(Debug, Clone)]
44
pub struct StateConfig {
55
/// This flag when enabled will storage all the trie keys from block execution in a cache, this
6-
/// is needed for gossiping the storage trie's changes.
7-
pub cache_contract_storage_changes: bool,
6+
/// is needed for gossiping the storage trie's changes. It is also needed for gossiping newly
7+
/// created contracts.
8+
pub cache_contract_changes: bool,
89
pub block_to_trace: BlockToTrace,
910
}
1011

1112
#[allow(clippy::derivable_impls)]
1213
impl Default for StateConfig {
1314
fn default() -> Self {
1415
Self {
15-
cache_contract_storage_changes: false,
16+
cache_contract_changes: false,
1617
block_to_trace: BlockToTrace::None,
1718
}
1819
}
@@ -21,7 +22,7 @@ impl Default for StateConfig {
2122
impl From<TrinExecutionConfig> for StateConfig {
2223
fn from(cli_config: TrinExecutionConfig) -> Self {
2324
Self {
24-
cache_contract_storage_changes: false,
25+
cache_contract_changes: false,
2526
block_to_trace: cli_config.block_to_trace,
2627
}
2728
}

trin-execution/src/storage/evm_db.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ fn start_processing_timer(name: &str) -> HistogramTimer {
3939
pub struct EvmDB {
4040
/// State config
4141
pub config: StateConfig,
42-
/// Storage cache for the accounts used optionally for gossiping, keyed by address hash.
43-
pub storage_cache: Arc<Mutex<FbHashMap<32, HashSet<B256>>>>,
42+
/// Storage cache for the accounts required for gossiping stat diffs, keyed by address hash.
43+
storage_cache: Arc<Mutex<FbHashMap<32, HashSet<B256>>>>,
44+
/// Cache for newly created contracts required for gossiping stat diffs, keyed by code hash.
45+
newly_created_contracts: Arc<Mutex<FbHashMap<32, Bytecode>>>,
4446
/// The underlying database.
4547
pub db: Arc<RocksDB>,
4648
/// To get proofs and to verify trie state.
@@ -68,9 +70,11 @@ impl EvmDB {
6870
));
6971

7072
let storage_cache = Arc::new(Mutex::new(FbHashMap::default()));
73+
let newly_created_contracts = Arc::new(Mutex::new(FbHashMap::default()));
7174
Ok(Self {
7275
config,
7376
storage_cache,
77+
newly_created_contracts,
7478
db,
7579
trie,
7680
})
@@ -102,6 +106,15 @@ impl EvmDB {
102106
trie_diff
103107
}
104108

109+
pub fn get_newly_created_contract(&self, code_hash: B256) -> Option<Bytecode> {
110+
self.newly_created_contracts.lock().get(&code_hash).cloned()
111+
}
112+
113+
pub fn clear_contract_cache(&self) {
114+
self.storage_cache.lock().clear();
115+
self.newly_created_contracts.lock().clear();
116+
}
117+
105118
fn commit_account(
106119
&mut self,
107120
address_hash: B256,
@@ -228,7 +241,7 @@ impl EvmDB {
228241
trie_diff,
229242
} = trie.root_hash_with_changed_nodes()?;
230243

231-
if self.config.cache_contract_storage_changes {
244+
if self.config.cache_contract_changes {
232245
let mut storage_cache_guard = self.storage_cache.lock();
233246
let account_storage_cache = storage_cache_guard.entry(address_hash).or_default();
234247
for key in trie_diff.keys() {
@@ -295,6 +308,12 @@ impl EvmDB {
295308
// TODO: Delete contract code if no accounts point to it: https://github.com/ethereum/trin/issues/1428
296309
let timer = start_commit_timer("contract:committing_contracts_total");
297310
for (hash, bytecode) in plain_state.contracts {
311+
// Cache contract code for gossiping if flag is set
312+
if self.config.cache_contract_changes {
313+
self.newly_created_contracts
314+
.lock()
315+
.insert(hash, bytecode.clone());
316+
}
298317
let timer = start_commit_timer("committing_contract");
299318
self.db
300319
.put(hash, bytecode.original_bytes().as_ref())

trin-execution/tests/content_generation.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use ethportal_api::{
88
},
99
ContentValue, OverlayContentKey, StateContentKey, StateContentValue,
1010
};
11-
use revm::DatabaseRef;
1211
use revm_primitives::keccak256;
1312
use tracing::info;
1413
use tracing_test::traced_test;
@@ -96,7 +95,7 @@ async fn test_we_can_generate_content_key_values_up_to_x() -> Result<()> {
9695
let mut trin_execution = TrinExecution::new(
9796
temp_directory.path(),
9897
StateConfig {
99-
cache_contract_storage_changes: true,
98+
cache_contract_changes: true,
10099
block_to_trace: BlockToTrace::None,
101100
},
102101
)
@@ -158,16 +157,18 @@ async fn test_we_can_generate_content_key_values_up_to_x() -> Result<()> {
158157

159158
// check contract code content key/value
160159
if account.code_hash != keccak256([]) {
161-
let code = trin_execution
160+
if let Some(code) = trin_execution
162161
.database
163-
.code_by_hash_ref(account.code_hash)?;
164-
165-
let content_key = create_contract_content_key(address_hash, account.code_hash)
166-
.expect("Content key should be present");
167-
let content_value = create_contract_content_value(block_hash, &account_proof, code)
168-
.expect("Content key should be present");
169-
block_stats.check_content(&content_key, &content_value);
170-
stats.check_content(&content_key, &content_value);
162+
.get_newly_created_contract(account.code_hash)
163+
{
164+
let content_key = create_contract_content_key(address_hash, account.code_hash)
165+
.expect("Content key should be present");
166+
let content_value =
167+
create_contract_content_value(block_hash, &account_proof, code)
168+
.expect("Content key should be present");
169+
block_stats.check_content(&content_key, &content_value);
170+
stats.check_content(&content_key, &content_value);
171+
}
171172
}
172173

173174
// check contract storage content key/value
@@ -188,7 +189,7 @@ async fn test_we_can_generate_content_key_values_up_to_x() -> Result<()> {
188189

189190
// flush the database cache
190191
// This is used for gossiping storage trie diffs
191-
trin_execution.database.storage_cache.lock().clear();
192+
trin_execution.database.clear_contract_cache();
192193
info!("Block {block_number} finished: {block_stats:?}");
193194
}
194195
temp_directory.close()?;

0 commit comments

Comments
 (0)