Skip to content

Commit

Permalink
Merge branch 'main' into arbiter-engine/world-agent-behaviors
Browse files Browse the repository at this point in the history
  • Loading branch information
Autoparallel committed Jan 22, 2024
2 parents d9d9647 + 3041530 commit d2b3911
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 75 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
[![Codecov badge](https://codecov.io/gh/primitivefinance/arbiter/branch/main/graph/badge.svg?token=UQ1SE0D9IN)](https://codecov.io/gh/primitivefinance/arbiter)
![Visitors badge](https://visitor-badge.laobi.icu/badge?page_id=arbiter)
![Telegram badge](https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Farbiter_rs)
[![Discord badge](https://dcbadge.vercel.app/api/server/primitive?style=flat)](https://discord.gg/primitive)
[![Twitter Badge](https://badgen.net/badge/icon/twitter?icon=twitter&label)](https://twitter.com/primitivefi)

**Arbiter** is a framework for stateful Ethereum smart-contract simulation.
Expand Down Expand Up @@ -92,7 +91,8 @@ You can run `arbiter init <simulation_name> --no-git` to remove the `.git` direc


### Bindings
You can load or write your own smart contracts in the templates `contracts/` directory and begin writing your own simulations.

You can load or write your own smart contracts in the `arbiter-bindings/contracts/` directory and begin writing your own simulations.
Arbiter treats Rust smart-contract bindings as first-class citizens. The contract bindings are generated via Foundry's `forge` command.
`arbiter bind` wraps `forge` with some convenience features that will generate all your bindings to src/bindings as a rust module.
[Foundry](https://github.com/foundry-rs/foundry) power-users are welcome to use `forge` directly.
Expand Down Expand Up @@ -125,9 +125,10 @@ You can run `arbiter init <simulation_name> --no-git` to remove the `.git` direc
## Documentation

To see the documentation for the Arbiter crates, please visit the following:
- [`arbiter`](https://docs.rs/crate/arbiter/0.3.2/)
- [`arbiter-core`](https://docs.rs/arbiter-core/0.5.1/arbiter_core/)
- [`arbiter-derive`](https://docs.rs/arbiter-derive/0.1.0/arbiter_derive/)
- [`arbiter`](https://docs.rs/crate/arbiter/)
- [`arbiter-bindings`](https://docs.rs/crate/arbiter-bindings/)
- [`arbiter-core`](https://docs.rs/arbiter-core/)
- [`arbiter-derive`](https://docs.rs/arbiter-derive/)

You will also find each of these on crates.io.

Expand All @@ -140,7 +141,7 @@ Preliminary benchmarks of the `RevmMiddleware` interface over `revm` against Anv

to run the benchmarking code yourself, you can run:
```bash
cargo bench --package arbiter-core -F contracts
cargo bench --package arbiter-core
```

bench from 10/24/23 arbiter-core v0.6.3
Expand Down
66 changes: 0 additions & 66 deletions arbiter-bindings/README.md

This file was deleted.

105 changes: 104 additions & 1 deletion arbiter-core/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! file.
use std::{
collections::BTreeMap,
convert::Infallible,
fmt::Debug,
fs,
Expand All @@ -16,7 +17,7 @@ use revm::{
primitives::{AccountInfo, B256, U256},
Database, DatabaseCommit,
};
use revm_primitives::{db::DatabaseRef, Bytecode};
use revm_primitives::{db::DatabaseRef, keccak256, Address, Bytecode, Bytes};
use serde::{Deserialize, Serialize};
use serde_json;

Expand Down Expand Up @@ -131,8 +132,57 @@ impl DatabaseCommit for ArbiterDB {
}
}

/// [AnvilDump] models the schema of an [anvil](https://github.com/foundry-rs/foundry) state dump.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AnvilDump {
/// Mapping of account addresses to [AccountRecord]s stored in the dump
/// file.
pub accounts: BTreeMap<Address, AccountRecord>,
}

/// [AccountRecord] describes metadata about an account within the state trie.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AccountRecord {
/// The nonce of the account.
pub nonce: u64,
/// The balance of the account.
pub balance: U256,
/// The bytecode of the account. If empty, the account is an EOA.
pub code: Bytes,
/// The storage mapping of the account.
pub storage: revm_primitives::HashMap<U256, U256>,
}

impl TryFrom<AnvilDump> for CacheDB<EmptyDB> {
type Error = <CacheDB<EmptyDB> as Database>::Error;

fn try_from(dump: AnvilDump) -> Result<Self, Self::Error> {
let mut db = CacheDB::default();

dump.accounts
.into_iter()
.try_for_each(|(address, account_record)| {
db.insert_account_info(
address,
AccountInfo {
balance: account_record.balance,
nonce: account_record.nonce,
code_hash: keccak256(account_record.code.as_ref()),
code: (!account_record.code.is_empty())
.then(|| Bytecode::new_raw(account_record.code)),
},
);
db.replace_account_storage(address, account_record.storage)
})?;

Ok(db)
}
}

#[cfg(test)]
mod tests {
use revm_primitives::{address, bytes};

use super::*;

#[test]
Expand All @@ -143,4 +193,57 @@ mod tests {
assert_eq!(db, ArbiterDB::new());
fs::remove_file("test.json").unwrap();
}

#[test]
fn load_anvil_dump_cachedb() {
const RAW_DUMP: &str = r#"
{
"accounts": {
"0x0000000000000000000000000000000000000000": {
"nonce": 1234,
"balance": "0xfacade",
"code": "0x",
"storage": {}
},
"0x0000000000000000000000000000000000000001": {
"nonce": 555,
"balance": "0xc0ffee",
"code": "0xbadc0de0",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000000000000000000000000000000000000000deAD",
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000000000000000000000000000000000000000babe"
}
}
}
}
"#;

let dump: AnvilDump = serde_json::from_str(RAW_DUMP).unwrap();
let mut db: CacheDB<EmptyDB> = dump.try_into().unwrap();

let account_a = db
.load_account(address!("0000000000000000000000000000000000000000"))
.unwrap();
assert_eq!(account_a.info.nonce, 1234);
assert_eq!(account_a.info.balance, U256::from(0xfacade));
assert_eq!(account_a.info.code, None);
assert_eq!(account_a.info.code_hash, keccak256(&[]));

let account_b = db
.load_account(address!("0000000000000000000000000000000000000001"))
.unwrap();
let b_bytecode = bytes!("badc0de0");
assert_eq!(account_b.info.nonce, 555);
assert_eq!(account_b.info.balance, U256::from(0xc0ffee));
assert_eq!(account_b.info.code_hash, keccak256(b_bytecode.as_ref()));
assert_eq!(account_b.info.code, Some(Bytecode::new_raw(b_bytecode)));
assert_eq!(
account_b.storage.get(&U256::ZERO),
Some(&U256::from(0xdead))
);
assert_eq!(
account_b.storage.get(&U256::from(1)),
Some(&U256::from(0xbabe))
);
}
}
5 changes: 4 additions & 1 deletion arbiter-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ description = "Allowing smart contract developers to do simulation driven develo
license = "Apache-2.0"
keywords = ["ethereum", "evm", "emulator", "testing", "smart-contracts"]
readme = "../README.md"
documentation = "https://docs.rs/arbiter-engine"
homepage = "https://github.com/primitivefinance/arbiter"
repository = "https://github.com/primitivefinance/arbiter"

[dependencies]
ethers.workspace = true
Expand All @@ -26,6 +29,6 @@ arbiter-bindings.workspace = true

[dev-dependencies]
arbiter-core.workspace = true
arbiter-bindings = { version = "0.1.1", path = "../arbiter-bindings" }
arbiter-bindings.workspace = true
tracing-subscriber = "0.3.18"
tracing-test = "0.2.4"
13 changes: 12 additions & 1 deletion arbiter-engine/src/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub struct World {
}

impl World {
/// Creates a new world with the given identifier and provider.
/// Creates a new [World] with the given identifier and provider.
pub fn new(id: &str) -> Self {
Self {
id: id.to_owned(),
Expand All @@ -86,6 +86,17 @@ impl World {
}
}

/// Creates a new [World] with the given identifier and provider.
pub fn new_with_env(id: &str, environment: Environment) -> Self {
Self {
id: id.to_owned(),
agents: Some(HashMap::new()),
agent_tasks: None,
environment,
messager: Messager::new(),
}
}

/// Adds an agent to the world.
pub fn add_agent(&mut self, agent: Agent) {
let id = agent.id.clone();
Expand Down

0 comments on commit d2b3911

Please sign in to comment.