Skip to content

Commit

Permalink
Due our work with anvil we faced huge memory consumption for long tests
Browse files Browse the repository at this point in the history
  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#3478
  • Loading branch information
kubmichael committed Dec 5, 2022
1 parent 36276aa commit 89e5907
Show file tree
Hide file tree
Showing 3 changed files with 38 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
20 changes: 20 additions & 0 deletions anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ 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 {
Expand All @@ -157,6 +159,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 +189,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 +758,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 89e5907

Please sign in to comment.