Skip to content

Commit

Permalink
use writeln
Browse files Browse the repository at this point in the history
  • Loading branch information
rachel-bousfield committed Sep 17, 2023
1 parent b736882 commit 5b1b905
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 43 deletions.
92 changes: 49 additions & 43 deletions src/c/gen.rs
Original file line number Diff line number Diff line change
@@ -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<String> = 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<()> {
Expand All @@ -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);
Expand All @@ -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);

Expand All @@ -52,27 +53,25 @@ 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());

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)
Expand All @@ -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::<u64>() 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() {
Expand All @@ -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 {
Expand All @@ -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 += "_";
Expand Down Expand Up @@ -217,15 +223,15 @@ 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();
pathbuf.push(filename + ".h");
fs::write(&pathbuf, &contents)?;
pathbuf.pop();
}
if !router_body.is_empty() {
if !router.is_empty() {
let contents = format!(
r#" // autogenerated by cargo-stylus
Expand Down Expand Up @@ -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();
Expand Down
3 changes: 3 additions & 0 deletions src/c/header.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down

0 comments on commit 5b1b905

Please sign in to comment.