foundry-rs / foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
https://getfoundry.sh
Apache License 2.0
8.27k stars 1.74k forks source link

Feature request: chaos-anvil #3788

Open prestwich opened 1 year ago

prestwich commented 1 year ago

Component

Anvil

Describe the feature you would like

Description

Add chaos modes to anvil to better simulate real network conditions.

Motivation

RPC issues are common causes of bugs in foundry, script execution, and off-chain actors. Because mainnet nodes are consistently less reliable than testnet nodes and simulation nodes, it is difficult to test resilience to RPC issues in an application before production deployment

To support stress testing libs, applications, etc, we should add chaos features to anvil, to simulate faulty or weird behavior of mainnet RPC nodes

Details

A --chaos flag for anvil that takes the following instructions each of which enables a specific feature:

Example invocation anvil --chaos tx,send,getLog

Bonus points if we can configure frequency at which each of these events occur :)

Additional context

No response

gakonst commented 1 year ago

@mattsse this would be really sick. fault injection effectively. it's possible we could add this feature cleanly by implementing it as a wrapper around our current anvil axum api? that would be minimally invasive while letting us Config everything that the user sees.

I wonder if a generalized version of this is a proxy queueimplementation that sits in front of any node?

mattsse commented 1 year ago

ye, we could easily intercept this here:

https://github.com/foundry-rs/foundry/blob/07dccfd6ebac583ccd63bb818bf27e29b2a4005f/anvil/src/eth/api.rs#L138

with something like:

fn intercept(&self, req: EthRequest) -> Result<EthRequest, ResponseResult>;
0xcacti commented 1 year ago

If there is still interest in this feature, I stubbed out a super basic outline for how this might work. You can see it at my fork here - https://github.com/0xcacti/foundry/tree/0xcacti/chaos/crates/anvil

Basically, you add a config flag --chaos to the cli. You can pass in --chaos tx,send for some default rate of fault injection. Or you can configure probabilities with --chaos tx:0.005, ... and tx will inject faults 0.5% of the time.

If I am not totally off base here, I would need guidance on determining exactly which api methods we want to intercept and exactly how we want the failures to occur. Of course, no concerns if I am not going down the right path and we want to scrap this.

I also wrote out an example for how we might intercept logs It's pretty verbose and I am sure there is a better way to do it, but it's a start. (Again, this might not even be the right behavior we want)

    /// Returns logs matching given filter object.
    ///
    /// Handler for ETH RPC call: `eth_getLogs`
    pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {
        node_info!("eth_getLogs");
        let logs = self.backend.logs(filter).await;
        if let Some(chaos_config) = &self.chaos_config {
            if let Some(failure_rate) = chaos_config.get_log {
                if rand::random::<f64>() < failure_rate {
                    if let Ok(logs) = logs {
                        return Ok(self.intercept_logs(logs, failure_rate))
                    }
                }
            }
        }
        logs
    }

    fn intercept_logs(&self, logs: Vec<Log>, failure_rate: f64) -> Vec<Log> {
        logs.into_iter().filter(|_| rand::random::<f64>() > failure_rate).collect()
    }

Also would love stylistic guidance if you want me to go forward with implementing this.

Modified Files:

https://github.com/0xcacti/foundry/blob/9eda31b95fce4b66f92c3f122adfa6c432fe9a37/crates/anvil/src/eth/api.rs#L1125

https://github.com/0xcacti/foundry/blob/9eda31b95fce4b66f92c3f122adfa6c432fe9a37/crates/anvil/src/lib.rs#L93

https://github.com/0xcacti/foundry/blob/9eda31b95fce4b66f92c3f122adfa6c432fe9a37/crates/anvil/src/config.rs#L163

https://github.com/0xcacti/foundry/blob/9eda31b95fce4b66f92c3f122adfa6c432fe9a37/crates/anvil/src/cmd.rs#L80

Added File: chaos.rs https://github.com/0xcacti/foundry/blob/0xcacti/chaos/crates/anvil/src/eth/chaos.rs