Compute transaction input for executing transactions (#28)

* Parsed ABI field in order to get method parameter

* Added logic for ABI

* Refactored dependencies

* Small refactoring

* Added unit tests for ABI parameter extraction logic

* Fixed format issues

* Fixed format

* Added new changes to format

* Added bail to stop execution when we have an error during deployment
This commit is contained in:
activecoder10
2025-07-09 14:03:38 +03:00
committed by GitHub
parent 3a537c2812
commit de7c7d6703
8 changed files with 457 additions and 44 deletions
+104 -22
View File
@@ -1,12 +1,14 @@
//! The test driver handles the compilation and execution of the test cases.
use alloy::json_abi::JsonAbi;
use alloy::primitives::Bytes;
use alloy::rpc::types::TransactionInput;
use alloy::rpc::types::trace::geth::GethTrace;
use alloy::rpc::types::{TransactionInput, TransactionReceipt};
use alloy::{
primitives::{Address, TxKind, map::HashMap},
rpc::types::{
TransactionReceipt, TransactionRequest,
trace::geth::{AccountState, DiffMode, GethTrace},
TransactionRequest,
trace::geth::{AccountState, DiffMode},
},
};
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_report::reporter::{CompilationTask, Report, Span};
use revive_solc_json_interface::SolcStandardJsonOutput;
use serde_json::Value;
use std::collections::HashMap as StdHashMap;
use crate::Platform;
@@ -27,7 +31,8 @@ pub struct State<'a, T: Platform> {
config: &'a Arguments,
span: Span,
contracts: Contracts<T>,
deployed_contracts: HashMap<String, Address>,
deployed_contracts: StdHashMap<String, Address>,
deployed_abis: StdHashMap<String, JsonAbi>,
}
impl<'a, T> State<'a, T>
@@ -40,6 +45,7 @@ where
span,
contracts: Default::default(),
deployed_contracts: Default::default(),
deployed_abis: Default::default(),
}
}
@@ -126,15 +132,21 @@ where
std::any::type_name::<T>()
);
let tx =
match input.legacy_transaction(self.config.network_id, nonce, &self.deployed_contracts)
{
Ok(tx) => tx,
Err(err) => {
log::error!("Failed to construct legacy transaction: {err:?}");
return Err(err);
}
};
let tx = match input.legacy_transaction(
self.config.network_id,
nonce,
&self.deployed_contracts,
&self.deployed_abis,
) {
Ok(tx) => {
log::debug!("Legacy transaction data: {tx:#?}");
tx
}
Err(err) => {
log::error!("Failed to construct legacy transaction: {err:?}");
return Err(err);
}
};
log::trace!("Executing transaction for input: {input:?}");
@@ -191,9 +203,6 @@ where
&contract_name,
&input.instance
);
if contract_name != &input.instance {
continue;
}
let bytecode = contract
.evm
@@ -270,6 +279,52 @@ where
address,
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 input in &case.inputs {
log::debug!("Starting deploying contract {}", &input.instance);
leader_state.deploy_contracts(input, self.leader_node)?;
follower_state.deploy_contracts(input, self.follower_node)?;
if let Err(err) = leader_state.deploy_contracts(input, self.leader_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);
let (leader_receipt, _, leader_diff) =
leader_state.execute_input(input, self.leader_node)?;
let (follower_receipt, _, follower_diff) =
follower_state.execute_input(input, self.follower_node)?;
let (leader_receipt, _, leader_diff) = match leader_state
.execute_input(input, self.leader_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 {
log::debug!("State diffs match between leader and follower.");