Arbiter v0.4.0 and Arbiter Core v0.6.0

Cover Image for Arbiter v0.4.0 and Arbiter Core v0.6.0
Waylon Jepsen
Waylon Jepsen

New Arbiter Release

This week we are happy to announce a new release of Arbiter! We have been working hard to improve the developer experience and add new features. This release has minor version updates to both the arbiter binary (v0.4.0) and the arbiter-core (v0.6.0) crates.

Primitive and Community Contributions

Environment Cheatcodes

We closed Issue #485 and shipped an initial set of the Environment Cheatcodes accessible over our Rust API. The included list of supported cheatcodes are:

  • deal: Distribute raw ether to any address.
  • load: Load a storage slot contents from an account.
  • store: Overwrites a storage slot of an account.

These can be found here. We will continue to add to these as we and other users find them useful. This also ships a BlockUpdate instruction which allows you to update the block number and timestamp of the environment.

Forking

Issue #461 was one of the most hotly requested features supporting the ability to fork a chain. This feature supports forking from an RPC endpoint with a new CLI command arbiter fork which reads in a block number, a URL to fork from, an output directory and file name, and an address we want to fork. This feature ships with an example configuration file and a collection of tests. Furthermore, we added support to load in the key-value store mapping of ETH accounts from the forked output file into the in-memory revm instance so you can use the forked state in your simulations.

This contrasts Anvil which maintains an active connection to blockchains. If you make a call on anvil, anvil will fetch all the info from main-net and store it locally. This allows for Anvil to actively fetch state from the chain as you need it, and then caches it, supporting dynamic exhaustive functionality which is quite useful.

We decided to take a different approach because actively maintaining a connection to the chain would be a lot of overhead and reduce the speed of our simulations. We decided to allow users to supply a list or ethereum addresses that we want to fork and have when we start our simulation. So the only time we are actually making an RPC call is when we fetch the on-chain data. This is nice because we don't need to maintain an active connection to the chain. We instead pre-fetch the data then load in the raw data at the start of the simulation allowing us to maintain the speed of the simulations at the cost of the dynamic functionality of Anvil. We feel this is a good tradeoff for our use case.

Nonce Management

We closed Issue #484 which implemented a NonceManagerMiddleware that is composable with the existing RevmMiddleware. This composability is made possible through the ethers-rs design approach which promotes “Open Closed Principle”, “Single Responsibility” and composable patterns. As a result of this feature we also extended the RevmMiddleware to support fill_transaction and get_transaction_count thus improving our middleware API. The get_transaction_count calls are sent to the environment with a new TransactionCount(ethers::types::Address) environment instruction and propagates the nonce from the revm account info to our end user API.

Data Output

Collecting data from simulations was one of the largest hurdles we faced in our own simulations. We are happy to announce that we have closed Issue #515 by adding a generic event capture mechanism that will auto log all events added to this process to a file. This is a huge step forward for our own simulations and we hope it will be for yours as well. This does so by creating an event builder that you can add event objects (as described in the ethers-rs) to. The generic event monitor will serialize and decode these events for us and write them to a file. This streamlines the process of collecting data from simulations and allows for better ingestion for more robust analysis. Special mention on this to the ether-rs and foundry teams for accepting these two PRs: feat: add dependencies to MultiBindingsInner, feat(forge-bind): add_derives for serde in contract bindings which helped us get this feature out the door.

Using the builder pattern for Environment

We closed Issue #516 and Issue #511 (Thanks Brock for the feedback) by supporting a builder pattern for the Environment struct. This allows us to support a more ergonomic API for the Environment struct and add the optionality for environment parameters. This does introduce breaking changes to the Environment struct and if you plan to migrate to the new version you must update your environment construction to use the builder pattern.

Refactoring

Issue #534 and Issue 528 were minor quality of life changes that have made the code base easier to navigate and maintain by breaking apart some of our larger files into modules. This also squashed a bug in our RevmMiddleware that was causing a stack overflow by infinite recursion of the self.inner attribute. We also got rid of the manager structure after arriving at the assumption that it was a premature abstraction and rarely used while adding complexity to the end user API. This simplified the simulation creation process from:

let mut manager = Manager::new(); let _ = manager.add_environment(EnvironmentParameters { label: "test_label".to_owned(), block_settings: BlockSettings::UserControlled, gas_settings: GasSettings::UserControlled, }); manager.start_environment("test_label")?; let _ = manager.add_environment( "test_label", EnvironmentParameters { block_rate: 1.0, seed: 1, }, let client_with_signer = Arc::new( RevmMiddleware::new(manager.environments.get("test_label").unwrap(), None).unwrap(), ); let client_with_signer = Arc::new(RevmMiddleware::new( manager.environments.get("test_label").unwrap(), None, ));

to two lines:

let environment = EnvironmentBuilder::new().label("test_label").build(); let client_with_signer = RevmMiddleware::new(&environment, None)?;

As you can see this greatly simplifies the process of creating a simulation and we hope it will make it easier for you to get started with Arbiter.

CLI Improvements

The binary crate has two primary improvements in addition to the forking feature. The first of which is outlined by Issue #502, which enables users to optionally pass a no-git flag to the arbiter init CLI which would initialize the arbiter simulation without a .git file. This is useful if you want to initialize a simulation inside of an already existing project. The second improvement is outlined by Issue #465 which adds some improvements to the arbiter bind CLI. Previously, many ancillary contracts that were never used or unnecessary were generated. This has now been fixed and only core contract bindings are generated greatly reducing the number of files generated. We feel this is a much better developer experience and will continue to improve this process.

Known Issues

While this release stabilizes we anticipate to discover and patch bugs and issues as they arise. If you find a problem with the new release please open an issue on Github. As of now we are aware that some tests fail on occasion. It has become a challenge to debug these issues as they are difficult to reproduce and only fail rarely. The occasionally failing tests are:

fork::tests::read_in ... FAILED
fork::tests::write_out ... FAILED
tests::data_output::data_capture_output_validation ... FAILED

We are working on a solution to these issues and will be sure to update the community when we have a fix.


What We Have Planned

Moving forward we want to allow for these features to stabilize and try them out for ourselves! We will be spending our next sprint using Arbiter internally on a number of projects to drive simulation driven insights on our development process and eliminate bugs and vulnerabilities. We aspire to use this experience to inform our next set of features and improvements in the future.

MD Book!

We did kick off an initiative to start an arbiter MDBook. As a number of our users have requested more documentation and we feel this is a great way to get started familiarizing yourself with the code base. We will be working with the community on this in the coming weeks and hope to have a first draft out soon.


As always all of our features are shipped with a collection of tests to ensure their functionality and quality of performance. If you would like to contribute to Arbiter in any way, be it suggestions, features, bug fixes, or management, please feel free to reach out to us on Telegram or open issues/PRs on Github. We are very open to community feedback and if there is consensus on desired features we will be sure to implement them as soon as we can. The new releases are published to crates.io and can be installed directly with cargo. For a full changelog see the full changelog on Github.