Compare commits

...

9 Commits

Author SHA1 Message Date
activecoder10 77606bf5de Added bail to stop execution when we have an error during deployment 2025-07-09 11:03:50 +03:00
activecoder10 f1a1ae1e9f Added new changes to format 2025-07-08 18:00:48 +03:00
activecoder10 60831d980d Fixed format 2025-07-08 17:49:07 +03:00
activecoder10 08d29f41ed Fixed format issues 2025-07-08 16:06:15 +03:00
activecoder10 36acad927d Added unit tests for ABI parameter extraction logic 2025-07-08 15:59:49 +03:00
activecoder10 9d2084834c Small refactoring 2025-07-07 12:28:05 +03:00
activecoder10 c5ab27ed82 Refactored dependencies 2025-07-04 12:37:56 +03:00
activecoder10 a0279f0c0c Added logic for ABI 2025-07-04 12:09:21 +03:00
activecoder10 48ed8db4db Parsed ABI field in order to get method parameter 2025-07-03 15:12:23 +03:00
8 changed files with 457 additions and 44 deletions
Generated
+19 -16
View File
@@ -260,9 +260,9 @@ dependencies = [
[[package]] [[package]]
name = "alloy-json-abi" name = "alloy-json-abi"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ccaa79753d7bf15f06399ea76922afbfaf8d18bebed9e8fc452984b4a90dcc9" checksum = "15516116086325c157c18261d768a20677f0f699348000ed391d4ad0dcb82530"
dependencies = [ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-sol-type-parser", "alloy-sol-type-parser",
@@ -325,9 +325,9 @@ dependencies = [
[[package]] [[package]]
name = "alloy-primitives" name = "alloy-primitives"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18c35fc4b03ace65001676358ffbbaefe2a2b27ee50fe777c345082c7c888be8" checksum = "6177ed26655d4e84e00b65cb494d4e0b8830e7cae7ef5d63087d445a2600fb55"
dependencies = [ dependencies = [
"alloy-rlp", "alloy-rlp",
"bytes", "bytes",
@@ -575,9 +575,9 @@ dependencies = [
[[package]] [[package]]
name = "alloy-sol-macro" name = "alloy-sol-macro"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8612e0658964d616344f199ab251a49d48113992d81b92dab93ed855faa66383" checksum = "a14f21d053aea4c6630687c2f4ad614bed4c81e14737a9b904798b24f30ea849"
dependencies = [ dependencies = [
"alloy-sol-macro-expander", "alloy-sol-macro-expander",
"alloy-sol-macro-input", "alloy-sol-macro-input",
@@ -589,9 +589,9 @@ dependencies = [
[[package]] [[package]]
name = "alloy-sol-macro-expander" name = "alloy-sol-macro-expander"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a384edac7283bc4c010a355fb648082860c04b826bb7a814c45263c8f304c74" checksum = "34d99282e7c9ef14eb62727981a985a01869e586d1dec729d3bb33679094c100"
dependencies = [ dependencies = [
"alloy-json-abi", "alloy-json-abi",
"alloy-sol-macro-input", "alloy-sol-macro-input",
@@ -608,9 +608,9 @@ dependencies = [
[[package]] [[package]]
name = "alloy-sol-macro-input" name = "alloy-sol-macro-input"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd588c2d516da7deb421b8c166dc60b7ae31bca5beea29ab6621fcfa53d6ca5" checksum = "eda029f955b78e493360ee1d7bd11e1ab9f2a220a5715449babc79d6d0a01105"
dependencies = [ dependencies = [
"alloy-json-abi", "alloy-json-abi",
"const-hex", "const-hex",
@@ -626,9 +626,9 @@ dependencies = [
[[package]] [[package]]
name = "alloy-sol-type-parser" name = "alloy-sol-type-parser"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86ddeb70792c7ceaad23e57d52250107ebbb86733e52f4a25d8dc1abc931837" checksum = "10db1bd7baa35bc8d4a1b07efbf734e73e5ba09f2580fb8cee3483a36087ceb2"
dependencies = [ dependencies = [
"serde", "serde",
"winnow", "winnow",
@@ -636,9 +636,9 @@ dependencies = [
[[package]] [[package]]
name = "alloy-sol-types" name = "alloy-sol-types"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "584cb97bfc5746cb9dcc4def77da11694b5d6d7339be91b7480a6a68dc129387" checksum = "58377025a47d8b8426b3e4846a251f2c1991033b27f517aade368146f6ab1dfe"
dependencies = [ dependencies = [
"alloy-json-abi", "alloy-json-abi",
"alloy-primitives", "alloy-primitives",
@@ -4034,6 +4034,7 @@ dependencies = [
"revive-dt-node-interaction", "revive-dt-node-interaction",
"revive-dt-report", "revive-dt-report",
"revive-solc-json-interface", "revive-solc-json-interface",
"serde_json",
"temp-dir", "temp-dir",
] ]
@@ -4042,6 +4043,8 @@ name = "revive-dt-format"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"alloy", "alloy",
"alloy-primitives",
"alloy-sol-types",
"anyhow", "anyhow",
"log", "log",
"semver 1.0.26", "semver 1.0.26",
@@ -5143,9 +5146,9 @@ dependencies = [
[[package]] [[package]]
name = "syn-solidity" name = "syn-solidity"
version = "1.1.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5d879005cc1b5ba4e18665be9e9501d9da3a9b95f625497c4cb7ee082b532e" checksum = "b9ac494e7266fcdd2ad80bf4375d55d27a117ea5c866c26d0e97fe5b3caeeb75"
dependencies = [ dependencies = [
"paste", "paste",
"proc-macro2", "proc-macro2",
+2
View File
@@ -23,6 +23,8 @@ revive-dt-node-pool = { version = "0.1.0", path = "crates/node-pool" }
revive-dt-report = { version = "0.1.0", path = "crates/report" } revive-dt-report = { version = "0.1.0", path = "crates/report" }
revive-dt-solc-binaries = { version = "0.1.0", path = "crates/solc-binaries" } revive-dt-solc-binaries = { version = "0.1.0", path = "crates/solc-binaries" }
alloy-primitives = "1.2.1"
alloy-sol-types = "1.2.1"
anyhow = "1.0" anyhow = "1.0"
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
env_logger = "0.11.8" env_logger = "0.11.8"
+1
View File
@@ -27,4 +27,5 @@ log = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }
rayon = { workspace = true } rayon = { workspace = true }
revive-solc-json-interface = { workspace = true } revive-solc-json-interface = { workspace = true }
serde_json = { workspace = true }
temp-dir = { workspace = true } temp-dir = { workspace = true }
+99 -17
View File
@@ -1,12 +1,14 @@
//! The test driver handles the compilation and execution of the test cases. //! The test driver handles the compilation and execution of the test cases.
use alloy::json_abi::JsonAbi;
use alloy::primitives::Bytes; use alloy::primitives::Bytes;
use alloy::rpc::types::TransactionInput; use alloy::rpc::types::trace::geth::GethTrace;
use alloy::rpc::types::{TransactionInput, TransactionReceipt};
use alloy::{ use alloy::{
primitives::{Address, TxKind, map::HashMap}, primitives::{Address, TxKind, map::HashMap},
rpc::types::{ rpc::types::{
TransactionReceipt, TransactionRequest, TransactionRequest,
trace::geth::{AccountState, DiffMode, GethTrace}, trace::geth::{AccountState, DiffMode},
}, },
}; };
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler}; use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
@@ -15,6 +17,8 @@ use revive_dt_format::{input::Input, metadata::Metadata, mode::SolcMode};
use revive_dt_node_interaction::EthereumNode; use revive_dt_node_interaction::EthereumNode;
use revive_dt_report::reporter::{CompilationTask, Report, Span}; use revive_dt_report::reporter::{CompilationTask, Report, Span};
use revive_solc_json_interface::SolcStandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use serde_json::Value;
use std::collections::HashMap as StdHashMap;
use crate::Platform; use crate::Platform;
@@ -27,7 +31,8 @@ pub struct State<'a, T: Platform> {
config: &'a Arguments, config: &'a Arguments,
span: Span, span: Span,
contracts: Contracts<T>, contracts: Contracts<T>,
deployed_contracts: HashMap<String, Address>, deployed_contracts: StdHashMap<String, Address>,
deployed_abis: StdHashMap<String, JsonAbi>,
} }
impl<'a, T> State<'a, T> impl<'a, T> State<'a, T>
@@ -40,6 +45,7 @@ where
span, span,
contracts: Default::default(), contracts: Default::default(),
deployed_contracts: Default::default(), deployed_contracts: Default::default(),
deployed_abis: Default::default(),
} }
} }
@@ -126,10 +132,16 @@ where
std::any::type_name::<T>() std::any::type_name::<T>()
); );
let tx = let tx = match input.legacy_transaction(
match input.legacy_transaction(self.config.network_id, nonce, &self.deployed_contracts) self.config.network_id,
{ nonce,
Ok(tx) => tx, &self.deployed_contracts,
&self.deployed_abis,
) {
Ok(tx) => {
log::debug!("Legacy transaction data: {tx:#?}");
tx
}
Err(err) => { Err(err) => {
log::error!("Failed to construct legacy transaction: {err:?}"); log::error!("Failed to construct legacy transaction: {err:?}");
return Err(err); return Err(err);
@@ -191,9 +203,6 @@ where
&contract_name, &contract_name,
&input.instance &input.instance
); );
if contract_name != &input.instance {
continue;
}
let bytecode = contract let bytecode = contract
.evm .evm
@@ -270,6 +279,52 @@ where
address, address,
std::any::type_name::<T>() std::any::type_name::<T>()
); );
if let Some(Value::String(metadata_json_str)) = &contract.metadata {
log::trace!(
"metadata found for contract {contract_name}, {metadata_json_str}"
);
match serde_json::from_str::<serde_json::Value>(metadata_json_str) {
Ok(metadata_json) => {
if let Some(abi_value) =
metadata_json.get("output").and_then(|o| o.get("abi"))
{
match serde_json::from_value::<JsonAbi>(abi_value.clone()) {
Ok(parsed_abi) => {
log::trace!(
"ABI found in metadata for contract {}",
&contract_name
);
self.deployed_abis
.insert(contract_name.clone(), parsed_abi);
}
Err(err) => {
anyhow::bail!(
"Failed to parse ABI from metadata for contract {}: {}",
contract_name,
err
);
}
}
} else {
anyhow::bail!(
"No ABI found in metadata for contract {}",
contract_name
);
}
}
Err(err) => {
anyhow::bail!(
"Failed to parse metadata JSON string for contract {}: {}",
contract_name,
err
);
}
}
} else {
anyhow::bail!("No metadata found for contract {}", contract_name);
}
} }
} }
} }
@@ -343,14 +398,41 @@ where
for case in &self.metadata.cases { for case in &self.metadata.cases {
for input in &case.inputs { for input in &case.inputs {
log::debug!("Starting deploying contract {}", &input.instance); log::debug!("Starting deploying contract {}", &input.instance);
leader_state.deploy_contracts(input, self.leader_node)?; if let Err(err) = leader_state.deploy_contracts(input, self.leader_node) {
follower_state.deploy_contracts(input, self.follower_node)?; log::error!("Leader deployment failed for {}: {err}", input.instance);
continue;
} else {
log::debug!("Leader deployment succeeded for {}", &input.instance);
}
if let Err(err) = follower_state.deploy_contracts(input, self.follower_node) {
log::error!("Follower deployment failed for {}: {err}", input.instance);
continue;
} else {
log::debug!("Follower deployment succeeded for {}", &input.instance);
}
log::debug!("Starting executing contract {}", &input.instance); log::debug!("Starting executing contract {}", &input.instance);
let (leader_receipt, _, leader_diff) =
leader_state.execute_input(input, self.leader_node)?; let (leader_receipt, _, leader_diff) = match leader_state
let (follower_receipt, _, follower_diff) = .execute_input(input, self.leader_node)
follower_state.execute_input(input, self.follower_node)?; {
Ok(result) => result,
Err(err) => {
log::error!("Leader execution failed for {}: {err}", input.instance);
continue;
}
};
let (follower_receipt, _, follower_diff) = match follower_state
.execute_input(input, self.follower_node)
{
Ok(result) => result,
Err(err) => {
log::error!("Follower execution failed for {}: {err}", input.instance);
continue;
}
};
if leader_diff == follower_diff { if leader_diff == follower_diff {
log::debug!("State diffs match between leader and follower."); log::debug!("State diffs match between leader and follower.");
+2
View File
@@ -10,6 +10,8 @@ rust-version.workspace = true
[dependencies] [dependencies]
alloy = { workspace = true } alloy = { workspace = true }
alloy-primitives = { workspace = true }
alloy-sol-types = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
log = { workspace = true } log = { workspace = true }
semver = { workspace = true } semver = { workspace = true }
+321 -4
View File
@@ -1,10 +1,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use alloy::{ use alloy::{
json_abi::Function, hex,
primitives::{Address, TxKind}, json_abi::{Function, JsonAbi},
rpc::types::TransactionRequest, primitives::{Address, Bytes, TxKind},
rpc::types::{TransactionInput, TransactionRequest},
}; };
use alloy_primitives::U256;
use alloy_sol_types::SolValue;
use semver::VersionReq; use semver::VersionReq;
use serde::{Deserialize, de::Deserializer}; use serde::{Deserialize, de::Deserializer};
use serde_json::Value; use serde_json::Value;
@@ -44,7 +47,15 @@ pub struct ExpectedOutput {
#[serde(untagged)] #[serde(untagged)]
pub enum Calldata { pub enum Calldata {
Single(String), Single(String),
Compound(Vec<String>), Compound(Vec<CalldataArg>),
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
#[serde(untagged)]
pub enum CalldataArg {
Literal(String),
/// For example: `Contract.address`
AddressRef(String),
} }
/// Specify how the contract is called. /// Specify how the contract is called.
@@ -102,12 +113,117 @@ impl Input {
.ok_or_else(|| anyhow::anyhow!("instance {instance} not deployed")) .ok_or_else(|| anyhow::anyhow!("instance {instance} not deployed"))
} }
pub fn encoded_input(
&self,
deployed_abis: &HashMap<String, JsonAbi>,
deployed_contracts: &HashMap<String, Address>,
) -> anyhow::Result<Bytes> {
let Method::Function(selector) = self.method else {
return Ok(Bytes::default()); // fallback or deployer — no input
};
let abi = deployed_abis
.get(&self.instance)
.ok_or_else(|| anyhow::anyhow!("ABI for instance '{}' not found", &self.instance))?;
log::trace!("ABI found for instance: {}", &self.instance);
// Find function by selector
let function = abi
.functions()
.find(|f| f.selector().0 == selector)
.ok_or_else(|| {
anyhow::anyhow!(
"Function with selector {:?} not found in ABI for the instance {:?}",
selector,
&self.instance
)
})?;
log::trace!("Functions found for instance: {}", &self.instance);
let calldata_args = match &self.calldata {
Some(Calldata::Compound(args)) => args,
_ => anyhow::bail!("Expected compound calldata for function call"),
};
if calldata_args.len() != function.inputs.len() {
anyhow::bail!(
"Function expects {} args, but got {}",
function.inputs.len(),
calldata_args.len()
);
}
log::trace!(
"Starting encoding ABI's parameters for instance: {}",
&self.instance
);
let mut encoded = selector.to_vec();
for (i, param) in function.inputs.iter().enumerate() {
let arg = calldata_args.get(i).unwrap();
let encoded_arg = match arg {
CalldataArg::Literal(value) => match param.ty.as_str() {
"uint256" | "uint" => {
let val: U256 = value.parse()?;
val.abi_encode()
}
"uint24" => {
let val: u32 = value.parse()?;
(val & 0xFFFFFF).abi_encode()
}
"bool" => {
let val: bool = value.parse()?;
val.abi_encode()
}
"address" => {
let addr: Address = value.parse()?;
addr.abi_encode()
}
"string" => value.abi_encode(),
"bytes32" => {
let val = hex::decode(value.trim_start_matches("0x"))?;
let mut fixed = [0u8; 32];
fixed[..val.len()].copy_from_slice(&val);
fixed.abi_encode()
}
"uint256[]" | "uint[]" => {
let nums: Vec<u64> = serde_json::from_str(value)?;
nums.abi_encode()
}
"bytes" => {
let val = hex::decode(value.trim_start_matches("0x"))?;
val.abi_encode()
}
_ => anyhow::bail!("Unsupported type: {}", param.ty),
},
CalldataArg::AddressRef(name) => {
let contract_name = name.trim_end_matches(".address");
let addr = deployed_contracts
.get(contract_name)
.copied()
.ok_or_else(|| {
anyhow::anyhow!("Address for '{}' not found", contract_name)
})?;
addr.abi_encode()
}
};
encoded.extend(encoded_arg);
}
Ok(Bytes::from(encoded))
}
/// Parse this input into a legacy transaction. /// Parse this input into a legacy transaction.
pub fn legacy_transaction( pub fn legacy_transaction(
&self, &self,
chain_id: u64, chain_id: u64,
nonce: u64, nonce: u64,
deployed_contracts: &HashMap<String, Address>, deployed_contracts: &HashMap<String, Address>,
deployed_abis: &HashMap<String, JsonAbi>,
) -> anyhow::Result<TransactionRequest> { ) -> anyhow::Result<TransactionRequest> {
let to = match self.method { let to = match self.method {
Method::Deployer => Some(TxKind::Create), Method::Deployer => Some(TxKind::Create),
@@ -116,6 +232,8 @@ impl Input {
)), )),
}; };
let input_data = self.encoded_input(deployed_abis, deployed_contracts)?;
Ok(TransactionRequest { Ok(TransactionRequest {
from: Some(self.caller), from: Some(self.caller),
to, to,
@@ -123,6 +241,7 @@ impl Input {
chain_id: Some(chain_id), chain_id: Some(chain_id),
gas_price: Some(5_000_000), gas_price: Some(5_000_000),
gas: Some(5_000_000), gas: Some(5_000_000),
input: TransactionInput::new(input_data),
..Default::default() ..Default::default()
}) })
} }
@@ -135,3 +254,201 @@ fn default_instance() -> String {
fn default_caller() -> Address { fn default_caller() -> Address {
"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1".parse().unwrap() "90F8bf6A479f320ead074411a4B0e7944Ea8c9C1".parse().unwrap()
} }
#[cfg(test)]
mod tests {
use super::*;
use alloy::json_abi::JsonAbi;
use alloy_primitives::{address, keccak256};
use std::collections::HashMap;
#[test]
fn test_encoded_input_uint256() {
let raw_metadata = r#"
[
{
"inputs": [{"name": "value", "type": "uint256"}],
"name": "store",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
"#;
let parsed_abi: JsonAbi = serde_json::from_str(raw_metadata).unwrap();
let selector = keccak256("store(uint256)".as_bytes())[0..4]
.try_into()
.unwrap();
let input = Input {
instance: "Contract".to_string(),
method: Method::Function(selector),
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
"42".to_string(),
)])),
..Default::default()
};
let mut deployed_abis = HashMap::new();
deployed_abis.insert("Contract".to_string(), parsed_abi);
let deployed_contracts = HashMap::new();
let encoded = input
.encoded_input(&deployed_abis, &deployed_contracts)
.unwrap();
assert!(encoded.0.starts_with(&selector));
type T = (u64,);
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
assert_eq!(decoded.0, 42);
}
#[test]
fn test_encoded_input_bool() {
let raw_abi = r#"[
{
"inputs": [{"name": "flag", "type": "bool"}],
"name": "toggle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]"#;
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
let selector = keccak256("toggle(bool)".as_bytes())[0..4]
.try_into()
.unwrap();
let input = Input {
instance: "Contract".to_string(),
method: Method::Function(selector),
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
"true".to_string(),
)])),
..Default::default()
};
let mut abis = HashMap::new();
abis.insert("Contract".to_string(), parsed_abi);
let contracts = HashMap::new();
let encoded = input.encoded_input(&abis, &contracts).unwrap();
assert!(encoded.0.starts_with(&selector));
type T = (bool,);
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
assert_eq!(decoded.0, true);
}
#[test]
fn test_encoded_input_string() {
let raw_abi = r#"[
{
"inputs": [{"name": "msg", "type": "string"}],
"name": "echo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]"#;
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
let selector = keccak256("echo(string)".as_bytes())[0..4]
.try_into()
.unwrap();
let input = Input {
instance: "Contract".to_string(),
method: Method::Function(selector),
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
"hello".to_string(),
)])),
..Default::default()
};
let mut abis = HashMap::new();
abis.insert("Contract".to_string(), parsed_abi);
let contracts = HashMap::new();
let encoded = input.encoded_input(&abis, &contracts).unwrap();
assert!(encoded.0.starts_with(&selector));
}
#[test]
fn test_encoded_input_uint256_array() {
let raw_abi = r#"[
{
"inputs": [{"name": "arr", "type": "uint256[]"}],
"name": "sum",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]"#;
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
let selector = keccak256("sum(uint256[])".as_bytes())[0..4]
.try_into()
.unwrap();
let input = Input {
instance: "Contract".to_string(),
method: Method::Function(selector),
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
"[1,2,3]".to_string(),
)])),
..Default::default()
};
let mut abis = HashMap::new();
abis.insert("Contract".to_string(), parsed_abi);
let contracts = HashMap::new();
let encoded = input.encoded_input(&abis, &contracts).unwrap();
assert!(encoded.0.starts_with(&selector));
}
#[test]
fn test_encoded_input_address() {
let raw_abi = r#"[
{
"inputs": [{"name": "recipient", "type": "address"}],
"name": "send",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]"#;
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
let selector = keccak256("send(address)".as_bytes())[0..4]
.try_into()
.unwrap();
let input = Input {
instance: "Contract".to_string(),
method: Method::Function(selector),
calldata: Some(Calldata::Compound(vec![CalldataArg::Literal(
"0x1000000000000000000000000000000000000001".to_string(),
)])),
..Default::default()
};
let mut abis = HashMap::new();
abis.insert("Contract".to_string(), parsed_abi);
let contracts = HashMap::new();
let encoded = input.encoded_input(&abis, &contracts).unwrap();
assert!(encoded.0.starts_with(&selector));
type T = (alloy_primitives::Address,);
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
assert_eq!(
decoded.0,
address!("0x1000000000000000000000000000000000000001")
);
}
}
+4 -1
View File
@@ -1,6 +1,7 @@
//! The go-ethereum node implementation. //! The go-ethereum node implementation.
use std::{ use std::{
collections::HashMap,
fs::{File, create_dir_all, remove_dir_all}, fs::{File, create_dir_all, remove_dir_all},
io::{BufRead, BufReader, Read, Write}, io::{BufRead, BufReader, Read, Write},
path::PathBuf, path::PathBuf,
@@ -15,7 +16,7 @@ use std::{
use alloy::{ use alloy::{
network::EthereumWallet, network::EthereumWallet,
primitives::{Address, map::HashMap}, primitives::Address,
providers::{Provider, ProviderBuilder, ext::DebugApi}, providers::{Provider, ProviderBuilder, ext::DebugApi},
rpc::types::{ rpc::types::{
TransactionReceipt, TransactionRequest, TransactionReceipt, TransactionRequest,
@@ -158,6 +159,8 @@ impl EthereumNode for Instance {
let connection_string = self.connection_string(); let connection_string = self.connection_string();
let wallet = self.wallet.clone(); let wallet = self.wallet.clone();
log::debug!("Submitting transaction: {transaction:#?}");
execute_transaction(Box::pin(async move { execute_transaction(Box::pin(async move {
Ok(ProviderBuilder::new() Ok(ProviderBuilder::new()
.wallet(wallet) .wallet(wallet)
+4 -1
View File
@@ -1,4 +1,5 @@
use std::{ use std::{
collections::HashMap,
fs::create_dir_all, fs::create_dir_all,
io::BufRead, io::BufRead,
path::PathBuf, path::PathBuf,
@@ -13,7 +14,7 @@ use std::{
use alloy::{ use alloy::{
hex, hex,
network::EthereumWallet, network::EthereumWallet,
primitives::{Address, map::HashMap}, primitives::Address,
providers::{Provider, ProviderBuilder, ext::DebugApi}, providers::{Provider, ProviderBuilder, ext::DebugApi},
rpc::types::{ rpc::types::{
TransactionReceipt, TransactionReceipt,
@@ -251,6 +252,8 @@ impl EthereumNode for KitchensinkNode {
let url = self.rpc_url.clone(); let url = self.rpc_url.clone();
let wallet = self.wallet.clone(); let wallet = self.wallet.clone();
log::debug!("Submitting transaction: {transaction:#?}");
execute_transaction(Box::pin(async move { execute_transaction(Box::pin(async move {
Ok(ProviderBuilder::new() Ok(ProviderBuilder::new()
.wallet(wallet) .wallet(wallet)