Compare commits

...

15 Commits

Author SHA1 Message Date
Omar Abdulla 8126449115 Merge remote-tracking branch 'origin/main' into bugfix/better-calldata-handling 2025-07-22 06:33:30 +03:00
Omar Abdulla 969990d3e0 Remove todo 2025-07-21 12:04:07 +03:00
Omar Abdulla ca59a1f6a9 Handle calldata better 2025-07-18 15:52:40 +03:00
Omar Abdulla adc0c44cde Merge remote-tracking branch 'origin/main' into refactor/contract-deployment-and-input-handling 2025-07-18 15:18:27 +03:00
Omar Abdulla 811e17136b Merge remote-tracking branch 'origin/main' into refactor/contract-deployment-and-input-handling 2025-07-18 15:11:40 +03:00
Omar Abdulla ba32bad6b3 Fix edge-case in deployment order 2025-07-17 22:26:49 +03:00
Omar Abdulla bb754cba4f Correct comment 2025-07-17 18:53:24 +03:00
Omar Abdulla c858bbe66d Ignore macro doc comment tests 2025-07-17 18:28:23 +03:00
Omar Abdulla 906878f06a Fix edge-case in input handling 2025-07-17 18:00:49 +03:00
Omar Abdulla 9a71369e8a Implement the new input handling logic 2025-07-17 17:46:40 +03:00
Omar Abdulla 84ab873b46 Impl new_from for wrapper types 2025-07-17 15:33:28 +03:00
Omar Abdulla 2ef6f7ba63 Make metadata structs more typed 2025-07-17 15:31:18 +03:00
Omar Abdulla 38e6140a7c Remove unneeded use of two HashMaps 2025-07-17 14:41:48 +03:00
Omar Abdulla ca6c5529e2 Move FilesWithExtensionIterator to core::common 2025-07-17 14:32:55 +03:00
Omar Abdulla 038a2db53c Add support for wrapper types 2025-07-17 14:22:18 +03:00
2 changed files with 64 additions and 60 deletions
+60 -44
View File
@@ -23,7 +23,8 @@ pub struct Input {
#[serde(default = "default_instance")] #[serde(default = "default_instance")]
pub instance: ContractInstance, pub instance: ContractInstance,
pub method: Method, pub method: Method,
pub calldata: Option<Calldata>, #[serde(default)]
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>>,
@@ -73,6 +74,12 @@ 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 {
@@ -83,6 +90,40 @@ 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 {
@@ -112,23 +153,12 @@ impl Input {
) -> anyhow::Result<Bytes> { ) -> anyhow::Result<Bytes> {
match self.method { match self.method {
Method::Deployer | Method::Fallback => { Method::Deployer | Method::Fallback => {
let calldata_args = match &self.calldata { let mut calldata = Vec::<u8>::with_capacity(self.calldata.size_requirement());
Some(Calldata::Compound(args)) => args, self.calldata.construct_call_data(
_ => anyhow::bail!("Expected compound calldata for function call"), &mut calldata,
}; 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())
} }
@@ -161,11 +191,6 @@ 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()
@@ -177,20 +202,13 @@ 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 + calldata_args.len() * 32); let mut calldata = Vec::<u8>::with_capacity(4 + self.calldata.size_requirement());
calldata.extend(function.selector().0); calldata.extend(function.selector().0);
self.calldata.construct_call_data(
for (arg_idx, arg) in calldata_args.iter().enumerate() { &mut calldata,
match resolve_argument(arg, deployed_contracts, chain_state_provider) { deployed_contracts,
Ok(resolved) => { chain_state_provider,
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())
} }
@@ -217,9 +235,7 @@ impl Input {
let mut vec = Vec::new(); let mut vec = Vec::new();
vec.push(self.instance.clone()); vec.push(self.instance.clone());
if let Some(ref cd) = self.calldata { self.calldata.find_all_contract_instances(&mut vec);
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);
@@ -416,7 +432,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: Some(Calldata::Compound(vec!["42".into()])), calldata: Calldata::Compound(vec!["42".into()]),
..Default::default() ..Default::default()
}; };
@@ -458,9 +474,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: Some(Calldata::Compound(vec![ calldata: Calldata::Compound(vec![
"0x1000000000000000000000000000000000000001".to_string(), "0x1000000000000000000000000000000000000001".to_string(),
])), ]),
..Default::default() ..Default::default()
}; };
@@ -505,9 +521,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: Some(Calldata::Compound(vec![ calldata: Calldata::Compound(vec![
"0x1000000000000000000000000000000000000001".to_string(), "0x1000000000000000000000000000000000000001".to_string(),
])), ]),
..Default::default() ..Default::default()
}; };
+4 -16
View File
@@ -110,37 +110,25 @@ mod tests {
#[test] #[test]
fn try_get_windows() { fn try_get_windows() {
let version = List::download(List::WINDOWS_URL) let version = List::download(List::WINDOWS_URL).unwrap().latest_release;
.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) let version = List::download(List::MACOSX_URL).unwrap().latest_release;
.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) let version = List::download(List::LINUX_URL).unwrap().latest_release;
.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) let version = List::download(List::WASM_URL).unwrap().latest_release;
.unwrap()
.latest_release
.into();
GHDownloader::wasm(version).download().unwrap(); GHDownloader::wasm(version).download().unwrap();
} }
} }