From 6a29dc9e9b3082df389619fb0a15a1108ea8650c Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Fri, 6 Jun 2025 21:07:31 +0000 Subject: [PATCH 01/16] init --- Cargo.lock | 58 ++++++-- Cargo.toml | 4 +- crates/bindings/src/lib.rs | 34 ++++- crates/cli/Cargo.toml | 4 +- crates/cli/src/commands/eval.rs | 20 +-- crates/dispair/Cargo.toml | 3 + crates/dispair/src/lib.rs | 53 +++---- crates/env/Cargo.toml | 10 -- crates/env/src/lib.rs | 39 ------ crates/eval/Cargo.toml | 2 +- crates/eval/src/eval.rs | 93 ++++++++----- crates/eval/src/fork.rs | 130 ++++++++--------- crates/eval/src/namespace.rs | 2 +- crates/eval/src/trace.rs | 75 +++++----- crates/test_fixtures/Cargo.toml | 15 ++ crates/test_fixtures/src/lib.rs | 239 ++++++++++++++++++++++++++++++++ test/utils/TestERC20.sol | 19 +++ 17 files changed, 543 insertions(+), 257 deletions(-) delete mode 100644 crates/env/Cargo.toml delete mode 100644 crates/env/src/lib.rs create mode 100644 crates/test_fixtures/Cargo.toml create mode 100644 crates/test_fixtures/src/lib.rs create mode 100644 test/utils/TestERC20.sol diff --git a/Cargo.lock b/Cargo.lock index 6e7a3337d..61aa538f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,6 +69,7 @@ dependencies = [ "alloy-genesis", "alloy-json-rpc", "alloy-network", + "alloy-node-bindings", "alloy-provider", "alloy-rpc-client", "alloy-rpc-types", @@ -379,6 +380,27 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-node-bindings" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aec69b8e97eaba1df99ac52e485931c066795dc92b221e337cf2a6d53f4beb10" +dependencies = [ + "alloy-genesis", + "alloy-hardforks", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "alloy-signer-local", + "k256", + "rand 0.8.5", + "serde_json", + "tempfile", + "thiserror 2.0.12", + "tracing", + "url", +] + [[package]] name = "alloy-op-evm" version = "0.10.0" @@ -449,8 +471,10 @@ dependencies = [ "alloy-json-rpc", "alloy-network", "alloy-network-primitives", + "alloy-node-bindings", "alloy-primitives", "alloy-rpc-client", + "alloy-rpc-types-anvil", "alloy-rpc-types-eth", "alloy-signer", "alloy-sol-types", @@ -557,6 +581,18 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-rpc-types-anvil" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f7e3f1efdb3ef6f2e0e09036099933f9d96ff1d3129be4b2e5394550a58b39d" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + [[package]] name = "alloy-rpc-types-any" version = "1.0.9" @@ -5161,9 +5197,9 @@ dependencies = [ "alloy", "anyhow", "clap", - "rain-interpreter-env", "rain-interpreter-eval", "rain_interpreter_bindings", + "rain_interpreter_test_fixtures", "serde", "serde_bytes", "tokio", @@ -5171,14 +5207,6 @@ dependencies = [ "tracing-subscriber 0.3.19", ] -[[package]] -name = "rain-interpreter-env" -version = "0.0.0" -dependencies = [ - "alloy", - "once_cell", -] - [[package]] name = "rain-interpreter-eval" version = "0.1.0" @@ -5188,8 +5216,8 @@ dependencies = [ "foundry-evm", "once_cell", "rain-error-decoding", - "rain-interpreter-env", "rain_interpreter_bindings", + "rain_interpreter_test_fixtures", "reqwest 0.11.27", "revm", "serde", @@ -5213,6 +5241,7 @@ dependencies = [ "alloy", "alloy-ethers-typecast", "rain_interpreter_bindings", + "rain_interpreter_test_fixtures", "serde", "serde_json", "thiserror 1.0.69", @@ -5235,6 +5264,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "rain_interpreter_test_fixtures" +version = "0.0.0" +dependencies = [ + "alloy", + "getrandom 0.2.16", + "serde_json", +] + [[package]] name = "rand" version = "0.8.5" diff --git a/Cargo.toml b/Cargo.toml index 54ded7e22..81595a31b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,6 @@ tracing-subscriber = "0.3.17" reqwest = { version = "0.11.17", features = ["json"] } once_cell = "1.17.1" alloy-ethers-typecast = { git = "https://github.com/rainlanguage/alloy-ethers-typecast", rev = "f7b5bfd0687f16c77dbfdd4905b2434793fa7885" } -rain-interpreter-env = { path = "crates/env" } eyre = "0.6" rain-error-decoding = { git = "https://github.com/rainlanguage/rain.error", rev = "bf08b5ab305287fc49408a441d6375f35dc280db" } @@ -48,3 +47,6 @@ path = "crates/bindings" [workspace.dependencies.rain-interpreter-eval] path = "crates/eval" + +[workspace.dependencies.rain_interpreter_test_fixtures] +path = "crates/test_fixtures" diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index f6fdc26c9..576f2a71e 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -1,5 +1,6 @@ use alloy::sol; +// interpreters sol!( #![sol(all_derives = true)] IInterpreterV2, @@ -10,6 +11,13 @@ sol!( IInterpreterV3, "../../out/IInterpreterV3.sol/IInterpreterV3.json" ); +sol!( + #![sol(all_derives = true)] + IInterpreterV4, + "../../out/IInterpreterV4.sol/IInterpreterV4.json" +); + +// stores sol!( #![sol(all_derives = true)] IInterpreterStoreV1, @@ -17,19 +25,39 @@ sol!( ); sol!( #![sol(all_derives = true)] - IParserV1, "../../out/IParserV1.sol/IParserV1.json"); + IInterpreterStoreV2, + "../../out/IInterpreterStoreV2.sol/IInterpreterStoreV2.json" +); +sol!( + #![sol(all_derives = true)] + IInterpreterStoreV3, + "../../out/IInterpreterStoreV3.sol/IInterpreterStoreV3.json" +); +// parsers sol!( #![sol(all_derives = true)] - IParserV2, "../../out/IParserV2.sol/IParserV2.json"); + IParserV1, "../../out/IParserV1.sol/IParserV1.json" +); +sol!( + #![sol(all_derives = true)] + IParserV2, "../../out/IParserV2.sol/IParserV2.json" +); + +// pragma sol!( #![sol(all_derives = true)] - IParserPragmaV1, "../../out/IParserPragmaV1.sol/IParserPragmaV1.json"); + IParserPragmaV1, "../../out/IParserPragmaV1.sol/IParserPragmaV1.json" +); + +// deployer sol!( #![sol(all_derives = true)] IExpressionDeployerV3, "../../out/IExpressionDeployerV3.sol/IExpressionDeployerV3.json" ); + +// dispair binding sol! { #![sol(all_derives = true)] interface DeployerISP { diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index abeb1f00c..30dd517e2 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -18,7 +18,6 @@ serde_bytes = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ['env-filter'] } alloy = { workspace = true } -rain-interpreter-env = { workspace = true } [target.'cfg(not(target_family = "wasm"))'.dependencies] tokio = { version = "1.28.0", features = ["full"] } @@ -31,3 +30,6 @@ tokio = { version = "1.28.0", features = [ "rt", "time", ] } + +[dev-dependencies] +rain_interpreter_test_fixtures = { workspace = true } diff --git a/crates/cli/src/commands/eval.rs b/crates/cli/src/commands/eval.rs index d0ccf1434..c8009bf75 100644 --- a/crates/cli/src/commands/eval.rs +++ b/crates/cli/src/commands/eval.rs @@ -6,7 +6,7 @@ use anyhow::anyhow; use anyhow::Context; use anyhow::Result; use clap::Args; -use rain_interpreter_bindings::IInterpreterStoreV1::FullyQualifiedNamespace; +use rain_interpreter_bindings::IInterpreterStoreV3::FullyQualifiedNamespace; use rain_interpreter_eval::trace::RainEvalResult; use rain_interpreter_eval::{eval::ForkEvalArgs, fork::Forker}; use std::path::PathBuf; @@ -62,6 +62,8 @@ impl TryFrom for ForkEvalArgs { namespace: FullyQualifiedNamespace::from(namespace), context, decode_errors: args.decode_errors, + inputs: vec![], + state_overlay: vec![], }) } } @@ -112,10 +114,7 @@ impl Execute for Eval { #[cfg(test)] mod tests { use super::*; - - use rain_interpreter_env::{ - CI_DEPLOY_SEPOLIA_RPC_URL, CI_FORK_SEPOLIA_BLOCK_NUMBER, CI_FORK_SEPOLIA_DEPLOYER_ADDRESS, - }; + use rain_interpreter_test_fixtures::LocalEvm; #[test] fn test_parse_int_or_hex() { @@ -127,16 +126,19 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_execute() { + let local_evm = LocalEvm::new().await; + let deployer = *local_evm.deployer.address(); + let eval = Eval { output_path: None, forked_evm: NewForkedEvmCliArgs { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_string(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }, fork_eval_args: ForkEvalCliArgs { - rainlang_string: r"_: add(10 2), _: context<0 0>(), _:context<0 1>();".into(), + rainlang_string: r"_: 12, _: context<0 0>(), _:context<0 1>();".into(), source_index: 0, - deployer: *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS, + deployer, namespace: "0x123".into(), context: vec!["0x06,99".into()], decode_errors: true, diff --git a/crates/dispair/Cargo.toml b/crates/dispair/Cargo.toml index 4cbe3e0b5..af7afa687 100644 --- a/crates/dispair/Cargo.toml +++ b/crates/dispair/Cargo.toml @@ -28,5 +28,8 @@ tokio = { version = "1.28.0", features = [ "time", ] } +[dev-dependencies] +rain_interpreter_test_fixtures = { workspace = true } + [package.metadata.docs.rs] all-features = true diff --git a/crates/dispair/src/lib.rs b/crates/dispair/src/lib.rs index 0342e3f75..3e76e5380 100644 --- a/crates/dispair/src/lib.rs +++ b/crates/dispair/src/lib.rs @@ -69,47 +69,26 @@ impl DISPair { #[cfg(test)] mod tests { use super::*; - use alloy::primitives::Address; - use alloy::providers::mock::Asserter; - use tracing_subscriber::FmtSubscriber; + use rain_interpreter_test_fixtures::LocalEvm; #[tokio::test] async fn test_from_deployer() { - setup_tracing(); - - let asserter = Asserter::new(); - let deployer_address = "0x1111111111111111111111111111111111111111" - .parse::
() - .unwrap(); - let interpreter_address = "2222222222222222222222222222222222222222"; - let store_address = "3333333333333333333333333333333333333333"; - let parser_address = "4444444444444444444444444444444444444444"; - - asserter.push_success(&format!("0x{interpreter_address:0>64}")); - asserter.push_success(&format!("0x{store_address:0>64}")); - asserter.push_success(&format!("0x{parser_address:0>64}")); - - let client = ReadableClient::new_mocked(asserter); - let dispair = DISPair::from_deployer(deployer_address, client) + let local_evm = LocalEvm::new().await; + let deployer = *local_evm.deployer.address(); + let client = ReadableClient::new_from_url(local_evm.url()) .await - .unwrap(); - - assert_eq!(dispair.deployer, deployer_address); - assert_eq!( - dispair.interpreter, - interpreter_address.parse::
().unwrap() - ); - assert_eq!(dispair.store, store_address.parse::
().unwrap()); - assert_eq!(dispair.parser, parser_address.parse::
().unwrap()); - } - - #[allow(dead_code)] - fn setup_tracing() { - let subscriber = FmtSubscriber::builder() - .with_max_level(tracing::Level::DEBUG) - .finish(); + .expect("Failed to create ReadableClient"); + let dispair = DISPair::from_deployer(deployer, client).await.unwrap(); + let expected = DISPair { + deployer, + interpreter: *local_evm.interpreter.address(), + store: *local_evm.store.address(), + parser: *local_evm.parser.address(), + }; - tracing::subscriber::set_global_default(subscriber) - .expect("Failed to set tracing subscriber"); + assert_eq!(dispair.deployer, expected.deployer); + assert_eq!(dispair.interpreter, expected.interpreter); + assert_eq!(dispair.store, expected.store); + assert_eq!(dispair.parser, expected.parser); } } diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml deleted file mode 100644 index d1d2e6954..000000000 --- a/crates/env/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "rain-interpreter-env" -version = "0.0.0" -edition.workspace = true -license.workspace = true -homepage.workspace = true - -[dependencies] -once_cell = { workspace = true } -alloy = { workspace = true } diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs deleted file mode 100644 index 817c3d6ac..000000000 --- a/crates/env/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -use alloy::primitives::{Address, BlockNumber}; -use once_cell::sync::Lazy; - -pub static CI_DEPLOY_SEPOLIA_RPC_URL: Lazy = Lazy::new(|| { - env!( - "CI_DEPLOY_SEPOLIA_RPC_URL", - "$CI_DEPLOY_SEPOLIA_RPC_URL not set." - ) - .to_string() -}); - -pub static CI_FORK_SEPOLIA_DEPLOYER_ADDRESS: Lazy
= Lazy::new(|| { - env!( - "CI_FORK_SEPOLIA_DEPLOYER_ADDRESS", - "$CI_FORK_SEPOLIA_DEPLOYER_ADDRESS not set." - ) - .parse() - .unwrap() -}); - -pub static CI_FORK_SEPOLIA_BLOCK_NUMBER: Lazy = Lazy::new(|| { - env!( - "CI_FORK_SEPOLIA_BLOCK_NUMBER", - "$CI_FORK_SEPOLIA_BLOCK_NUMBER not set." - ) - .parse() - .unwrap() -}); - -pub static CI_FORK_POLYGON_RPC_URL: Lazy = Lazy::new(|| { - env!( - "CI_FORK_POLYGON_RPC_URL", - "$CI_FORK_POLYGON_RPC_URL not set." - ) - .to_string() -}); - -pub static CI_FORK_BSC_RPC_URL: Lazy = - Lazy::new(|| env!("CI_FORK_BSC_RPC_URL", "$CI_FORK_BSC_RPC_URL not set.").to_string()); diff --git a/crates/eval/Cargo.toml b/crates/eval/Cargo.toml index c4f9631be..65f7afc32 100644 --- a/crates/eval/Cargo.toml +++ b/crates/eval/Cargo.toml @@ -22,7 +22,7 @@ revm = { workspace = true } [dev-dependencies] tracing = { workspace = true } -rain-interpreter-env = { workspace = true } +rain_interpreter_test_fixtures = { workspace = true } [target.'cfg(not(target_family = "wasm"))'.dev-dependencies] tokio = { version = "1.28.0", features = ["full"] } diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 2b088d012..859736baa 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -2,8 +2,8 @@ use crate::error::ForkCallError; use crate::fork::{ForkTypedReturn, Forker}; use alloy::primitives::{Address, U256}; use rain_interpreter_bindings::DeployerISP::{iInterpreterCall, iStoreCall}; -use rain_interpreter_bindings::IInterpreterStoreV1::FullyQualifiedNamespace; -use rain_interpreter_bindings::IInterpreterV3::eval3Call; +use rain_interpreter_bindings::IInterpreterStoreV3::FullyQualifiedNamespace; +use rain_interpreter_bindings::IInterpreterV4::{EvalV4, eval4Call}; use rain_interpreter_bindings::IParserV2::parse2Call; #[derive(Debug, Clone)] @@ -14,6 +14,8 @@ pub struct ForkEvalArgs { pub namespace: FullyQualifiedNamespace, pub context: Vec>, pub decode_errors: bool, + pub inputs: Vec, + pub state_overlay: Vec, } #[derive(Debug, Clone)] @@ -74,6 +76,9 @@ impl Forker { /// * `deployer` - The address of the deployer. /// * `namespace` - The fully qualified namespace. /// * `context` - The context vector. + /// * `inputs` - The inputs vector. + /// * `state_overlay` - The state_overlay vector. + /// * `decode_errors` - Whether to decode errors from registry or not /// /// # Returns /// @@ -81,7 +86,7 @@ impl Forker { pub async fn fork_eval( &self, args: ForkEvalArgs, - ) -> Result, ForkCallError> { + ) -> Result, ForkCallError> { let ForkEvalArgs { rainlang_string, source_index, @@ -89,6 +94,8 @@ impl Forker { namespace, context, decode_errors, + inputs, + state_overlay, } = args; let parse_result = self .fork_parse(ForkParseArgs { @@ -113,13 +120,19 @@ impl Forker { .await? .typed_return; - let eval_args = eval3Call { - bytecode: parse_result.typed_return, - sourceIndex: U256::from(source_index), - store, - namespace: namespace.into(), - context, - inputs: vec![], + let eval_args = eval4Call { + eval: EvalV4 { + bytecode: parse_result.typed_return, + sourceIndex: U256::from(source_index), + store, + namespace: namespace.into(), + context: context + .into_iter() + .map(|v| v.into_iter().map(Into::into).collect()) + .collect(), + inputs: inputs.into_iter().map(Into::into).collect(), + stateOverlay: state_overlay.into_iter().map(Into::into).collect(), + }, }; let res = self @@ -132,76 +145,78 @@ impl Forker { #[cfg(test)] mod tests { - use alloy::primitives::utils::parse_ether; - use foundry_evm::traces::CallTraceArena; - use rain_interpreter_env::{ - CI_DEPLOY_SEPOLIA_RPC_URL, CI_FORK_SEPOLIA_BLOCK_NUMBER, CI_FORK_SEPOLIA_DEPLOYER_ADDRESS, - }; - - use std::sync::Arc; - use super::*; use crate::fork::NewForkedEvm; + use alloy::primitives::FixedBytes; + use foundry_evm::traces::CallTraceArena; + use rain_interpreter_test_fixtures::LocalEvm; + use std::sync::Arc; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_fork_parse() { - let deployer: Address = *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS; + let local_evm = LocalEvm::new().await; + let deployer = *local_evm.deployer.address(); let args = NewForkedEvm { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_string(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }; let fork = Forker::new_with_fork(args, None, None).await.unwrap(); + let x = local_evm.deployer.iInterpreter().call().await.unwrap(); + println!("{}", x); let res = fork .fork_parse(ForkParseArgs { - rainlang_string: r"_: add(1 2);".to_owned(), + rainlang_string: r"_: 1;".to_owned(), deployer, decode_errors: true, }) .await .unwrap(); - let expected_bytes: Vec = alloy::hex::decode("0x00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000130100000302000101100001011000002b120000").unwrap(); + let expected_bytes: Vec = alloy::hex::decode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000b0100000101000101100000").unwrap(); assert_eq!(res.typed_return.0, expected_bytes); } #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_fork_eval() { - let deployer: Address = *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS; + let local_evm = LocalEvm::new().await; + let deployer = *local_evm.deployer.address(); let args = NewForkedEvm { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_owned(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }; let fork = Forker::new_with_fork(args, None, None).await.unwrap(); let res = fork .fork_eval(ForkEvalArgs { - rainlang_string: r"_: add(1 2);".into(), + rainlang_string: r"_: 3;".into(), source_index: 0, deployer, namespace: FullyQualifiedNamespace::default(), context: vec![], decode_errors: true, + state_overlay: vec![], + inputs: vec![], }) .await .unwrap(); // stack - let expected_stack = vec![parse_ether("3").unwrap()]; + let expected_stack: Vec> = vec![FixedBytes::left_padding_from(&[3u8])]; assert_eq!(res.typed_return.stack, expected_stack); // storage writes - let expected_writes = vec![]; + let expected_writes: Vec> = vec![]; assert_eq!(res.typed_return.writes, expected_writes); // stack in the trace for source index 0 let mut expected_stack_trace = vec![0u8, 0u8, 0u8, 0u8]; - expected_stack_trace.append(&mut parse_ether("3").unwrap().to_be_bytes_vec()); + expected_stack_trace.append(&mut >::left_padding_from(&[3u8]).to_vec()); let sparsed_trace_arena = res.raw.traces.unwrap(); let source_index_zero_trace = ::clone(&sparsed_trace_arena) .into_nodes()[1] .to_owned() .trace; - assert_eq!(source_index_zero_trace.data, expected_stack_trace); + assert_eq!(source_index_zero_trace.data.to_vec(), expected_stack_trace); // asserting the known trace address let expected_trace_address = "0xF06Cd48c98d7321649dB7D8b2C396A81A2046555" @@ -213,10 +228,11 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 10)] async fn test_fork_eval_parallel() { - let deployer: Address = *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS; + let local_evm = LocalEvm::new().await; + let deployer = *local_evm.deployer.address(); let args = NewForkedEvm { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_string(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }; let fork = Forker::new_with_fork(args, None, None).await.unwrap(); let fork = Arc::new(fork); // Wrap in Arc for shared ownership @@ -227,12 +243,14 @@ mod tests { let handle = tokio::spawn(async move { fork_clone .fork_eval(ForkEvalArgs { - rainlang_string: r"_: add(1 2);".into(), + rainlang_string: r"_: 3;".into(), source_index: 0, deployer, namespace: FullyQualifiedNamespace::default(), context: vec![], decode_errors: true, + state_overlay: vec![], + inputs: vec![], }) .await .unwrap() @@ -242,7 +260,10 @@ mod tests { for handle in handles { let res = handle.await.unwrap(); - assert_eq!(res.typed_return.stack, vec![parse_ether("3").unwrap()]); + assert_eq!( + res.typed_return.stack, + vec![FixedBytes::left_padding_from(&[3u8])] + ); } } } diff --git a/crates/eval/src/fork.rs b/crates/eval/src/fork.rs index 3b2bedb83..a988e3a7d 100644 --- a/crates/eval/src/fork.rs +++ b/crates/eval/src/fork.rs @@ -408,19 +408,18 @@ impl Forker { #[cfg(test)] mod tests { - use crate::namespace::CreateNamespace; - use rain_interpreter_env::{ - CI_DEPLOY_SEPOLIA_RPC_URL, CI_FORK_BSC_RPC_URL, CI_FORK_POLYGON_RPC_URL, - CI_FORK_SEPOLIA_BLOCK_NUMBER, CI_FORK_SEPOLIA_DEPLOYER_ADDRESS, - }; - use super::*; - use alloy::primitives::U256; + use crate::namespace::CreateNamespace; use alloy::sol; + use alloy::{ + primitives::{FixedBytes, U256}, + providers::Provider, + }; use rain_interpreter_bindings::{ - DeployerISP::{iParserCall, iStoreCall}, - IInterpreterStoreV1::{getCall, setCall}, + DeployerISP::iParserCall, + IInterpreterStoreV3::{getCall, setCall}, }; + use rain_interpreter_test_fixtures::LocalEvm; sol! { interface IERC20 { @@ -431,59 +430,45 @@ mod tests { function transferFrom(address from, address to, uint256 amount) external returns (bool); } } - const USDT_POLYGON: &str = "0xc2132d05d31c914a87c6611c10748aeb04b58e8f"; - const USDT_BSC: &str = "0x55d398326f99059fF775485246999027B3197955"; - const POLYGON_FORK_NUMBER: u64 = 54697866; - const BSC_FORK_NUMBER: u64 = 40531873; - const BSC_ACC: &str = "0xee5B5B923fFcE93A870B3104b7CA09c3db80047A"; - const POLYGON_ACC: &str = "0xF977814e90dA44bFA03b6295A0616a897441aceC"; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_forker_read() { + let local_evm = LocalEvm::new().await; + let deployer = *local_evm.deployer.address(); let args = NewForkedEvm { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_string(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }; + let forker = Forker::new_with_fork(args, None, None).await.unwrap(); let from_address = Address::default(); - let to_address: Address = *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS; + let to_address = deployer; let call = iParserCall {}; let result = forker .alloy_call(from_address, to_address, call, false) .await .unwrap(); let parser_address = result.typed_return; - let expected_address = "0xf14e09601a47552de6abd3a0b165607fafd2b5ba" - .parse::
() - .unwrap(); + let expected_address = *local_evm.parser.address(); assert_eq!(parser_address, expected_address); } #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_forker_write() { + let local_evm = LocalEvm::new().await; let args = NewForkedEvm { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_string(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }; let mut forker = Forker::new_with_fork(args, None, None).await.unwrap(); let from_address = Address::repeat_byte(0x02); - let store_call = iStoreCall {}; - let store_result = forker - .alloy_call( - from_address, - *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS, - store_call, - false, - ) - .await - .unwrap(); - let store_address: Address = store_result.typed_return; + let store_address = *local_evm.store.address(); let namespace = U256::from(1); - let key = U256::from(3); - let value = U256::from(4); + let key = >::left_padding_from(&[3u8]); + let value = >::left_padding_from(&[4u8]); let _set = forker .alloy_call_committing( from_address, @@ -507,7 +492,7 @@ mod tests { store_address, getCall { namespace: fully_quallified_namespace.into(), - key: U256::from(3), + key: >::left_padding_from(&[3u8]), }, false, ) @@ -519,16 +504,19 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_multi_fork_read_write_switch_reset() -> Result<(), ForkCallError> { + let local_evm1 = LocalEvm::new_with_tokens(1).await; + let local_evm1_token = *local_evm1.tokens[0].address(); + let local_evm1_token_holder = local_evm1.anvil.addresses()[0]; let args = NewForkedEvm { - fork_url: CI_FORK_POLYGON_RPC_URL.clone(), - fork_block_number: Some(POLYGON_FORK_NUMBER), + fork_url: local_evm1.url(), + fork_block_number: None, }; let mut forker = Forker::new_with_fork(args, None, None).await.unwrap(); let from_address = Address::default(); - let to_address: Address = USDT_POLYGON.parse::
().unwrap(); + let to_address = local_evm1_token; let call = IERC20::balanceOfCall { - account: POLYGON_ACC.parse::
().unwrap(), + account: local_evm1_token_holder, }; let result = forker .alloy_call(from_address, to_address, call, false) @@ -537,8 +525,8 @@ mod tests { let old_balance = result.typed_return; let polygon_old_balance = result.typed_return; - let from_address = POLYGON_ACC.parse::
().unwrap(); - let to_address: Address = USDT_POLYGON.parse::
().unwrap(); + let from_address = local_evm1_token_holder; + let to_address = local_evm1_token; let send_amount = U256::from(0xffu64); let transfer_call = IERC20::transferCall { to: Address::repeat_byte(0x2), @@ -556,9 +544,9 @@ mod tests { .unwrap(); let from_address = Address::default(); - let to_address: Address = USDT_POLYGON.parse::
().unwrap(); + let to_address = local_evm1_token; let call = IERC20::balanceOfCall { - account: POLYGON_ACC.parse::
().unwrap(), + account: local_evm1_token_holder, }; let result = forker .alloy_call(from_address, to_address, call, false) @@ -569,16 +557,19 @@ mod tests { let polygon_balance = new_balance; // switch fork + let local_evm2 = LocalEvm::new_with_tokens(1).await; + let local_evm2_token = *local_evm2.tokens[0].address(); + let local_evm2_token_holder = local_evm2.anvil.addresses()[0]; let args = NewForkedEvm { - fork_url: CI_FORK_BSC_RPC_URL.to_owned(), - fork_block_number: Some(BSC_FORK_NUMBER), + fork_url: local_evm2.url(), + fork_block_number: None, }; forker.add_or_select(args, None).await?; let from_address = Address::default(); - let to_address: Address = USDT_BSC.parse::
().unwrap(); + let to_address = local_evm2_token; let call = IERC20::balanceOfCall { - account: BSC_ACC.parse::
().unwrap(), + account: local_evm2_token_holder, }; let result = forker .alloy_call(from_address, to_address, call, false) @@ -586,9 +577,9 @@ mod tests { .unwrap(); let old_balance = result.typed_return; - let from_address = BSC_ACC.parse::
().unwrap(); - let to_address: Address = USDT_BSC.parse::
().unwrap(); - let send_amount = U256::from(0xffffffffu64); + let from_address = local_evm2_token_holder; + let to_address = local_evm2_token; + let send_amount = U256::from(0xffu64); let transfer_call = IERC20::transferCall { to: Address::repeat_byte(0x2), amount: send_amount, @@ -605,9 +596,9 @@ mod tests { .unwrap(); let from_address = Address::default(); - let to_address: Address = USDT_BSC.parse::
().unwrap(); + let to_address = local_evm2_token; let call = IERC20::balanceOfCall { - account: BSC_ACC.parse::
().unwrap(), + account: local_evm2_token_holder, }; let result = forker .alloy_call(from_address, to_address, call, false) @@ -616,17 +607,17 @@ mod tests { let new_balance = result.typed_return; assert_eq!(new_balance, old_balance - send_amount); - // switch fork + // switch fork back to fork1 let args = NewForkedEvm { - fork_url: CI_FORK_POLYGON_RPC_URL.clone(), - fork_block_number: Some(POLYGON_FORK_NUMBER), + fork_url: local_evm1.url(), + fork_block_number: None, }; forker.add_or_select(args, None).await?; let from_address = Address::default(); - let to_address: Address = USDT_POLYGON.parse::
().unwrap(); + let to_address = local_evm1_token; let call = IERC20::balanceOfCall { - account: POLYGON_ACC.parse::
().unwrap(), + account: local_evm1_token_holder, }; let result = forker .alloy_call(from_address, to_address, call, false) @@ -636,9 +627,9 @@ mod tests { assert_eq!(balance, polygon_balance); // reset fork - forker.roll_fork(Some(POLYGON_FORK_NUMBER), None)?; + forker.roll_fork(None, None)?; let call = IERC20::balanceOfCall { - account: POLYGON_ACC.parse::
().unwrap(), + account: local_evm1_token_holder, }; let result = forker .alloy_call(from_address, to_address, call, false) @@ -653,27 +644,24 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_fork_rolls() { // we need to roll the fork forwards and check that the env block number is updated + let local_evm = LocalEvm::new().await; + let block_number = local_evm.provider.get_block_number().await.unwrap() - 2; let args = NewForkedEvm { - fork_url: CI_FORK_POLYGON_RPC_URL.clone(), - fork_block_number: Some(POLYGON_FORK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: Some(block_number), }; let mut forker = Forker::new_with_fork(args, None, None).await.unwrap(); // check the env block number is the same as the fork block number - assert_eq!( - forker.executor.env().evm_env.block_env.number, - POLYGON_FORK_NUMBER - ); + assert_eq!(forker.executor.env().evm_env.block_env.number, block_number); // roll the fork forwards by 1 block - forker - .roll_fork(Some(POLYGON_FORK_NUMBER + 1), None) - .unwrap(); + forker.roll_fork(Some(block_number + 1), None).unwrap(); // check the env block number is updated assert_eq!( forker.executor.env().evm_env.block_env.number, - POLYGON_FORK_NUMBER + 1 + block_number + 1 ); } } diff --git a/crates/eval/src/namespace.rs b/crates/eval/src/namespace.rs index 67d6f7978..becc72cf8 100644 --- a/crates/eval/src/namespace.rs +++ b/crates/eval/src/namespace.rs @@ -1,5 +1,5 @@ use alloy::primitives::{Address, B256, U256, keccak256}; -use rain_interpreter_bindings::IInterpreterV2::FullyQualifiedNamespace; +use rain_interpreter_bindings::IInterpreterV4::FullyQualifiedNamespace; pub struct CreateNamespace {} diff --git a/crates/eval/src/trace.rs b/crates/eval/src/trace.rs index 2273354a2..1cfbfabe0 100644 --- a/crates/eval/src/trace.rs +++ b/crates/eval/src/trace.rs @@ -1,7 +1,7 @@ use crate::fork::ForkTypedReturn; use alloy::primitives::{Address, U256}; use foundry_evm::traces::CallTraceArena; -use rain_interpreter_bindings::IInterpreterV3::{eval3Call, eval3Return}; +use rain_interpreter_bindings::IInterpreterV4::{eval4Call, eval4Return}; use thiserror::Error; @@ -48,7 +48,7 @@ impl RainSourceTrace { } /// A struct representing the result of a Rain eval call. Contains the stack, -/// writes, and traces. Can be constructed from a `ForkTypedReturn`. +/// writes, and traces. Can be constructed from a `ForkTypedReturn`. #[derive(Debug, Clone)] pub struct RainEvalResult { pub reverted: bool, @@ -57,9 +57,9 @@ pub struct RainEvalResult { pub traces: Vec, } -impl From> for RainEvalResult { - fn from(typed_return: ForkTypedReturn) -> Self { - let eval3Return { stack, writes } = typed_return.typed_return; +impl From> for RainEvalResult { + fn from(typed_return: ForkTypedReturn) -> Self { + let eval4Return { stack, writes } = typed_return.typed_return; let tracer_address = RAIN_TRACER_ADDRESS.parse::
().unwrap(); let call_trace_arena = typed_return.raw.traces.unwrap().to_owned(); @@ -78,8 +78,8 @@ impl From> for RainEvalResult { RainEvalResult { reverted: typed_return.raw.reverted, - stack, - writes, + stack: stack.into_iter().map(Into::into).collect(), + writes: writes.into_iter().map(Into::into).collect(), traces, } } @@ -167,25 +167,24 @@ mod tests { use super::*; use crate::eval::ForkEvalArgs; use crate::fork::{Forker, NewForkedEvm}; - use alloy::primitives::utils::parse_ether; - use rain_interpreter_bindings::IInterpreterStoreV1::FullyQualifiedNamespace; - use rain_interpreter_env::{ - CI_DEPLOY_SEPOLIA_RPC_URL, CI_FORK_SEPOLIA_BLOCK_NUMBER, CI_FORK_SEPOLIA_DEPLOYER_ADDRESS, - }; + use rain_interpreter_bindings::IInterpreterStoreV3::FullyQualifiedNamespace; + use rain_interpreter_test_fixtures::LocalEvm; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_fork_trace() { - let deployer_address: Address = *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS; + let local_evm = LocalEvm::new().await; + let deployer_address = *local_evm.deployer.address(); let args = NewForkedEvm { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_string(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }; + let fork = Forker::new_with_fork(args, None, None).await.unwrap(); let res = fork .fork_eval(ForkEvalArgs { rainlang_string: r" - a: add(1 2), + a: 3, b: 2, c: 4, _: call<1>(1 2), @@ -193,9 +192,9 @@ mod tests { :set(3 4); a b:, c: call<2>(a b), - d: add(a b); + d: 3; a b:, - c: mul(a b); + c: 2; " .into(), source_index: 0, @@ -203,6 +202,8 @@ mod tests { namespace: FullyQualifiedNamespace::default(), context: vec![], decode_errors: true, + state_overlay: vec![], + inputs: vec![], }) .await .unwrap(); @@ -212,11 +213,11 @@ mod tests { // reverted assert!(!rain_eval_result.reverted); // stack - let expected_stack = vec_i32_to_u256(vec![3, 4, 2, 3]); + let expected_stack = vec![U256::from(3), U256::from(4), U256::from(2), U256::from(3)]; assert_eq!(rain_eval_result.stack, expected_stack); // storage writes - let expected_writes = vec_i32_to_u256(vec![3, 4, 1, 2]); + let expected_writes = vec![U256::from(3), U256::from(4), U256::from(1), U256::from(2)]; assert_eq!(rain_eval_result.writes, expected_writes); // stack traces @@ -224,52 +225,56 @@ mod tests { let trace_0 = RainSourceTrace { parent_source_index: 0, source_index: 0, - stack: vec_i32_to_u256(vec![3, 4, 2, 3]), + stack: vec![U256::from(3), U256::from(4), U256::from(2), U256::from(3)], }; assert_eq!(rain_eval_result.traces[0], trace_0); // 0 1 let trace_1 = RainSourceTrace { parent_source_index: 0, source_index: 1, - stack: vec_i32_to_u256(vec![3, 2, 2, 1]), + stack: vec![U256::from(3), U256::from(2), U256::from(2), U256::from(1)], }; assert_eq!(rain_eval_result.traces[1], trace_1); // 1 2 let trace_2 = RainSourceTrace { parent_source_index: 1, source_index: 2, - stack: vec_i32_to_u256(vec![2, 2, 1]), + stack: vec![U256::from(2), U256::from(2), U256::from(1)], }; assert_eq!(rain_eval_result.traces[2], trace_2); } #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_search_trace_by_path() { + let local_evm = LocalEvm::new().await; + let deployer_address = *local_evm.deployer.address(); let args = NewForkedEvm { - fork_url: CI_DEPLOY_SEPOLIA_RPC_URL.to_string(), - fork_block_number: Some(*CI_FORK_SEPOLIA_BLOCK_NUMBER), + fork_url: local_evm.url(), + fork_block_number: None, }; let fork = Forker::new_with_fork(args, None, None).await.unwrap(); let res = fork .fork_eval(ForkEvalArgs { rainlang_string: r" - a: add(1 2), + a: 3, b: 2, c: 4, _: call<1>(1 2); a b:, c: call<2>(a b), - d: add(a b); + d: 3; a b:, - c: mul(a b); + c: 2; " .into(), source_index: 0, - deployer: *CI_FORK_SEPOLIA_DEPLOYER_ADDRESS, + deployer: deployer_address, namespace: FullyQualifiedNamespace::default(), context: vec![], decode_errors: true, + state_overlay: vec![], + inputs: vec![], }) .await .unwrap(); @@ -278,11 +283,11 @@ mod tests { // search_trace_by_path let trace_0 = rain_eval_result.search_trace_by_path("0.1").unwrap(); - assert_eq!(trace_0, parse_ether("2").unwrap()); + assert_eq!(trace_0, U256::from(2)); let trace_1 = rain_eval_result.search_trace_by_path("0.1.3").unwrap(); - assert_eq!(trace_1, parse_ether("3").unwrap()); + assert_eq!(trace_1, U256::from(3)); let trace_2 = rain_eval_result.search_trace_by_path("0.1.2").unwrap(); - assert_eq!(trace_2, parse_ether("2").unwrap()); + assert_eq!(trace_2, U256::from(2)); // test the various errors // bad trace path @@ -294,10 +299,4 @@ mod tests { let result = rain_eval_result.search_trace_by_path("0.1.12"); assert!(matches!(result, Err(TraceSearchError::TraceNotFound(_)))); } - - fn vec_i32_to_u256(vec: Vec) -> Vec { - vec.iter() - .map(|&x| parse_ether(&x.to_string()).unwrap()) - .collect() - } } diff --git a/crates/test_fixtures/Cargo.toml b/crates/test_fixtures/Cargo.toml new file mode 100644 index 000000000..97562e30b --- /dev/null +++ b/crates/test_fixtures/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rain_interpreter_test_fixtures" +edition.workspace = true +license.workspace = true +homepage.workspace = true +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde_json = { workspace = true } +alloy = { workspace = true, features = ["node-bindings", "sol-types", "rpc-types", "provider-http", "network", "contract", "signer-local"] } + +[target.'cfg(target_family = "wasm")'.dependencies] +getrandom = { version = "0", features = ["js", "js-sys"] } \ No newline at end of file diff --git a/crates/test_fixtures/src/lib.rs b/crates/test_fixtures/src/lib.rs new file mode 100644 index 000000000..4f9d7164d --- /dev/null +++ b/crates/test_fixtures/src/lib.rs @@ -0,0 +1,239 @@ +use alloy::{ + contract::SolCallBuilder, + network::EthereumWallet, + node_bindings::{Anvil, AnvilInstance}, + primitives::{Address, Bytes, U256, utils::parse_units}, + providers::{ + PendingTransactionError, Provider, ProviderBuilder, RootProvider, + fillers::{FillProvider, JoinFill, WalletFiller}, + }, + rpc::types::{TransactionReceipt, TransactionRequest}, + signers::local::PrivateKeySigner, + sol, + sol_types::SolCall, + transports::{RpcError, TransportErrorKind}, +}; +use std::marker::PhantomData; + +sol!( + #![sol(all_derives = true, rpc = true)] + ERC20, "../../out/TestERC20.sol/TestERC20.json" +); + +sol!( + #![sol(all_derives = true, rpc = true)] + Interpreter, + "../../out/Rainterpreter.sol/Rainterpreter.json" +); + +sol!( + #![sol(all_derives = true, rpc = true)] + Store, + "../../out/RainterpreterStore.sol/RainterpreterStore.json" +); + +sol!( + #![sol(all_derives = true, rpc = true)] + Parser, + "../../out/RainterpreterParser.sol/RainterpreterParser.json" +); + +sol!( + #![sol(all_derives = true, rpc = true)] + Deployer, + "../../out/RainterpreterExpressionDeployer.sol/RainterpreterExpressionDeployer.json" +); + +// type aliases for LocalEvm fillers and provider type +pub type LocalEvmFillers = JoinFill< + JoinFill< + alloy::providers::Identity, + JoinFill< + alloy::providers::fillers::GasFiller, + JoinFill< + alloy::providers::fillers::BlobGasFiller, + JoinFill< + alloy::providers::fillers::NonceFiller, + alloy::providers::fillers::ChainIdFiller, + >, + >, + >, + >, + WalletFiller, +>; +pub type LocalEvmProvider = FillProvider; + +/// A local evm instance that wraps an Anvil instance and provider with +/// signers as well as rain contracts already deployed on it. +/// The first signer wallet is the main wallet that would sign any transactions +/// that dont specify a sender (transaction's 'to' field) +pub struct LocalEvm { + /// The Anvil instance, ie the local blockchain + pub anvil: AnvilInstance, + + /// The alloy provider instance of this local blockchain + pub provider: LocalEvmProvider, + + /// Alloy interpreter contract instance deployed on this blockchain + pub interpreter: Interpreter::InterpreterInstance, + + /// Alloy store contract instance deployed on this blockchain + pub store: Store::StoreInstance, + + /// Alloy parser contract instance deployed on this blockchain + pub parser: Parser::ParserInstance, + + /// Alloy expression deployer contract instance deployed on this blockchain + pub deployer: Deployer::DeployerInstance, + + /// Array of alloy ERC20 contract instances deployed on this blockchain + pub tokens: Vec>, + + /// All wallets of this local blockchain that can be used to perform transactions + /// the first wallet is the blockchain's default wallet, ie transactions that dont + /// explicitly specify a sender address will use this as the sender + pub signer_wallets: Vec, +} + +impl LocalEvm { + /// Instantiates this struct with rain contracts deployed and no ERC20 tokens + pub async fn new() -> Self { + let anvil = Anvil::new().try_spawn().unwrap(); + + // set up signers from anvil accounts + let mut signer_wallets = vec![]; + let mut default_signer = + EthereumWallet::from(PrivateKeySigner::from(anvil.keys()[0].clone())); + let other_signer_wallets: Vec = anvil.keys()[1..] + .iter() + .map(|v| EthereumWallet::from(PrivateKeySigner::from(v.clone()))) + .collect(); + + for s in &other_signer_wallets { + default_signer.register_signer(s.default_signer()) + } + signer_wallets.push(default_signer); + signer_wallets.extend(other_signer_wallets); + + // Create a provider with the wallet and fillers + let provider = ProviderBuilder::new() + .wallet(signer_wallets[0].clone()) + .connect_http(anvil.endpoint_url()); + + // deploy rain contracts + let interpreter = Interpreter::deploy(provider.clone()).await.unwrap(); + let store = Store::deploy(provider.clone()).await.unwrap(); + let parser = Parser::deploy(provider.clone()).await.unwrap(); + let config = Deployer::RainterpreterExpressionDeployerConstructionConfigV2 { + interpreter: *interpreter.address(), + parser: *parser.address(), + store: *store.address(), + }; + let deployer = Deployer::deploy(provider.clone(), config).await.unwrap(); + + Self { + anvil, + provider, + interpreter, + store, + parser, + deployer, + tokens: vec![], + signer_wallets, + } + } + + /// Instantiates with number of ERC20 tokens with 18 decimals. + /// Each token after being deployed will mint 1 milion tokens to the + /// default address, which is the first signer wallet of this instance + pub async fn new_with_tokens(tokens_count: u8) -> Self { + let mut local_evm = Self::new().await; + + // deploy tokens contracts and mint 1 milion of each for the default address (first signer wallet) + for i in 1..=tokens_count { + local_evm + .deploy_new_token( + &format!("Token{}", i), + &format!("Token{}", i), + 18, + parse_units("1_000_000", 18).unwrap().into(), + local_evm.anvil.addresses()[0], + ) + .await; + } + local_evm + } + + /// Get the local rpc url of the underlying anvil instance + pub fn url(&self) -> String { + self.anvil.endpoint() + } + + /// Deploys a new ERC20 token with the given arguments + pub async fn deploy_new_token( + &mut self, + name: &str, + symbol: &str, + decimals: u8, + supply: U256, + recipient: Address, + ) -> ERC20::ERC20Instance { + let token = ERC20::deploy( + self.provider.clone(), + name.to_string(), + symbol.to_string(), + decimals, + recipient, + supply, + ) + .await + .unwrap(); + self.tokens.push(token.clone()); + token + } + + /// Sends a contract write transaction to the blockchain and returns the tx receipt + pub async fn send_contract_transaction( + &self, + contract_call: SolCallBuilder<&LocalEvmProvider, PhantomData>, + ) -> Result { + self.provider + .send_transaction(contract_call.into_transaction_request()) + .await? + .get_receipt() + .await + } + + /// Sends (write call) a raw transaction request to the blockchain and returns the tx receipt + pub async fn send_transaction( + &self, + tx: TransactionRequest, + ) -> Result { + self.provider + .send_transaction(tx) + .await? + .get_receipt() + .await + } + + /// Calls (readonly call) contract method and returns the decoded result + pub async fn call_contract( + &self, + contract_call: SolCallBuilder<&LocalEvmProvider, PhantomData>, + ) -> Result, RpcError> { + Ok(T::abi_decode_returns( + &self + .provider + .call(contract_call.into_transaction_request()) + .await?, + )) + } + + /// Calls (readonly call) a raw transaction and returns the result + pub async fn call( + &self, + tx: &TransactionRequest, + ) -> Result> { + self.provider.call(tx.clone()).await + } +} diff --git a/test/utils/TestERC20.sol b/test/utils/TestERC20.sol new file mode 100644 index 000000000..dfd880f0f --- /dev/null +++ b/test/utils/TestERC20.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; + +contract TestERC20 is ERC20 { + uint8 private _decimals; + + constructor(string memory name_, string memory symbol_, uint8 decimals_, address recipient_, uint256 supply_) + ERC20(name_, symbol_) + { + _decimals = decimals_; + _mint(recipient_, supply_); + } + + function decimals() public view virtual override returns (uint8) { + return _decimals; + } +} From ffd2c54c860cf986497f0cc0e76326a576144577 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Fri, 6 Jun 2025 21:46:25 +0000 Subject: [PATCH 02/16] Update TestERC20.sol --- test/utils/TestERC20.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/test/utils/TestERC20.sol b/test/utils/TestERC20.sol index dfd880f0f..c605edccb 100644 --- a/test/utils/TestERC20.sol +++ b/test/utils/TestERC20.sol @@ -3,6 +3,7 @@ pragma solidity =0.8.25; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; +// a erc20 contract for testing purposes in `test_fixtures` crate to deploy erc20 tokens on the local evm contract TestERC20 is ERC20 { uint8 private _decimals; From 4359b73ec501c153157f683d0896780ea377ece1 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Fri, 6 Jun 2025 21:46:42 +0000 Subject: [PATCH 03/16] Update TestERC20.sol --- test/utils/TestERC20.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/TestERC20.sol b/test/utils/TestERC20.sol index c605edccb..68c5cf188 100644 --- a/test/utils/TestERC20.sol +++ b/test/utils/TestERC20.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.25; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; -// a erc20 contract for testing purposes in `test_fixtures` crate to deploy erc20 tokens on the local evm +// an erc20 contract for testing purposes in `test_fixtures` crate to deploy erc20 tokens on the local evm contract TestERC20 is ERC20 { uint8 private _decimals; From f1fa512c75724e42fd885a83299ea12b5e5cd5d8 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Fri, 6 Jun 2025 21:58:33 +0000 Subject: [PATCH 04/16] fmt --- crates/test_fixtures/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/test_fixtures/Cargo.toml b/crates/test_fixtures/Cargo.toml index 97562e30b..8163ffbd7 100644 --- a/crates/test_fixtures/Cargo.toml +++ b/crates/test_fixtures/Cargo.toml @@ -12,4 +12,4 @@ serde_json = { workspace = true } alloy = { workspace = true, features = ["node-bindings", "sol-types", "rpc-types", "provider-http", "network", "contract", "signer-local"] } [target.'cfg(target_family = "wasm")'.dependencies] -getrandom = { version = "0", features = ["js", "js-sys"] } \ No newline at end of file +getrandom = { version = "0", features = ["js", "js-sys"] } From 955a67afc57cf0382478dcf50b0cdd0ce3a6e530 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Fri, 6 Jun 2025 22:08:12 +0000 Subject: [PATCH 05/16] Update eval.rs --- crates/cli/src/commands/eval.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/commands/eval.rs b/crates/cli/src/commands/eval.rs index c8009bf75..0df131e81 100644 --- a/crates/cli/src/commands/eval.rs +++ b/crates/cli/src/commands/eval.rs @@ -36,6 +36,14 @@ pub struct ForkEvalCliArgs { #[arg(short, long, help = "Decode errors using the openchain.xyz database")] pub decode_errors: bool, + + // Accept inputs vector as array of uint256 + #[arg(short, long, help = "The inputs vectore")] + pub inputs: Vec, + + // Accept state overlay vector as array of uint256 + #[arg( short, long, help = "The state overlay vector")] + pub state_overlay: Vec, } impl TryFrom for ForkEvalArgs { @@ -62,8 +70,8 @@ impl TryFrom for ForkEvalArgs { namespace: FullyQualifiedNamespace::from(namespace), context, decode_errors: args.decode_errors, - inputs: vec![], - state_overlay: vec![], + inputs: args.inputs, + state_overlay: args.state_overlay, }) } } @@ -142,6 +150,8 @@ mod tests { namespace: "0x123".into(), context: vec!["0x06,99".into()], decode_errors: true, + inputs: vec![], + state_overlay: vec![], }, }; From 051d98ab1728f0b02d70a4ca978a60243cd5f226 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Fri, 6 Jun 2025 22:14:55 +0000 Subject: [PATCH 06/16] Update lib.rs --- crates/dispair/src/lib.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/crates/dispair/src/lib.rs b/crates/dispair/src/lib.rs index 3e76e5380..66b32731d 100644 --- a/crates/dispair/src/lib.rs +++ b/crates/dispair/src/lib.rs @@ -79,16 +79,10 @@ mod tests { .await .expect("Failed to create ReadableClient"); let dispair = DISPair::from_deployer(deployer, client).await.unwrap(); - let expected = DISPair { - deployer, - interpreter: *local_evm.interpreter.address(), - store: *local_evm.store.address(), - parser: *local_evm.parser.address(), - }; - assert_eq!(dispair.deployer, expected.deployer); - assert_eq!(dispair.interpreter, expected.interpreter); - assert_eq!(dispair.store, expected.store); - assert_eq!(dispair.parser, expected.parser); + assert_eq!(dispair.deployer, deployer); + assert_eq!(dispair.interpreter, *local_evm.interpreter.address(),); + assert_eq!(dispair.store, *local_evm.store.address()); + assert_eq!(dispair.parser, *local_evm.parser.address(),); } } From f17bb0a8f249d92514a5f39d2e6ec2795f1b372f Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Fri, 6 Jun 2025 22:15:17 +0000 Subject: [PATCH 07/16] fmt --- crates/cli/src/commands/eval.rs | 2 +- crates/dispair/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/cli/src/commands/eval.rs b/crates/cli/src/commands/eval.rs index 0df131e81..be81ea675 100644 --- a/crates/cli/src/commands/eval.rs +++ b/crates/cli/src/commands/eval.rs @@ -42,7 +42,7 @@ pub struct ForkEvalCliArgs { pub inputs: Vec, // Accept state overlay vector as array of uint256 - #[arg( short, long, help = "The state overlay vector")] + #[arg(short, long, help = "The state overlay vector")] pub state_overlay: Vec, } diff --git a/crates/dispair/src/lib.rs b/crates/dispair/src/lib.rs index 66b32731d..b128ab285 100644 --- a/crates/dispair/src/lib.rs +++ b/crates/dispair/src/lib.rs @@ -81,8 +81,8 @@ mod tests { let dispair = DISPair::from_deployer(deployer, client).await.unwrap(); assert_eq!(dispair.deployer, deployer); - assert_eq!(dispair.interpreter, *local_evm.interpreter.address(),); + assert_eq!(dispair.interpreter, *local_evm.interpreter.address()); assert_eq!(dispair.store, *local_evm.store.address()); - assert_eq!(dispair.parser, *local_evm.parser.address(),); + assert_eq!(dispair.parser, *local_evm.parser.address()); } } From 3de0ef941e5aae0cc8f8fa2a366a0ffd8be5b795 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sat, 7 Jun 2025 02:22:21 +0000 Subject: [PATCH 08/16] update --- crates/eval/src/eval.rs | 3 +-- crates/test_fixtures/src/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 859736baa..573b96b61 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -161,8 +161,7 @@ mod tests { fork_block_number: None, }; let fork = Forker::new_with_fork(args, None, None).await.unwrap(); - let x = local_evm.deployer.iInterpreter().call().await.unwrap(); - println!("{}", x); + let res = fork .fork_parse(ForkParseArgs { rainlang_string: r"_: 1;".to_owned(), diff --git a/crates/test_fixtures/src/lib.rs b/crates/test_fixtures/src/lib.rs index 4f9d7164d..92f31c16b 100644 --- a/crates/test_fixtures/src/lib.rs +++ b/crates/test_fixtures/src/lib.rs @@ -44,7 +44,7 @@ sol!( "../../out/RainterpreterExpressionDeployer.sol/RainterpreterExpressionDeployer.json" ); -// type aliases for LocalEvm fillers and provider type +// type aliases for LocalEvm fillers and provider pub type LocalEvmFillers = JoinFill< JoinFill< alloy::providers::Identity, @@ -63,7 +63,7 @@ pub type LocalEvmFillers = JoinFill< >; pub type LocalEvmProvider = FillProvider; -/// A local evm instance that wraps an Anvil instance and provider with +/// LocalEvm is a thin wrapper around Anvil instance and alloy provider with /// signers as well as rain contracts already deployed on it. /// The first signer wallet is the main wallet that would sign any transactions /// that dont specify a sender (transaction's 'to' field) @@ -89,7 +89,7 @@ pub struct LocalEvm { /// Array of alloy ERC20 contract instances deployed on this blockchain pub tokens: Vec>, - /// All wallets of this local blockchain that can be used to perform transactions + /// All wallets of this local blockchain that can be used to perform transactions. /// the first wallet is the blockchain's default wallet, ie transactions that dont /// explicitly specify a sender address will use this as the sender pub signer_wallets: Vec, From 84b63e089ae2c63b51df9e8d092d0192409ad1c6 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:18:46 +0000 Subject: [PATCH 09/16] update --- .env.example | 5 --- .github/workflows/rainix.yaml | 5 --- crates/cli/src/commands/eval.rs | 24 +++++++++----- crates/eval/src/eval.rs | 24 +++++++------- crates/test_fixtures/src/lib.rs | 57 +++++++++++++-------------------- 5 files changed, 52 insertions(+), 63 deletions(-) delete mode 100644 .env.example diff --git a/.env.example b/.env.example deleted file mode 100644 index e04835c54..000000000 --- a/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -CI_DEPLOY_SEPOLIA_RPC_URL= -CI_FORK_SEPOLIA_BLOCK_NUMBER= -CI_FORK_SEPOLIA_DEPLOYER_ADDRESS= -CI_FORK_POLYGON_RPC_URL= -CI_FORK_BSC_RPC_URL= \ No newline at end of file diff --git a/.github/workflows/rainix.yaml b/.github/workflows/rainix.yaml index f46beb136..819e2c592 100644 --- a/.github/workflows/rainix.yaml +++ b/.github/workflows/rainix.yaml @@ -62,9 +62,4 @@ jobs: DEPLOY_BROADCAST: "" DEPLOY_VERIFIER: "" DEPLOY_METABOARD_ADDRESS: ${{ vars.CI_DEPLOY_SEPOLIA_METABOARD_ADDRESS }} - CI_FORK_SEPOLIA_BLOCK_NUMBER: ${{ vars.CI_FORK_SEPOLIA_BLOCK_NUMBER }} - CI_FORK_SEPOLIA_DEPLOYER_ADDRESS: ${{ vars.CI_FORK_SEPOLIA_DEPLOYER_ADDRESS }} - CI_DEPLOY_SEPOLIA_RPC_URL: ${{ secrets.CI_DEPLOY_SEPOLIA_RPC_URL || vars.CI_DEPLOY_SEPOLIA_RPC_URL }} - CI_FORK_POLYGON_RPC_URL: ${{ secrets.CI_FORK_POLYGON_RPC_URL || vars.CI_FORK_POLYGON_RPC_URL }} - CI_FORK_BSC_RPC_URL: ${{ secrets.CI_FORK_BSC_RPC_URL || vars.CI_FORK_BSC_RPC_URL }} run: nix develop -c ${{ matrix.task }} diff --git a/crates/cli/src/commands/eval.rs b/crates/cli/src/commands/eval.rs index be81ea675..55fc5b3f0 100644 --- a/crates/cli/src/commands/eval.rs +++ b/crates/cli/src/commands/eval.rs @@ -38,12 +38,20 @@ pub struct ForkEvalCliArgs { pub decode_errors: bool, // Accept inputs vector as array of uint256 - #[arg(short, long, help = "The inputs vectore")] - pub inputs: Vec, + #[arg( + short, + long, + help = "The inputs vector which are prepopulated stack items" + )] + pub inputs: Option>, // Accept state overlay vector as array of uint256 - #[arg(short, long, help = "The state overlay vector")] - pub state_overlay: Vec, + #[arg( + short, + long, + help = "The state overlay vector which applies to the state before evaluation to facilitate 'what if' analysis" + )] + pub state_overlay: Option>, } impl TryFrom for ForkEvalArgs { @@ -70,8 +78,8 @@ impl TryFrom for ForkEvalArgs { namespace: FullyQualifiedNamespace::from(namespace), context, decode_errors: args.decode_errors, - inputs: args.inputs, - state_overlay: args.state_overlay, + inputs: args.inputs.unwrap_or_default(), + state_overlay: args.state_overlay.unwrap_or_default(), }) } } @@ -150,8 +158,8 @@ mod tests { namespace: "0x123".into(), context: vec!["0x06,99".into()], decode_errors: true, - inputs: vec![], - state_overlay: vec![], + inputs: None, + state_overlay: None, }, }; diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 573b96b61..367d51129 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -7,21 +7,34 @@ use rain_interpreter_bindings::IInterpreterV4::{EvalV4, eval4Call}; use rain_interpreter_bindings::IParserV2::parse2Call; #[derive(Debug, Clone)] +/// Arguments for evaluating a Rainlang string in a forked EVM context pub struct ForkEvalArgs { + /// The Rainalang string to evaluate pub rainlang_string: String, + /// The source index pub source_index: u16, + /// The address of the deployer pub deployer: Address, + /// The fully qualified namespace pub namespace: FullyQualifiedNamespace, + /// The context matrix pub context: Vec>, + /// Whether to decode errors from the registry pub decode_errors: bool, + /// Inputs vector which are prepopulated stack items pub inputs: Vec, + /// Applies to the state before evaluation to facilitate "what if" analysis pub state_overlay: Vec, } #[derive(Debug, Clone)] +/// Arguments for parsing a Rainlang string in a forked EVM context pub struct ForkParseArgs { + /// The Rainlang string to parse pub rainlang_string: String, + /// The address of the deployer pub deployer: Address, + /// Whether to decode errors from the registry pub decode_errors: bool, } @@ -69,17 +82,6 @@ impl Forker { } /// Evaluates the Rain language string and returns the evaluation result. - /// - /// # Arguments - /// * `rainlang_string` - The Rainalang string to evaluate. - /// * `source_index` - The source index. - /// * `deployer` - The address of the deployer. - /// * `namespace` - The fully qualified namespace. - /// * `context` - The context vector. - /// * `inputs` - The inputs vector. - /// * `state_overlay` - The state_overlay vector. - /// * `decode_errors` - Whether to decode errors from registry or not - /// /// # Returns /// /// The typed return of the eval, plus Foundry's RawCallResult struct, including the trace. diff --git a/crates/test_fixtures/src/lib.rs b/crates/test_fixtures/src/lib.rs index 92f31c16b..0608d4e85 100644 --- a/crates/test_fixtures/src/lib.rs +++ b/crates/test_fixtures/src/lib.rs @@ -1,13 +1,15 @@ use alloy::{ contract::SolCallBuilder, - network::EthereumWallet, + network::{AnyNetwork, AnyReceiptEnvelope, EthereumWallet}, node_bindings::{Anvil, AnvilInstance}, primitives::{Address, Bytes, U256, utils::parse_units}, providers::{ PendingTransactionError, Provider, ProviderBuilder, RootProvider, fillers::{FillProvider, JoinFill, WalletFiller}, + utils::JoinedRecommendedFillers, }, - rpc::types::{TransactionReceipt, TransactionRequest}, + rpc::types::{Log, TransactionReceipt, TransactionRequest}, + serde::WithOtherFields, signers::local::PrivateKeySigner, sol, sol_types::SolCall, @@ -45,23 +47,8 @@ sol!( ); // type aliases for LocalEvm fillers and provider -pub type LocalEvmFillers = JoinFill< - JoinFill< - alloy::providers::Identity, - JoinFill< - alloy::providers::fillers::GasFiller, - JoinFill< - alloy::providers::fillers::BlobGasFiller, - JoinFill< - alloy::providers::fillers::NonceFiller, - alloy::providers::fillers::ChainIdFiller, - >, - >, - >, - >, - WalletFiller, ->; -pub type LocalEvmProvider = FillProvider; +pub type LocalEvmFillers = JoinFill>; +pub type LocalEvmProvider = FillProvider, AnyNetwork>; /// LocalEvm is a thin wrapper around Anvil instance and alloy provider with /// signers as well as rain contracts already deployed on it. @@ -75,19 +62,19 @@ pub struct LocalEvm { pub provider: LocalEvmProvider, /// Alloy interpreter contract instance deployed on this blockchain - pub interpreter: Interpreter::InterpreterInstance, + pub interpreter: Interpreter::InterpreterInstance, /// Alloy store contract instance deployed on this blockchain - pub store: Store::StoreInstance, + pub store: Store::StoreInstance, /// Alloy parser contract instance deployed on this blockchain - pub parser: Parser::ParserInstance, + pub parser: Parser::ParserInstance, /// Alloy expression deployer contract instance deployed on this blockchain - pub deployer: Deployer::DeployerInstance, + pub deployer: Deployer::DeployerInstance, /// Array of alloy ERC20 contract instances deployed on this blockchain - pub tokens: Vec>, + pub tokens: Vec>, /// All wallets of this local blockchain that can be used to perform transactions. /// the first wallet is the blockchain's default wallet, ie transactions that dont @@ -115,8 +102,8 @@ impl LocalEvm { signer_wallets.push(default_signer); signer_wallets.extend(other_signer_wallets); - // Create a provider with the wallet and fillers - let provider = ProviderBuilder::new() + // Create a provider with the wallet and fillers with http endpoint of the anvil instance + let provider = ProviderBuilder::new_with_network::() .wallet(signer_wallets[0].clone()) .connect_http(anvil.endpoint_url()); @@ -177,7 +164,7 @@ impl LocalEvm { decimals: u8, supply: U256, recipient: Address, - ) -> ERC20::ERC20Instance { + ) -> ERC20::ERC20Instance { let token = ERC20::deploy( self.provider.clone(), name.to_string(), @@ -195,8 +182,9 @@ impl LocalEvm { /// Sends a contract write transaction to the blockchain and returns the tx receipt pub async fn send_contract_transaction( &self, - contract_call: SolCallBuilder<&LocalEvmProvider, PhantomData>, - ) -> Result { + contract_call: SolCallBuilder<&LocalEvmProvider, PhantomData, AnyNetwork>, + ) -> Result>>, PendingTransactionError> + { self.provider .send_transaction(contract_call.into_transaction_request()) .await? @@ -207,8 +195,9 @@ impl LocalEvm { /// Sends (write call) a raw transaction request to the blockchain and returns the tx receipt pub async fn send_transaction( &self, - tx: TransactionRequest, - ) -> Result { + tx: WithOtherFields, + ) -> Result>>, PendingTransactionError> + { self.provider .send_transaction(tx) .await? @@ -219,7 +208,7 @@ impl LocalEvm { /// Calls (readonly call) contract method and returns the decoded result pub async fn call_contract( &self, - contract_call: SolCallBuilder<&LocalEvmProvider, PhantomData>, + contract_call: SolCallBuilder<&LocalEvmProvider, PhantomData, AnyNetwork>, ) -> Result, RpcError> { Ok(T::abi_decode_returns( &self @@ -232,8 +221,8 @@ impl LocalEvm { /// Calls (readonly call) a raw transaction and returns the result pub async fn call( &self, - tx: &TransactionRequest, + tx: WithOtherFields, ) -> Result> { - self.provider.call(tx.clone()).await + self.provider.call(tx).await } } From 564b36352fcac2610f25a279de5cedfc8d8eee96 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:24:50 +0000 Subject: [PATCH 10/16] Update eval.rs --- crates/eval/src/eval.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 367d51129..32cd6f76c 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -11,13 +11,13 @@ use rain_interpreter_bindings::IParserV2::parse2Call; pub struct ForkEvalArgs { /// The Rainalang string to evaluate pub rainlang_string: String, - /// The source index + /// The source index of the rainlang to evaluate pub source_index: u16, /// The address of the deployer pub deployer: Address, /// The fully qualified namespace pub namespace: FullyQualifiedNamespace, - /// The context matrix + /// The context matrix, that will be available in "context" word pub context: Vec>, /// Whether to decode errors from the registry pub decode_errors: bool, From 575bf6447bb1a177153c718141e6b24e50a654f4 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:25:21 +0000 Subject: [PATCH 11/16] Update eval.rs --- crates/eval/src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 32cd6f76c..7187bdf47 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -17,7 +17,7 @@ pub struct ForkEvalArgs { pub deployer: Address, /// The fully qualified namespace pub namespace: FullyQualifiedNamespace, - /// The context matrix, that will be available in "context" word + /// The context matrix, that will be available in "context" word and its aliases pub context: Vec>, /// Whether to decode errors from the registry pub decode_errors: bool, From c63e9e7e826dfed46b14778e8da602b9f931230c Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:27:10 +0000 Subject: [PATCH 12/16] Update eval.rs --- crates/eval/src/eval.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 7187bdf47..6d65223e5 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -82,6 +82,10 @@ impl Forker { } /// Evaluates the Rain language string and returns the evaluation result. + /// + /// # Arguments + /// * `args` - The arguments for the evaluation + /// /// # Returns /// /// The typed return of the eval, plus Foundry's RawCallResult struct, including the trace. From c960930da5c53b4baf1245386ff828b86ef4f03a Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:27:36 +0000 Subject: [PATCH 13/16] Update eval.rs --- crates/eval/src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 6d65223e5..32219014d 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -84,7 +84,7 @@ impl Forker { /// Evaluates the Rain language string and returns the evaluation result. /// /// # Arguments - /// * `args` - The arguments for the evaluation + /// * `args` - The fork eval arguments for the evaluation /// /// # Returns /// From e96364dd9fd93ef1fa309d9285bacd93cbfa0c7c Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:29:26 +0000 Subject: [PATCH 14/16] Update eval.rs --- crates/eval/src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 32219014d..899c3bf04 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -205,7 +205,7 @@ mod tests { .unwrap(); // stack - let expected_stack: Vec> = vec![FixedBytes::left_padding_from(&[3u8])]; + let expected_stack = vec![>::left_padding_from(&[3u8])]; assert_eq!(res.typed_return.stack, expected_stack); // storage writes From b63c2957af0c7384e588df0e53127c3ff1363c2b Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:32:06 +0000 Subject: [PATCH 15/16] Update eval.rs --- crates/eval/src/eval.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/eval/src/eval.rs b/crates/eval/src/eval.rs index 899c3bf04..7a705513c 100644 --- a/crates/eval/src/eval.rs +++ b/crates/eval/src/eval.rs @@ -154,9 +154,8 @@ mod tests { use super::*; use crate::fork::NewForkedEvm; use alloy::primitives::FixedBytes; - use foundry_evm::traces::CallTraceArena; use rain_interpreter_test_fixtures::LocalEvm; - use std::sync::Arc; + use std::{ops::Deref, sync::Arc}; #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_fork_parse() { @@ -217,8 +216,7 @@ mod tests { expected_stack_trace.append(&mut >::left_padding_from(&[3u8]).to_vec()); let sparsed_trace_arena = res.raw.traces.unwrap(); - let source_index_zero_trace = ::clone(&sparsed_trace_arena) - .into_nodes()[1] + let source_index_zero_trace = sparsed_trace_arena.deref().clone().into_nodes()[1] .to_owned() .trace; assert_eq!(source_index_zero_trace.data.to_vec(), expected_stack_trace); From d3141a613fc50e91cafd36b4a6b6371d2323e77b Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 8 Jun 2025 00:33:31 +0000 Subject: [PATCH 16/16] Update trace.rs --- crates/eval/src/trace.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/eval/src/trace.rs b/crates/eval/src/trace.rs index 1cfbfabe0..67a2c4b76 100644 --- a/crates/eval/src/trace.rs +++ b/crates/eval/src/trace.rs @@ -1,6 +1,7 @@ +use std::ops::Deref; + use crate::fork::ForkTypedReturn; use alloy::primitives::{Address, U256}; -use foundry_evm::traces::CallTraceArena; use rain_interpreter_bindings::IInterpreterV4::{eval4Call, eval4Return}; use thiserror::Error; @@ -63,7 +64,9 @@ impl From> for RainEvalResult { let tracer_address = RAIN_TRACER_ADDRESS.parse::
().unwrap(); let call_trace_arena = typed_return.raw.traces.unwrap().to_owned(); - let mut traces: Vec = ::clone(&call_trace_arena) + let mut traces: Vec = call_trace_arena + .deref() + .clone() .into_nodes() .iter() .filter_map(|trace_node| {