Skip to content

Commit

Permalink
Due our work with anvil we faced huge memory consumption for long t……
Browse files Browse the repository at this point in the history
… (#3836)

* Due our work with anvil we faced huge memory consumption for long tests
  Anvil is keeping all mined transaction in memory, so proposal is to
  add config option that will limit number of block with transaction in memory

  This is workaround
  Related to foundry-rs/foundry#3478

* make clippy happy
  • Loading branch information
charisma98 committed Dec 7, 2022
1 parent cb52f53 commit 3240f43
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
4 changes: 4 additions & 0 deletions anvil/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ pub struct NodeArgs {

#[clap(long, help = "Don't keep full chain history.")]
pub prune_history: bool,

#[clap(long, help = "Number of blocks with transactions to keep in memory.")]
pub transaction_block_keeper: Option<usize>,
}

#[cfg(windows)]
Expand Down Expand Up @@ -235,6 +238,7 @@ impl NodeArgs {
.set_pruned_history(self.prune_history)
.with_init_state(self.load_state)
.with_init_state(self.state.and_then(|s| s.state))
.with_transaction_block_keeper(self.transaction_block_keeper)
}

fn account_generator(&self) -> AccountGenerator {
Expand Down
14 changes: 14 additions & 0 deletions anvil/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ pub struct NodeConfig {
pub prune_history: bool,
/// The file where to load the state from
pub init_state: Option<SerializableState>,
/// max number of blocks with transactions in memory
pub transaction_block_keeper: Option<usize>,
}

impl NodeConfig {
Expand Down Expand Up @@ -362,6 +364,7 @@ impl Default for NodeConfig {
code_size_limit: None,
prune_history: false,
init_state: None,
transaction_block_keeper: None,
}
}
}
Expand Down Expand Up @@ -447,6 +450,16 @@ impl NodeConfig {
self
}

/// Sets max number of blocks with transactions to keep in memory
#[must_use]
pub fn with_transaction_block_keeper<U: Into<usize>>(
mut self,
transaction_block_keeper: Option<U>,
) -> Self {
self.transaction_block_keeper = transaction_block_keeper.map(Into::into);
self
}

/// Sets the base fee
#[must_use]
pub fn with_base_fee<U: Into<U256>>(mut self, base_fee: Option<U>) -> Self {
Expand Down Expand Up @@ -908,6 +921,7 @@ impl NodeConfig {
fork,
self.enable_steps_tracing,
self.prune_history,
self.transaction_block_keeper,
)
.await;

Expand Down
21 changes: 21 additions & 0 deletions anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,13 @@ pub struct Backend {
enable_steps_tracing: bool,
/// Whether to keep history state
prune_history: bool,
/// max number of blocks with transactions in memory
transaction_block_keeper: Option<usize>,
}

impl Backend {
/// Initialises the balance of the given accounts
#[allow(clippy::too_many_arguments)]
pub async fn with_genesis(
db: Arc<AsyncRwLock<dyn Db>>,
env: Arc<RwLock<Env>>,
Expand All @@ -157,6 +160,7 @@ impl Backend {
fork: Option<ClientFork>,
enable_steps_tracing: bool,
prune_history: bool,
transaction_block_keeper: Option<usize>,
) -> Self {
// if this is a fork then adjust the blockchain storage
let blockchain = if let Some(ref fork) = fork {
Expand Down Expand Up @@ -186,6 +190,7 @@ impl Backend {
active_snapshots: Arc::new(Mutex::new(Default::default())),
enable_steps_tracing,
prune_history,
transaction_block_keeper,
};

// Note: this can only fail in forking mode, in which case we can't recover
Expand Down Expand Up @@ -754,6 +759,22 @@ impl Backend {
storage.transactions.insert(mined_tx.info.transaction_hash, mined_tx);
}

if let Some(transaction_block_keeper) = self.transaction_block_keeper {
if storage.blocks.len() > transaction_block_keeper {
let n: U64 = block_number
.as_u64()
.saturating_sub(transaction_block_keeper.try_into().unwrap())
.into();
if let Some(hash) = storage.hashes.get(&n) {
if let Some(block) = storage.blocks.get(hash) {
for tx in block.clone().transactions {
let _ = storage.transactions.remove(&tx.hash());
}
}
}
}
}

// we intentionally set the difficulty to `0` for newer blocks
env.block.difficulty = U256::zero();

Expand Down

0 comments on commit 3240f43

Please sign in to comment.