diff --git a/protocol-testing/Cargo.lock b/protocol-testing/Cargo.lock index 921f406..950feda 100644 --- a/protocol-testing/Cargo.lock +++ b/protocol-testing/Cargo.lock @@ -7810,8 +7810,8 @@ dependencies = [ [[package]] name = "tycho-simulation" -version = "0.155.2" -source = "git+https://github.com/propeller-heads/tycho-simulation.git?tag=0.155.2#b1f5a6e2b7c70a2871a1dd9e19f53d48421be5c8" +version = "0.156.0" +source = "git+https://github.com/propeller-heads/tycho-simulation.git?tag=0.156.0#1983a787440e8ae757626d808a6e619baffc52f2" dependencies = [ "alloy", "async-stream", diff --git a/protocol-testing/Cargo.toml b/protocol-testing/Cargo.toml index 94ce2aa..2864da7 100644 --- a/protocol-testing/Cargo.toml +++ b/protocol-testing/Cargo.toml @@ -11,7 +11,7 @@ tracing = "0.1.37" # Tycho dependencies tycho-common = "0.82.0" tycho-client = "0.82.0" -tycho-simulation = { git = "https://github.com/propeller-heads/tycho-simulation.git", tag = "0.155.2", features = ["evm"] } +tycho-simulation = { git = "https://github.com/propeller-heads/tycho-simulation.git", tag = "0.156.0", features = ["evm"] } ## TODO: for local development #tycho-simulation = { path = "../../tycho-simulation" } # EVM dependencies diff --git a/protocol-testing/src/config.rs b/protocol-testing/src/config.rs index 6b5c262..da2d045 100644 --- a/protocol-testing/src/config.rs +++ b/protocol-testing/src/config.rs @@ -48,8 +48,8 @@ impl ProtocolComponentExpectation { match other_value { Some(other_value) => { if value != other_value { - let self_value = format!("{:?}", value); - let other_value = format!("{:?}", other_value); + let self_value = format!("{value:?}"); + let other_value = format!("{other_value:?}"); let diff = self.format_diff( "static_attributes", &self_value, diff --git a/protocol-testing/src/test_runner.rs b/protocol-testing/src/test_runner.rs index 6a30a5e..8336d26 100644 --- a/protocol-testing/src/test_runner.rs +++ b/protocol-testing/src/test_runner.rs @@ -21,6 +21,7 @@ use tycho_simulation::{ engine_db::tycho_db::PreCachedDB, protocol::{u256_num::bytes_to_u256, vm::state::EVMPoolState}, }, + protocol::models::DecoderContext, tycho_client::feed::{ synchronizer::{ComponentWithState, Snapshot, StateSyncMessage}, FeedMessage, @@ -28,6 +29,7 @@ use tycho_simulation::{ }; use crate::{ + adapter_builder::AdapterContractBuilder, config::{IntegrationTest, IntegrationTestsConfig, ProtocolComponentWithTestConfig}, rpc::RPCProvider, tycho_rpc::TychoClient, @@ -40,12 +42,17 @@ pub struct TestRunner { db_url: String, vm_traces: bool, substreams_path: PathBuf, + adapter_contract_builder: AdapterContractBuilder, } impl TestRunner { pub fn new(package: String, tycho_logs: bool, db_url: String, vm_traces: bool) -> Self { let substreams_path = PathBuf::from("../substreams").join(&package); - Self { tycho_logs, db_url, vm_traces, substreams_path } + let repo_root = env::current_dir().expect("Failed to get current directory"); + let evm_path = repo_root.join("../evm"); + let adapter_contract_builder = + AdapterContractBuilder::new(evm_path.to_string_lossy().to_string()); + Self { tycho_logs, db_url, vm_traces, substreams_path, adapter_contract_builder } } pub fn run_tests(&self) -> miette::Result<()> { @@ -96,7 +103,7 @@ impl TestRunner { fn parse_config(config_yaml_path: &PathBuf) -> miette::Result { info!("Config YAML: {}", config_yaml_path.display()); - let yaml = Yaml::file(&config_yaml_path); + let yaml = Yaml::file(config_yaml_path); let figment = Figment::new().merge(yaml); let config = figment .extract::() @@ -145,7 +152,16 @@ impl TestRunner { .wrap_err("Failed to run Tycho")?; let _ = tycho_runner.run_with_rpc_server( - validate_state, + |expected_components, start_block, stop_block, skip_balance_check| { + validate_state( + expected_components, + start_block, + stop_block, + skip_balance_check, + config, + &self.adapter_contract_builder, + ) + }, &test.expected_components, test.start_block, test.stop_block, @@ -176,6 +192,8 @@ fn validate_state( start_block: u64, stop_block: u64, skip_balance_check: bool, + config: &IntegrationTestsConfig, + adapter_contract_builder: &AdapterContractBuilder, ) -> miette::Result<()> { let rt = Runtime::new().unwrap(); @@ -263,8 +281,42 @@ fn validate_state( } // Step 3: Run Tycho Simulation + + // Build/find the adapter contract + let adapter_contract_path = + match adapter_contract_builder.find_contract(&config.adapter_contract) { + Ok(path) => { + info!("Found adapter contract at: {}", path.display()); + path + } + Err(_) => { + info!("Adapter contract not found, building it..."); + adapter_contract_builder + .build_target( + &config.adapter_contract, + config + .adapter_build_signature + .as_deref(), + config.adapter_build_args.as_deref(), + ) + .wrap_err("Failed to build adapter contract")? + } + }; + + info!("Using adapter contract: {}", adapter_contract_path.display()); + let adapter_contract_path_str: &str = adapter_contract_path.to_str().unwrap(); + let mut decoder = TychoStreamDecoder::new(); - decoder.register_decoder::>("test_protocol"); + let decoder_context = DecoderContext::new().vm_adapter_path(adapter_contract_path_str); + decoder.register_decoder_with_context::>( + "test_protocol", + decoder_context, + ); + + // NOTE: Once tycho-simulation is updated, you can use the new API like this: + // use tycho_simulation::protocol::models::DecoderContext; + // let context = DecoderContext::new().vm_adapter_path(adapter_contract_path_str); + // decoder.register_decoder_with_context::>("test_protocol", context); // Mock a stream message, with only a Snapshot and no deltas let mut states: HashMap = HashMap::new(); @@ -325,9 +377,6 @@ fn validate_state( .or_insert_with(|| comp.tokens.clone()); } - // This is where we get blocked. Currently, Tycho Simulation expects the runtime to be - // prebuild and accessible from TychoSim - we should allow passing it when parsing the block - // TODO: Since we don't have balances on the VM State, we could try to use Limits, otherwise ask // the user to specify a set of values on the YAML file. for (id, state) in block_msg.states.iter() { diff --git a/protocol-testing/src/tycho_rpc.rs b/protocol-testing/src/tycho_rpc.rs index d9b0fe6..65e9436 100644 --- a/protocol-testing/src/tycho_rpc.rs +++ b/protocol-testing/src/tycho_rpc.rs @@ -21,8 +21,8 @@ pub enum RpcError { impl fmt::Display for RpcError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - RpcError::ClientError(msg) => write!(f, "RPC client error: {}", msg), - RpcError::ResponseError(msg) => write!(f, "RPC response error: {}", msg), + RpcError::ClientError(msg) => write!(f, "RPC client error: {msg}"), + RpcError::ResponseError(msg) => write!(f, "RPC response error: {msg}"), } } } diff --git a/protocol-testing/src/tycho_runner.rs b/protocol-testing/src/tycho_runner.rs index b59136e..be611ef 100644 --- a/protocol-testing/src/tycho_runner.rs +++ b/protocol-testing/src/tycho_runner.rs @@ -129,10 +129,12 @@ impl TychoRunner { debug!("Received termination message, stopping RPC server..."); cmd.kill() .expect("Failed to kill RPC server"); + let _ = cmd.wait(); } Err(_) => { // Channel closed, terminate anyway let _ = cmd.kill(); + let _ = cmd.wait(); } } }); @@ -160,7 +162,7 @@ impl TychoRunner { thread::spawn(move || { let reader = BufReader::new(stdout); for line in reader.lines().map_while(Result::ok) { - println!("{}", line); + println!("{line}"); } }); } @@ -169,7 +171,7 @@ impl TychoRunner { thread::spawn(move || { let reader = BufReader::new(stderr); for line in reader.lines().map_while(Result::ok) { - eprintln!("{}", line); + eprintln!("{line}"); } }); } diff --git a/protocol-testing/src/utils.rs b/protocol-testing/src/utils.rs index 4810928..2463bd0 100644 --- a/protocol-testing/src/utils.rs +++ b/protocol-testing/src/utils.rs @@ -48,8 +48,7 @@ pub fn build_spkg(yaml_file_path: &PathBuf, initial_block: u64) -> miette::Resul .expect("Version not found on YAML"); let package_version = binding.as_str().unwrap_or(""); - - let spkg_name = format!("{}/{}-{}.spkg", parent_dir, package_name, package_version); + let spkg_name = format!("{parent_dir}/{package_name}-{package_version}.spkg"); // Write the modified YAML back to the file let yaml_string = serde_yaml::to_string(&data).into_diagnostic()?;