Compare commits

..

3 Commits

Author SHA1 Message Date
Omar Abdulla 7836461763 Add test 2025-07-21 12:15:27 +03:00
Omar Abdulla 0e473e1633 Merge remote-tracking branch 'origin/main' into bugfix/function-signature 2025-07-21 12:13:24 +03:00
Omar Abdulla c8cef4834f Allow for the use of function signatures 2025-07-18 16:37:15 +03:00
2 changed files with 60 additions and 64 deletions
+44 -60
View File
@@ -23,8 +23,7 @@ pub struct Input {
#[serde(default = "default_instance")] #[serde(default = "default_instance")]
pub instance: ContractInstance, pub instance: ContractInstance,
pub method: Method, pub method: Method,
#[serde(default)] pub calldata: Option<Calldata>,
pub calldata: Calldata,
pub expected: Option<Expected>, pub expected: Option<Expected>,
pub value: Option<String>, pub value: Option<String>,
pub storage: Option<HashMap<String, Calldata>>, pub storage: Option<HashMap<String, Calldata>>,
@@ -74,12 +73,6 @@ pub enum Method {
FunctionName(String), FunctionName(String),
} }
impl Default for Calldata {
fn default() -> Self {
Self::Compound(Default::default())
}
}
impl Calldata { impl Calldata {
pub fn find_all_contract_instances(&self, vec: &mut Vec<ContractInstance>) { pub fn find_all_contract_instances(&self, vec: &mut Vec<ContractInstance>) {
if let Calldata::Compound(compound) = self { if let Calldata::Compound(compound) = self {
@@ -90,40 +83,6 @@ impl Calldata {
} }
} }
} }
pub fn construct_call_data(
&self,
buffer: &mut Vec<u8>,
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
chain_state_provider: &impl EthereumNode,
) -> anyhow::Result<()> {
match self {
Calldata::Single(string) => {
alloy::hex::decode_to_slice(string, buffer)?;
}
Calldata::Compound(items) => {
for (arg_idx, arg) in items.iter().enumerate() {
match resolve_argument(arg, deployed_contracts, chain_state_provider) {
Ok(resolved) => {
buffer.extend(resolved.to_be_bytes::<32>());
}
Err(error) => {
tracing::error!(arg, arg_idx, ?error, "Failed to resolve argument");
return Err(error);
}
};
}
}
};
Ok(())
}
pub fn size_requirement(&self) -> usize {
match self {
Calldata::Single(single) => (single.len() - 2) / 2,
Calldata::Compound(items) => items.len() * 32,
}
}
} }
impl ExpectedOutput { impl ExpectedOutput {
@@ -153,12 +112,23 @@ impl Input {
) -> anyhow::Result<Bytes> { ) -> anyhow::Result<Bytes> {
match self.method { match self.method {
Method::Deployer | Method::Fallback => { Method::Deployer | Method::Fallback => {
let mut calldata = Vec::<u8>::with_capacity(self.calldata.size_requirement()); let calldata_args = match &self.calldata {
self.calldata.construct_call_data( Some(Calldata::Compound(args)) => args,
&mut calldata, _ => anyhow::bail!("Expected compound calldata for function call"),
deployed_contracts, };
chain_state_provider,
)?; let mut calldata = Vec::<u8>::with_capacity(calldata_args.len() * 32);
for (arg_idx, arg) in calldata_args.iter().enumerate() {
match resolve_argument(arg, deployed_contracts, chain_state_provider) {
Ok(resolved) => {
calldata.extend(resolved.to_be_bytes::<32>());
}
Err(error) => {
tracing::error!(arg, arg_idx, ?error, "Failed to resolve argument");
return Err(error);
}
};
}
Ok(calldata.into()) Ok(calldata.into())
} }
@@ -191,6 +161,11 @@ impl Input {
tracing::trace!("Functions found for instance: {}", self.instance.as_ref()); tracing::trace!("Functions found for instance: {}", self.instance.as_ref());
let calldata_args = match &self.calldata {
Some(Calldata::Compound(args)) => args,
_ => anyhow::bail!("Expected compound calldata for function call"),
};
tracing::trace!( tracing::trace!(
"Starting encoding ABI's parameters for instance: {}", "Starting encoding ABI's parameters for instance: {}",
self.instance.as_ref() self.instance.as_ref()
@@ -202,13 +177,20 @@ impl Input {
// //
// We're using indices in the following code in order to avoid the need for us to allocate // We're using indices in the following code in order to avoid the need for us to allocate
// a new buffer for each one of the resolved arguments. // a new buffer for each one of the resolved arguments.
let mut calldata = Vec::<u8>::with_capacity(4 + self.calldata.size_requirement()); let mut calldata = Vec::<u8>::with_capacity(4 + calldata_args.len() * 32);
calldata.extend(function.selector().0); calldata.extend(function.selector().0);
self.calldata.construct_call_data(
&mut calldata, for (arg_idx, arg) in calldata_args.iter().enumerate() {
deployed_contracts, match resolve_argument(arg, deployed_contracts, chain_state_provider) {
chain_state_provider, Ok(resolved) => {
)?; calldata.extend(resolved.to_be_bytes::<32>());
}
Err(error) => {
tracing::error!(arg, arg_idx, ?error, "Failed to resolve argument");
return Err(error);
}
};
}
Ok(calldata.into()) Ok(calldata.into())
} }
@@ -235,7 +217,9 @@ impl Input {
let mut vec = Vec::new(); let mut vec = Vec::new();
vec.push(self.instance.clone()); vec.push(self.instance.clone());
self.calldata.find_all_contract_instances(&mut vec); if let Some(ref cd) = self.calldata {
cd.find_all_contract_instances(&mut vec);
}
match &self.expected { match &self.expected {
Some(Expected::Calldata(cd)) => { Some(Expected::Calldata(cd)) => {
cd.find_all_contract_instances(&mut vec); cd.find_all_contract_instances(&mut vec);
@@ -432,7 +416,7 @@ mod tests {
let input = Input { let input = Input {
instance: ContractInstance::new_from("Contract"), instance: ContractInstance::new_from("Contract"),
method: Method::FunctionName("store".to_owned()), method: Method::FunctionName("store".to_owned()),
calldata: Calldata::Compound(vec!["42".into()]), calldata: Some(Calldata::Compound(vec!["42".into()])),
..Default::default() ..Default::default()
}; };
@@ -474,9 +458,9 @@ mod tests {
let input: Input = Input { let input: Input = Input {
instance: "Contract".to_owned().into(), instance: "Contract".to_owned().into(),
method: Method::FunctionName("send(address)".to_owned()), method: Method::FunctionName("send(address)".to_owned()),
calldata: Calldata::Compound(vec![ calldata: Some(Calldata::Compound(vec![
"0x1000000000000000000000000000000000000001".to_string(), "0x1000000000000000000000000000000000000001".to_string(),
]), ])),
..Default::default() ..Default::default()
}; };
@@ -521,9 +505,9 @@ mod tests {
let input: Input = Input { let input: Input = Input {
instance: ContractInstance::new_from("Contract"), instance: ContractInstance::new_from("Contract"),
method: Method::FunctionName("send".to_owned()), method: Method::FunctionName("send".to_owned()),
calldata: Calldata::Compound(vec![ calldata: Some(Calldata::Compound(vec![
"0x1000000000000000000000000000000000000001".to_string(), "0x1000000000000000000000000000000000000001".to_string(),
]), ])),
..Default::default() ..Default::default()
}; };
+16 -4
View File
@@ -110,25 +110,37 @@ mod tests {
#[test] #[test]
fn try_get_windows() { fn try_get_windows() {
let version = List::download(List::WINDOWS_URL).unwrap().latest_release; let version = List::download(List::WINDOWS_URL)
.unwrap()
.latest_release
.into();
GHDownloader::windows(version).download().unwrap(); GHDownloader::windows(version).download().unwrap();
} }
#[test] #[test]
fn try_get_macosx() { fn try_get_macosx() {
let version = List::download(List::MACOSX_URL).unwrap().latest_release; let version = List::download(List::MACOSX_URL)
.unwrap()
.latest_release
.into();
GHDownloader::macosx(version).download().unwrap(); GHDownloader::macosx(version).download().unwrap();
} }
#[test] #[test]
fn try_get_linux() { fn try_get_linux() {
let version = List::download(List::LINUX_URL).unwrap().latest_release; let version = List::download(List::LINUX_URL)
.unwrap()
.latest_release
.into();
GHDownloader::linux(version).download().unwrap(); GHDownloader::linux(version).download().unwrap();
} }
#[test] #[test]
fn try_get_wasm() { fn try_get_wasm() {
let version = List::download(List::WASM_URL).unwrap().latest_release; let version = List::download(List::WASM_URL)
.unwrap()
.latest_release
.into();
GHDownloader::wasm(version).download().unwrap(); GHDownloader::wasm(version).download().unwrap();
} }
} }