diff --git a/src/c/gen.rs b/src/c/gen.rs index 2d7adee..564d952 100644 --- a/src/c/gen.rs +++ b/src/c/gen.rs @@ -1,17 +1,17 @@ +// Copyright 2023, Offchain Labs, Inc. +// For licensing, see https://github.com/OffchainLabs/cargo-stylus/blob/main/licenses/COPYRIGHT.md + use alloy_json_abi::{Function, JsonAbi, StateMutability}; use eyre::bail; use serde_json::Value; -use std::collections::HashMap; use std::fs; use std::io::BufReader; +use std::{collections::HashMap, fmt::Write}; use tiny_keccak::{Hasher, Keccak}; fn c_bytearray_initializer(val: &[u8]) -> String { - let slot_strings: Vec = val - .iter() - .map(|input| -> String { format!("0x{:02x}", input) }) - .collect(); - format!("{{{}}}", slot_strings.join(", ")) + let inner: Vec<_> = val.iter().map(|byte| format!("0x{byte:02x}")).collect(); + format!("{{{}}}", inner.join(", ")) } pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { @@ -25,7 +25,8 @@ pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { let mut pathbuf = std::path::PathBuf::new(); pathbuf.push(out_path); - for (solidity_file_name, solidity_file_out) in input_contracts.iter() { + + for (solidity_file_name, solidity_file_out) in input_contracts { let debug_path = vec![solidity_file_name.as_str()]; let Some(contracts) = solidity_file_out.as_object() else { println!("skipping output for {:?} not an object..", &debug_path); @@ -34,7 +35,7 @@ pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { pathbuf.push(solidity_file_name); fs::create_dir_all(&pathbuf)?; - for (contract_name, contract_val) in contracts.iter() { + for (contract_name, contract_val) in contracts { let mut debug_path = debug_path.clone(); debug_path.push(contract_name); @@ -52,17 +53,14 @@ pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { let abi: JsonAbi = serde_json::from_str(&abi_json)?; for function in abi.functions() { let name = function.name.clone(); - methods - .entry(name) - .or_insert(Vec::default()) - .push(function.clone()); + methods.entry(name).or_default().push(function.clone()); } } else { println!("skipping abi for {:?}: not found", &debug_path); } - let mut header_body = String::default(); - let mut router_body = String::default(); + let mut header = String::default(); + let mut router = String::default(); for (simple_name, mut overloads) in methods { overloads.sort_by_key(|a| a.signature()); @@ -70,9 +68,10 @@ pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { for (index, overload) in overloads.iter().enumerate() { let c_name = match index { 0 => simple_name.clone(), - x => format!("{}_{}", simple_name, x), + x => format!("{simple_name}_{x}"), }; let selector = u32::from_be_bytes(overload.selector()); + let (hdr_params, call_params, payable) = match overload.state_mutability { StateMutability::Pure => { ("(uint8_t *input, size_t len)", "(input, len)", false) @@ -95,48 +94,52 @@ pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { }; let sig = &overload.signature(); + writeln!( + header, + "#define SELECTOR_{c_name} 0x{selector:08x} // {sig}" + )?; + writeln!(header, "ArbResult {c_name}{hdr_params}; // {sig}")?; - header_body += - &format!("#define SELECTOR_{c_name} 0x{selector:08x} // {sig}\n"); - header_body += &format!("ArbResult {c_name}{hdr_params}; // {sig}\n"); - router_body += &format!(" if (selector==SELECTOR_{c_name}) {{\n"); + writeln!(router, " if (selector==SELECTOR_{c_name}) {{")?; if !payable { - router_body += " if (!bebi32_is_0(value)) revert();\n"; + writeln!(router, " if (!bebi32_is_0(value)) revert();")?; } - router_body += &format!(" return {c_name}{call_params};\n }}\n"); + writeln!(router, " return {c_name}{call_params};\n }}")?; } } - if !header_body.is_empty() { - header_body.push('\n'); + if !header.is_empty() { + header.push('\n'); } debug_path.push("storageLayout"); + if let Some(Value::Object(layout_vals)) = properties.get("storageLayout") { debug_path.push("storage"); + if let Some(Value::Array(storage_arr)) = layout_vals.get("storage") { - for storage_val in storage_arr.iter() { + for storage_val in storage_arr { let Some(storage_obj) = storage_val.as_object() else { - println!("skipping output inside {:?}: not an object..", &debug_path); + println!("skipping output inside {debug_path:?}: not an object.."); continue; }; let Some(Value::String(label)) = storage_obj.get("label") else { - println!("skipping output inside {:?}: no label..", &debug_path); + println!("skipping output inside {debug_path:?}: no label.."); continue; }; let Some(Value::String(slot)) = storage_obj.get("slot") else { - println!("skipping output inside {:?}: no slot..", &debug_path); + println!("skipping output inside {debug_path:?}: no slot.."); continue; }; let Ok(slot) = slot.parse::() else { - println!("skipping output inside {:?}: slot not u64 ..", &debug_path); + println!("skipping output inside {debug_path:?}: slot not u64.."); continue; }; let Some(Value::String(val_type)) = storage_obj.get("type") else { - println!("skipping output inside {:?}: no type..", &debug_path); + println!("skipping output inside {debug_path:?}: no type.."); continue; }; let Some(Value::Number(read_offset)) = storage_obj.get("offset") else { - println!("skipping output inside {:?}: no offset..", &debug_path); + println!("skipping output inside {debug_path:?}: no offset.."); continue; }; let offset = match read_offset.as_i64() { @@ -159,24 +162,27 @@ pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { let mut slot_buf = vec![0u8; 32 - 8]; slot_buf.extend(slot.to_be_bytes()); - header_body += &format!( - "#define STORAGE_SLOT_{label} {} // {val_type}\n", + writeln!( + header, + "#define STORAGE_SLOT_{label} {} // {val_type}", c_bytearray_initializer(&slot_buf), - ); + )?; if val_type.starts_with("t_array(") { if val_type.ends_with(")dyn_storage") { let mut keccak = Keccak::v256(); keccak.update(&slot_buf); keccak.finalize(&mut slot_buf); - header_body += &format!( - "#define STORAGE_BASE_{label} {} // {val_type}\n", + writeln!( + header, + "#define STORAGE_BASE_{label} {} // {val_type}", c_bytearray_initializer(&slot_buf), - ); + )?; } } else if !val_type.starts_with("t_mapping") { - header_body += &format!( - "#define STORAGE_END_OFFSET_{label} {offset} // {val_type}\n", - ); + writeln!( + header, + "#define STORAGE_END_OFFSET_{label} {offset} // {val_type}", + )?; } } } else { @@ -187,7 +193,7 @@ pub fn c_gen(in_path: String, out_path: String) -> eyre::Result<()> { println!("skipping output for {:?}: not an object..", &debug_path); } debug_path.pop(); - if !header_body.is_empty() { + if !header.is_empty() { let mut unique_identifier = String::from("__"); unique_identifier += &solidity_file_name.to_uppercase(); unique_identifier += "_"; @@ -217,7 +223,7 @@ ArbResult default_func(void *storage, uint8_t *input, size_t len, bebi32 value); #endif // {uniq} "#, uniq = unique_identifier, - body = header_body + body = header ); let filename: String = contract_name.into(); @@ -225,7 +231,7 @@ ArbResult default_func(void *storage, uint8_t *input, size_t len, bebi32 value); fs::write(&pathbuf, &contents)?; pathbuf.pop(); } - if !router_body.is_empty() { + if !router.is_empty() { let contents = format!( r#" // autogenerated by cargo-stylus @@ -253,7 +259,7 @@ ArbResult {contract}_entry(uint8_t *input, size_t len) {{ ENTRYPOINT({contract}_entry) "#, contract = contract_name, - body = router_body + body = router ); let filename: String = contract_name.into(); diff --git a/src/c/header.rs b/src/c/header.rs index f18e4e5..6cfa2af 100644 --- a/src/c/header.rs +++ b/src/c/header.rs @@ -1,3 +1,6 @@ +// Copyright 2023, Offchain Labs, Inc. +// For licensing, see https://github.com/OffchainLabs/cargo-stylus/blob/main/licenses/COPYRIGHT.md + use alloy_json_abi::{Function, JsonAbi, StateMutability}; use eyre::bail; use serde_json::Value;