From 923b686adbd0cc50b56d8556ce9c3edbf1917928 Mon Sep 17 00:00:00 2001 From: cozfuttu Date: Fri, 24 Jan 2025 21:41:57 +0300 Subject: [PATCH 1/2] feat: move Slot type into it's own library --- Cargo.lock | 27 ++++ Cargo.toml | 3 + lib/arbitrum-verifier/Cargo.toml | 1 + lib/arbitrum-verifier/src/lib.rs | 6 +- lib/linea-verifier/Cargo.toml | 1 + lib/linea-verifier/src/lib.rs | 6 +- lib/scroll-verifier/Cargo.toml | 1 + lib/scroll-verifier/src/lib.rs | 2 +- lib/slotlib/Cargo.toml | 15 +++ lib/slotlib/src/lib.rs | 3 + lib/slotlib/src/slot.rs | 85 ++++++++++++ lib/unionlabs/Cargo.toml | 1 + lib/unionlabs/src/ethereum.rs | 6 +- tools/slot-calculator/Cargo.toml | 19 +++ tools/slot-calculator/src/main.rs | 206 ++++++++++++++++++++++++++++++ 15 files changed, 369 insertions(+), 13 deletions(-) create mode 100644 lib/slotlib/Cargo.toml create mode 100644 lib/slotlib/src/lib.rs create mode 100644 lib/slotlib/src/slot.rs create mode 100644 tools/slot-calculator/Cargo.toml create mode 100644 tools/slot-calculator/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 00ad6b6286..4207cd5a6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1391,6 +1391,7 @@ dependencies = [ "evm-storage-verifier", "rlp", "sha3 0.10.8", + "slotlib", "thiserror", "unionlabs", ] @@ -7041,6 +7042,7 @@ dependencies = [ "linea-types", "linea-zktrie", "rlp", + "slotlib", "thiserror", "unionlabs", ] @@ -10351,6 +10353,7 @@ dependencies = [ "rlp", "scroll-codec", "scroll-light-client-types", + "slotlib", "thiserror", "unionlabs", "zktrie", @@ -10902,6 +10905,29 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slot-calculator" +version = "0.1.0" +dependencies = [ + "clap 4.5.4", + "hex-literal", + "sha2 0.10.8", + "sha3 0.10.8", + "slotlib", + "typed-arena", + "unionlabs", +] + +[[package]] +name = "slotlib" +version = "0.1.0" +dependencies = [ + "hex-literal", + "sha2 0.10.8", + "sha3 0.10.8", + "unionlabs-primitives", +] + [[package]] name = "smallbitvec" version = "2.5.3" @@ -12758,6 +12784,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "sha3 0.10.8", + "slotlib", "ssz", "static_assertions 1.1.0 (git+https://github.com/nvzqz/static-assertions)", "subtle-encoding", diff --git a/Cargo.toml b/Cargo.toml index 0ac663b9a5..1848d89147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ members = [ "tools/devnet-utils", "tools/parse-wasm-client-type", + "tools/slot-calculator", "tools/tidy", "tools/move-bindgen", "lib/move-bindgen-derive", @@ -176,6 +177,7 @@ members = [ "lib/state-lens-light-client-types", "lib/create3", "lib/linea-types", + "lib/slotlib", ] [workspace.package] @@ -264,6 +266,7 @@ movement-light-client-types = { path = "lib/movement-light-client-types", defaul cosmos-sdk-event = { path = "lib/cosmos-sdk-event", default-features = false } serde-utils = { path = "lib/serde-utils", default-features = false } +slotlib = { path = "lib/slotlib", default-features = false } ssz = { path = "lib/ssz", default-features = false } ssz-derive = { path = "lib/ssz-derive", default-features = false } subset-of = { path = "lib/subset-of", default-features = false } diff --git a/lib/arbitrum-verifier/Cargo.toml b/lib/arbitrum-verifier/Cargo.toml index ce8486cc70..4c8b3089d0 100644 --- a/lib/arbitrum-verifier/Cargo.toml +++ b/lib/arbitrum-verifier/Cargo.toml @@ -19,6 +19,7 @@ arbitrum-light-client-types = { workspace = true } evm-storage-verifier = { workspace = true } rlp = { workspace = true } sha3 = { workspace = true } +slotlib = { workspace = true } thiserror = { workspace = true } unionlabs = { workspace = true } diff --git a/lib/arbitrum-verifier/src/lib.rs b/lib/arbitrum-verifier/src/lib.rs index d8ef983978..b01a3aa2b3 100644 --- a/lib/arbitrum-verifier/src/lib.rs +++ b/lib/arbitrum-verifier/src/lib.rs @@ -3,10 +3,8 @@ use core::fmt::Debug; use arbitrum_light_client_types::{ClientState, Header}; use evm_storage_verifier::{verify_account_storage_root, verify_storage_proof}; use sha3::{Digest, Keccak256}; -use unionlabs::{ - ethereum::slot::{MappingKey, Slot}, - primitives::{H256, U256}, -}; +use slotlib::{MappingKey, Slot}; +use unionlabs::primitives::{H256, U256}; #[derive(thiserror::Error, Debug, PartialEq, Clone)] pub enum Error { diff --git a/lib/linea-verifier/Cargo.toml b/lib/linea-verifier/Cargo.toml index 73b757f586..a829b1fb3f 100644 --- a/lib/linea-verifier/Cargo.toml +++ b/lib/linea-verifier/Cargo.toml @@ -21,5 +21,6 @@ linea-light-client-types = { workspace = true } linea-types = { workspace = true } linea-zktrie = { workspace = true } rlp = { workspace = true } +slotlib = { workspace = true } thiserror = { workspace = true } unionlabs = { workspace = true } diff --git a/lib/linea-verifier/src/lib.rs b/lib/linea-verifier/src/lib.rs index 333fd703f2..0ec30bece6 100644 --- a/lib/linea-verifier/src/lib.rs +++ b/lib/linea-verifier/src/lib.rs @@ -4,10 +4,8 @@ use evm_storage_verifier::{verify_account_storage_root, verify_storage_proof}; use gnark_mimc::new_mimc_constants_bls12_377; use linea_light_client_types::{ClientState, Header}; use linea_types::account::ZkAccount; -use unionlabs::{ - ethereum::slot::{MappingKey, Slot}, - primitives::{H256, U256}, -}; +use slotlib::{MappingKey, Slot}; +use unionlabs::primitives::{H256, U256}; #[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum Error { diff --git a/lib/scroll-verifier/Cargo.toml b/lib/scroll-verifier/Cargo.toml index 79362f017c..3944dc48f4 100644 --- a/lib/scroll-verifier/Cargo.toml +++ b/lib/scroll-verifier/Cargo.toml @@ -19,6 +19,7 @@ evm-storage-verifier = { workspace = true } rlp = { workspace = true } scroll-codec = { workspace = true } scroll-light-client-types = { workspace = true } +slotlib = { workspace = true } thiserror = { workspace = true } unionlabs = { workspace = true } zktrie = { workspace = true } diff --git a/lib/scroll-verifier/src/lib.rs b/lib/scroll-verifier/src/lib.rs index 3b31ac07e6..47f37659df 100644 --- a/lib/scroll-verifier/src/lib.rs +++ b/lib/scroll-verifier/src/lib.rs @@ -3,8 +3,8 @@ use core::fmt::Debug; use evm_storage_verifier::{verify_account_storage_root, verify_storage_proof}; use scroll_codec::{hash_batch, HashBatchError}; use scroll_light_client_types::{ClientState, Header}; +use slotlib::{MappingKey, Slot}; use unionlabs::{ - ethereum::slot::{MappingKey, Slot}, primitives::{H160, H256, U256}, scroll::account::Account, }; diff --git a/lib/slotlib/Cargo.toml b/lib/slotlib/Cargo.toml new file mode 100644 index 0000000000..e77a1adee7 --- /dev/null +++ b/lib/slotlib/Cargo.toml @@ -0,0 +1,15 @@ +[package] +edition.workspace = true +license-file.workspace = true +name = "slotlib" +repository.workspace = true +version = "0.1.0" + +[dependencies] +hex-literal = { workspace = true } +sha2 = { workspace = true } +sha3 = { workspace = true } +unionlabs-primitives = { workspace = true } + +[lints] +workspace = true diff --git a/lib/slotlib/src/lib.rs b/lib/slotlib/src/lib.rs new file mode 100644 index 0000000000..137f5f5dd8 --- /dev/null +++ b/lib/slotlib/src/lib.rs @@ -0,0 +1,3 @@ +pub mod slot; + +pub use crate::slot::{MappingKey, Slot}; diff --git a/lib/slotlib/src/slot.rs b/lib/slotlib/src/slot.rs new file mode 100644 index 0000000000..1e4a4abb12 --- /dev/null +++ b/lib/slotlib/src/slot.rs @@ -0,0 +1,85 @@ +use sha2::Digest; +use sha3::Keccak256; +use unionlabs_primitives::{H256, U256}; + +// Duplication of keccak256 function defined in /lib/unionlabs/ethereum.rs, otherwise it creates a dependency cycle. +#[inline] +#[must_use] +pub fn keccak256(bytes: impl AsRef<[u8]>) -> H256 { + Keccak256::new().chain_update(bytes).finalize().into() +} + +/// Solidity storage slot calculations. Note that this currently does not handle dynamic arrays with packed values; the index passed to [`Slot::Array`] will need to be calculated manually in this case. +pub enum Slot<'a> { + /// (base slot, index) + Array(&'a Slot<'a>, U256), + /// (base slot, mapping key) + Mapping(&'a Slot<'a>, MappingKey<'a>), + Offset(U256), +} + +impl Slot<'_> { + // https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#mappings-and-dynamic-arrays + #[inline] + #[must_use = "calculating the slot has no effect"] + // REVIEW: Make const? + pub fn slot(&self) -> U256 { + match self { + // keccak256(p) + Slot::Array(p, idx) => { + U256::from_be_bytes(*keccak256(p.slot().to_be_bytes()).get()) + *idx + } + // keccak256(h(k) . p) + Slot::Mapping(p, k) => { + let mut hasher = Keccak256::new(); + match &k { + MappingKey::String(string) => hasher.update(string.as_bytes()), + MappingKey::Uint256(k) => hasher.update(k.to_be_bytes()), + MappingKey::Uint64(k) => hasher.update(U256::from(*k).to_be_bytes()), + MappingKey::Bytes32(k) => hasher.update(k.get()), + }; + + U256::from_be_bytes( + hasher + .chain_update(p.slot().to_be_bytes()) + .finalize() + .into(), + ) + } + Slot::Offset(p) => *p, + } + } +} + +#[derive(Debug)] +pub enum MappingKey<'a> { + String(&'a str), + Uint256(U256), + Uint64(u64), + Bytes32(H256), +} + +#[test] +fn test() { + // Test contract uploaded here: https://sepolia.etherscan.io/address/0x6845dbaa9513d3d07737ea9f6e350011dcfeb9bd + + // mapping(uint256 => mapping(uint256 => uint256)[]) + let slot = Slot::Mapping( + &Slot::Array( + &Slot::Mapping( + &Slot::Offset(0u32.into()), + MappingKey::Uint256(123u32.into()), + ), + 1u32.into(), + ), + MappingKey::Uint256(100u32.into()), + ) + .slot(); + + assert_eq!( + ::new(slot.to_be_bytes()), + ::new(hex_literal::hex!( + "00a9b48fe93e5d10ebc2d9021d1477088c6292bf047876944343f57fdf3f0467" + )) + ); +} diff --git a/lib/unionlabs/Cargo.toml b/lib/unionlabs/Cargo.toml index 06e1007fe5..0d6c520825 100644 --- a/lib/unionlabs/Cargo.toml +++ b/lib/unionlabs/Cargo.toml @@ -53,6 +53,7 @@ near-primitives-core = { version = "0.21", optional = true } near-sdk = { workspace = true, optional = true } schemars = { workspace = true, features = ["derive"], optional = true } serde_bytes = "0.11.6" +slotlib = { workspace = true } unionlabs-primitives = { workspace = true, features = ["generic-array-compat", "serde", "base64"] } [dev-dependencies] diff --git a/lib/unionlabs/src/ethereum.rs b/lib/unionlabs/src/ethereum.rs index 4928cc2f46..037d6ed7b0 100644 --- a/lib/unionlabs/src/ethereum.rs +++ b/lib/unionlabs/src/ethereum.rs @@ -1,10 +1,8 @@ use sha2::Digest; use sha3::Keccak256; +use slotlib::{MappingKey, Slot}; -use crate::{ - ethereum::slot::{MappingKey, Slot}, - primitives::{H256, U256}, -}; +use crate::primitives::{H256, U256}; pub mod slot; diff --git a/tools/slot-calculator/Cargo.toml b/tools/slot-calculator/Cargo.toml new file mode 100644 index 0000000000..36476f8afd --- /dev/null +++ b/tools/slot-calculator/Cargo.toml @@ -0,0 +1,19 @@ +[package] +edition = { workspace = true } +license-file = { workspace = true } +name = "slot-calculator" +publish = false +repository = { workspace = true } +version = "0.1.0" + +[lints] +workspace = true + +[dependencies] +clap = { workspace = true, features = ["derive", "help"] } +hex-literal = { workspace = true } +sha2 = { workspace = true } +sha3 = { workspace = true } +slotlib = { workspace = true } +typed-arena = "2.0" +unionlabs = { workspace = true, features = ["rlp"] } diff --git a/tools/slot-calculator/src/main.rs b/tools/slot-calculator/src/main.rs new file mode 100644 index 0000000000..9a064bb5cc --- /dev/null +++ b/tools/slot-calculator/src/main.rs @@ -0,0 +1,206 @@ +use std::{collections::VecDeque, str::FromStr, vec}; + +use clap::{Arg, Command}; +use slotlib::{MappingKey, Slot}; +use typed_arena::Arena; +use unionlabs::primitives::{H256, U256}; + +// Examples: +// mapping(uint256 => uint256) => ["uint256"] +// mapping(uint256 => uint256[]) => ["uint256", "uint256[]"] +// mapping(uint256 => mapping(uint256 => uint256)) => ["uint256", "uint256"] +// mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)[])[]) => ["uint256", "mapping[]", "uint256", "mapping[]", "uint256"] +// mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)[]))[]) => ["uint256", "mapping[]", "uint256", "uint256", "mapping[]", "uint256"] +// mapping(uint256 => mapping(uint256 => uint256)[]) => ["uint256", "mapping[]", "uint256"] +fn parse_layout(layout: &str) -> Result, String> { + // 1. Basic validation + if !layout.starts_with("mapping(") || !layout.ends_with(')') { + return Err("Invalid layout".to_string()); + } + + // 2. Remove all 'mapping', then strip the first '(' and last ')' character. + let mut sanitized = layout.replace("mapping", ""); + sanitized = sanitized[1..sanitized.len() - 1].to_string(); + + // 3. Split by '=>', trim and remove any leftover '(' + let mut split_by_arrow: Vec = sanitized + .split("=>") + .map(|s| s.trim().replace("(", "")) + .collect(); + + // cloning the array so we can iterate indexes from the *original* split_by_arrow + // while we modify the *current* split_by_arrow in place. + let original_split = split_by_arrow.clone(); + + for (i, element) in original_split.iter().enumerate() { + let mapping_array_count = element.matches(")[]").count(); + if mapping_array_count == 0 { + continue; + } + + // 1) split element by ")[]" + // 2) skip the first chunk + // 3) in each chunk, count how many times ')' appears, subtract 1 + // 4) reverse at the end + let mut skip_indexes: Vec = element + .split(")[]") + .skip(1) + .map(|chunk| chunk.matches(')').count()) + .collect(); + skip_indexes.reverse(); + + // For each occurrence, insert "mapping[]" at index (i - j - skipCount). + for j in 1..=mapping_array_count { + let skip_count = skip_indexes[j - 1]; + let insert_index = (i as usize) - (j as usize) - (skip_count as usize); + split_by_arrow.insert(insert_index as usize, "mapping[]".to_string()); + } + } + + // 4. Final check on the last element: + // if it doesn't have "[]" or if it still contains ")[]", pop it + if let Some(last) = split_by_arrow.last() { + if !last.contains("[]") || last.contains(")[]") { + split_by_arrow.pop(); + } + } + + Ok(split_by_arrow) +} + +// MappingKey + U32 +#[derive(Debug)] +pub enum KeyTypes<'a> { + MappingIndex(MappingKey<'a>), + ArrayIndex(U256), +} + +fn parse_keys<'a>(parsed_layout: &Vec, keys: &'a str) -> Vec> { + let split_keys: Vec<&str> = keys.split(" ").collect(); + let mut final_keys: Vec> = vec![]; + for (i, parsed_layout_elem) in parsed_layout.iter().enumerate() { + if (*parsed_layout_elem).contains("[]") { + final_keys.push(KeyTypes::ArrayIndex( + split_keys[i].parse::().unwrap().into(), + )); + } else if *parsed_layout_elem == "uint256" { + final_keys.push(KeyTypes::MappingIndex(MappingKey::Uint256( + split_keys[i].parse::().unwrap().into(), + ))); + } else if *parsed_layout_elem == "string" { + final_keys.push(KeyTypes::MappingIndex(MappingKey::String(split_keys[i]))); + } else if *parsed_layout_elem == "uint64" { + final_keys.push(KeyTypes::MappingIndex(MappingKey::Uint64( + split_keys[i].parse::().unwrap(), + ))); + } else if *parsed_layout_elem == "bytes32" { + final_keys.push(KeyTypes::MappingIndex(MappingKey::Bytes32( + H256::from_str(split_keys[i]).unwrap(), + ))); + } else { + panic!("Unrecognized key!"); + }; + } + + final_keys +} + +// ["uint256", "mapping[]", "uint256"] +fn build_slot<'a>( + parsed_layout: &mut VecDeque, + parsed_keys: &mut VecDeque>, + arena: &'a Arena>, +) -> &'a Slot<'a> { + if parsed_layout.is_empty() { + return arena.alloc(Slot::Offset(U256::from(0u32))); + } + + let layout_part = parsed_layout.pop_front().unwrap(); + + if layout_part.contains("[]") { + let KeyTypes::ArrayIndex(i) = parsed_keys.pop_front().unwrap() else { + panic!("Expected an array index but got a mapping key!"); + }; + arena.alloc(Slot::Array( + build_slot(parsed_layout, parsed_keys, arena), + i, + )) + } else { + let KeyTypes::MappingIndex(mk) = parsed_keys.pop_front().unwrap() else { + panic!("Expected a mapping key but got an array index!"); + }; + arena.alloc(Slot::Mapping( + build_slot(parsed_layout, parsed_keys, arena), + mk, + )) + } +} + +fn calculate_slot(layout: &str, keys: &str) -> U256 { + let parsed_layout = parse_layout(layout).unwrap(); + let parsed_keys = parse_keys(&parsed_layout, keys); + + // we need a queue structure for popping first elements more efficiently, therefore we're using VecDeque + let mut parsed_layout = VecDeque::from(parsed_layout); + let mut parsed_keys = VecDeque::from(parsed_keys); + + let arena = Arena::new(); + let slot = build_slot(&mut parsed_layout, &mut parsed_keys, &arena); + slot.slot() +} + +fn main() { + let matches = Command::new("Slot Calculator (post-order)") + .version("1.0") + .about("Calculates Solidity storage slots for various layouts in a post-order manner") + .arg( + Arg::new("layout") + .long("layout") + .value_name("LAYOUT") + .required(true) + .help("e.g. 'mapping(uint256 => mapping(uint256 => uint256)[])'"), + ) + .arg( + Arg::new("keys") + .long("keys") + .value_name("KEYS") + .required(true) + .num_args(1..) // Accept one or more + .help("The keys in the order that matches your snippet, e.g. 123 1 100"), + ) + .get_matches(); + + let layout = matches + .get_one::("layout") + .expect("Missing --layout"); + let keys_collected: Vec = matches + .get_many::("keys") + .expect("Missing --keys") + .map(|s| s.to_string()) + .collect(); + + // Combine user-provided keys into "123 1 100" form: + let keys_str = keys_collected.join(" "); + + let slot_hex = calculate_slot(layout, &keys_str); + + println!( + "Calculated storage slot: {}", + ::new(slot_hex.to_be_bytes()) + ); +} + +#[test] +fn test_calculate_slot() { + let layout = "mapping(uint256 => mapping(uint256 => uint256)[])"; + let keys = "100 1 123"; + + let slot = calculate_slot(layout, keys); + + assert_eq!( + ::new(slot.to_be_bytes()), + ::new(hex_literal::hex!( + "00a9b48fe93e5d10ebc2d9021d1477088c6292bf047876944343f57fdf3f0467" + )) + ); +} From 62ba46926dbc6f6ec4ae7ad1e0f9c125b39d4bbe Mon Sep 17 00:00:00 2001 From: cozfuttu Date: Wed, 29 Jan 2025 02:36:54 +0300 Subject: [PATCH 2/2] feat: added array support and used syn_solidity for parsing --- Cargo.lock | 158 +++++++++++------------ tools/slot-calculator/Cargo.toml | 14 +-- tools/slot-calculator/src/main.rs | 200 +++++++++++------------------- 3 files changed, 159 insertions(+), 213 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4207cd5a6c..8c3955f880 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -449,7 +449,7 @@ checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -560,7 +560,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -577,7 +577,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", "syn-solidity", "tiny-keccak", ] @@ -595,7 +595,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.77", + "syn 2.0.96", "syn-solidity", ] @@ -1796,7 +1796,7 @@ dependencies = [ "proc-macro2", "quote", "strum 0.26.3", - "syn 2.0.77", + "syn 2.0.96", "thiserror", ] @@ -1855,7 +1855,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -1866,7 +1866,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -1931,7 +1931,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -2056,7 +2056,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -2586,7 +2586,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", "syn_derive", ] @@ -2990,7 +2990,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -3431,7 +3431,7 @@ checksum = "1b5658b1dc64e10b56ae7a449f678f96932a96f6cfad1769d608d1d1d656480a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -3479,7 +3479,7 @@ checksum = "c8ef1b5835a65fcca3ab8b9a02b4f4dacc78e233a5c2f20b270efb9db0666d12" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -3841,7 +3841,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4096,7 +4096,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4107,7 +4107,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4192,7 +4192,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4202,7 +4202,7 @@ source = "git+https://github.com/unionlabs/arbitrary#b5796f1a0066dc5707d7681a80e dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4223,7 +4223,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4233,7 +4233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" dependencies = [ "derive_builder_core", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4266,7 +4266,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", "unicode-xid", ] @@ -4638,7 +4638,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4650,7 +4650,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4661,7 +4661,7 @@ checksum = "6d3e2610493c0a1fc3bf33fb420650c6ebf7990c55e3d5e71a57bee374486824" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -4830,7 +4830,7 @@ dependencies = [ "prettier-please", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -5132,7 +5132,7 @@ dependencies = [ "proc-macro2", "quote", "sp-crypto-hashing", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -5145,7 +5145,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -5156,7 +5156,7 @@ checksum = "ed971c6435503a099bdac99fe4c5bea08981709e5b5a0a8535a1856f48561191" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -5259,7 +5259,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -6794,7 +6794,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -7119,7 +7119,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -7133,7 +7133,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -7144,7 +7144,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -7155,7 +7155,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -7164,7 +7164,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -7359,7 +7359,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.77", + "syn 2.0.96", "tokio", "tracing", ] @@ -7370,7 +7370,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -7977,7 +7977,7 @@ dependencies = [ "serde_json", "strum 0.26.3", "strum_macros 0.26.4", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -8224,7 +8224,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -8301,7 +8301,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -8665,7 +8665,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -8807,7 +8807,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -8928,7 +8928,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -8969,7 +8969,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.77", + "syn 2.0.96", "thiserror", ] @@ -9042,7 +9042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -9052,7 +9052,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -9160,7 +9160,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -9183,14 +9183,14 @@ checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -9292,7 +9292,7 @@ dependencies = [ "prost 0.12.6", "prost-types", "regex", - "syn 2.0.77", + "syn 2.0.96", "tempfile", "which", ] @@ -9307,7 +9307,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -9320,7 +9320,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -9706,7 +9706,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -10278,7 +10278,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -10579,7 +10579,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -10590,7 +10590,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -10645,7 +10645,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -10696,7 +10696,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -10911,9 +10911,9 @@ version = "0.1.0" dependencies = [ "clap 4.5.4", "hex-literal", - "sha2 0.10.8", - "sha3 0.10.8", + "proc-macro2", "slotlib", + "syn-solidity", "typed-arena", "unionlabs", ] @@ -11285,7 +11285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -11493,7 +11493,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -11506,7 +11506,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -11526,7 +11526,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.77", + "syn 2.0.96", "trybuild", ] @@ -11583,9 +11583,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -11594,14 +11594,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f76fe0a3e1476bdaa0775b9aec5b869ed9520c2b2fedfe9c6df3618f8ea6290b" +checksum = "b84e4d83a0a6704561302b917a932484e1cae2d8c6354c64be8b7bac1c1fe057" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -11613,7 +11613,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -11886,7 +11886,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -12072,7 +12072,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -12351,7 +12351,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -12613,7 +12613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -14020,7 +14020,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", "wasm-bindgen-shared", ] @@ -14054,7 +14054,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -14466,7 +14466,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] @@ -14486,7 +14486,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] [[package]] diff --git a/tools/slot-calculator/Cargo.toml b/tools/slot-calculator/Cargo.toml index 36476f8afd..9b47f2fe58 100644 --- a/tools/slot-calculator/Cargo.toml +++ b/tools/slot-calculator/Cargo.toml @@ -10,10 +10,10 @@ version = "0.1.0" workspace = true [dependencies] -clap = { workspace = true, features = ["derive", "help"] } -hex-literal = { workspace = true } -sha2 = { workspace = true } -sha3 = { workspace = true } -slotlib = { workspace = true } -typed-arena = "2.0" -unionlabs = { workspace = true, features = ["rlp"] } +clap = { workspace = true, features = ["derive", "help"] } +hex-literal = { workspace = true } +proc-macro2 = "1.0.93" +slotlib = { workspace = true } +syn-solidity = "0.8.19" +typed-arena = "2.0" +unionlabs = { workspace = true, features = ["rlp"] } diff --git a/tools/slot-calculator/src/main.rs b/tools/slot-calculator/src/main.rs index 9a064bb5cc..debf2c42d1 100644 --- a/tools/slot-calculator/src/main.rs +++ b/tools/slot-calculator/src/main.rs @@ -1,151 +1,98 @@ -use std::{collections::VecDeque, str::FromStr, vec}; - use clap::{Arg, Command}; +use proc_macro2::TokenStream; use slotlib::{MappingKey, Slot}; +use std::{collections::VecDeque, str::FromStr}; +use syn_solidity::{parse2, Item, Type}; use typed_arena::Arena; use unionlabs::primitives::{H256, U256}; // Examples: -// mapping(uint256 => uint256) => ["uint256"] -// mapping(uint256 => uint256[]) => ["uint256", "uint256[]"] -// mapping(uint256 => mapping(uint256 => uint256)) => ["uint256", "uint256"] -// mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)[])[]) => ["uint256", "mapping[]", "uint256", "mapping[]", "uint256"] -// mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)[]))[]) => ["uint256", "mapping[]", "uint256", "uint256", "mapping[]", "uint256"] -// mapping(uint256 => mapping(uint256 => uint256)[]) => ["uint256", "mapping[]", "uint256"] -fn parse_layout(layout: &str) -> Result, String> { - // 1. Basic validation - if !layout.starts_with("mapping(") || !layout.ends_with(')') { - return Err("Invalid layout".to_string()); +// mapping(uint256 => uint256) +// uint256[] => ["uint256[]"] +// mapping(uint256 => uint256[]) +// mapping(uint256 => mapping(uint256 => uint256)) +// mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)[])[]) +// mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)[]))[]) +// mapping(uint256 => mapping(uint256 => uint256)[]) +fn parse_layout(layout: &mut String) -> Result { + // Check if the layout already includes a visibility modifier and a variable name + if !layout.contains("public") && !layout.contains("internal") && !layout.contains("private") { + layout.push_str(" public dummyName;"); } - // 2. Remove all 'mapping', then strip the first '(' and last ')' character. - let mut sanitized = layout.replace("mapping", ""); - sanitized = sanitized[1..sanitized.len() - 1].to_string(); - - // 3. Split by '=>', trim and remove any leftover '(' - let mut split_by_arrow: Vec = sanitized - .split("=>") - .map(|s| s.trim().replace("(", "")) - .collect(); - - // cloning the array so we can iterate indexes from the *original* split_by_arrow - // while we modify the *current* split_by_arrow in place. - let original_split = split_by_arrow.clone(); - - for (i, element) in original_split.iter().enumerate() { - let mapping_array_count = element.matches(")[]").count(); - if mapping_array_count == 0 { - continue; - } - - // 1) split element by ")[]" - // 2) skip the first chunk - // 3) in each chunk, count how many times ')' appears, subtract 1 - // 4) reverse at the end - let mut skip_indexes: Vec = element - .split(")[]") - .skip(1) - .map(|chunk| chunk.matches(')').count()) - .collect(); - skip_indexes.reverse(); - - // For each occurrence, insert "mapping[]" at index (i - j - skipCount). - for j in 1..=mapping_array_count { - let skip_count = skip_indexes[j - 1]; - let insert_index = (i as usize) - (j as usize) - (skip_count as usize); - split_by_arrow.insert(insert_index as usize, "mapping[]".to_string()); - } - } - - // 4. Final check on the last element: - // if it doesn't have "[]" or if it still contains ")[]", pop it - if let Some(last) = split_by_arrow.last() { - if !last.contains("[]") || last.contains(")[]") { - split_by_arrow.pop(); - } + let parsed_layout = layout + .parse::() + .map_err(|_| "Failed to parse layout".to_string())?; + let parsed_layout = parse2(parsed_layout).map_err(|e| e.to_string())?; + + match &parsed_layout.items[0] { + Item::Variable(var) => match &var.ty { + Type::Mapping(map) => Ok(Type::Mapping(map.clone())), + Type::Array(arr) => Ok(Type::Array(arr.clone())), + _ => return Err("Unsupported type".to_string()), + }, + _ => return Err("Unsupported item".to_string()), } - - Ok(split_by_arrow) } -// MappingKey + U32 -#[derive(Debug)] -pub enum KeyTypes<'a> { - MappingIndex(MappingKey<'a>), - ArrayIndex(U256), -} - -fn parse_keys<'a>(parsed_layout: &Vec, keys: &'a str) -> Vec> { - let split_keys: Vec<&str> = keys.split(" ").collect(); - let mut final_keys: Vec> = vec![]; - for (i, parsed_layout_elem) in parsed_layout.iter().enumerate() { - if (*parsed_layout_elem).contains("[]") { - final_keys.push(KeyTypes::ArrayIndex( - split_keys[i].parse::().unwrap().into(), - )); - } else if *parsed_layout_elem == "uint256" { - final_keys.push(KeyTypes::MappingIndex(MappingKey::Uint256( - split_keys[i].parse::().unwrap().into(), - ))); - } else if *parsed_layout_elem == "string" { - final_keys.push(KeyTypes::MappingIndex(MappingKey::String(split_keys[i]))); - } else if *parsed_layout_elem == "uint64" { - final_keys.push(KeyTypes::MappingIndex(MappingKey::Uint64( - split_keys[i].parse::().unwrap(), - ))); - } else if *parsed_layout_elem == "bytes32" { - final_keys.push(KeyTypes::MappingIndex(MappingKey::Bytes32( - H256::from_str(split_keys[i]).unwrap(), - ))); - } else { - panic!("Unrecognized key!"); - }; +fn parse_mapping_key<'a>(key_type: &'a Type, key: &'a str) -> MappingKey<'a> { + match key_type { + Type::Uint(_, size) => { + let size = size.and_then(|s| Some(s.get())).unwrap_or(256); + match size { + 256 => MappingKey::Uint256(U256::from( + key.parse::().expect("Invalid uint256 key"), + )), + 64 => MappingKey::Uint64(key.parse::().expect("Invalid uint64 key")), + _ => panic!("Unsupported uint size: {}", size), + } + } + Type::FixedBytes(_, size) => { + let size = size.get(); + match size { + 32 => MappingKey::Bytes32(H256::from_str(key).expect("Invalid bytes32 key")), + _ => panic!("Unsupported bytes size: {}", size), + } + } + Type::String(_) => MappingKey::String(key), + _ => panic!("Unsupported mapping key type"), } - - final_keys } -// ["uint256", "mapping[]", "uint256"] fn build_slot<'a>( - parsed_layout: &mut VecDeque, - parsed_keys: &mut VecDeque>, + parsed_layout: &'a Type, + keys: &mut VecDeque<&'a str>, arena: &'a Arena>, ) -> &'a Slot<'a> { - if parsed_layout.is_empty() { - return arena.alloc(Slot::Offset(U256::from(0u32))); - } - - let layout_part = parsed_layout.pop_front().unwrap(); - - if layout_part.contains("[]") { - let KeyTypes::ArrayIndex(i) = parsed_keys.pop_front().unwrap() else { - panic!("Expected an array index but got a mapping key!"); - }; - arena.alloc(Slot::Array( - build_slot(parsed_layout, parsed_keys, arena), - i, - )) - } else { - let KeyTypes::MappingIndex(mk) = parsed_keys.pop_front().unwrap() else { - panic!("Expected a mapping key but got an array index!"); - }; - arena.alloc(Slot::Mapping( - build_slot(parsed_layout, parsed_keys, arena), - mk, - )) + let key: &str = match keys.pop_front() { + Some(k) => k, + None => return arena.alloc(Slot::Offset(U256::from(0u32))), + }; + match parsed_layout { + Type::Mapping(mapping) => arena.alloc(Slot::Mapping( + build_slot(mapping.value.as_ref(), keys, arena), + parse_mapping_key(mapping.key.as_ref(), key), + )), + Type::Array(arr) => arena.alloc(Slot::Array( + build_slot(arr.ty.as_ref(), keys, arena), + U256::from(key.parse::().expect("Invalid array index")), + )), + _ => panic!("Unsupported layout type or wrong key count."), } } fn calculate_slot(layout: &str, keys: &str) -> U256 { - let parsed_layout = parse_layout(layout).unwrap(); - let parsed_keys = parse_keys(&parsed_layout, keys); - - // we need a queue structure for popping first elements more efficiently, therefore we're using VecDeque - let mut parsed_layout = VecDeque::from(parsed_layout); - let mut parsed_keys = VecDeque::from(parsed_keys); + let parsed_layout = parse_layout(&mut layout.to_string()).unwrap(); + let mut split_keys: VecDeque<&str> = keys.split(" ").collect(); let arena = Arena::new(); - let slot = build_slot(&mut parsed_layout, &mut parsed_keys, &arena); + let slot = build_slot(&parsed_layout, &mut split_keys, &arena); + if split_keys.len() != 0 { + eprintln!( + "Warning: Unused keys: {:?}. The calculated slot might be wrong. Please check the layout and keys you provided.", + split_keys + ); + } slot.slot() } @@ -179,7 +126,6 @@ fn main() { .map(|s| s.to_string()) .collect(); - // Combine user-provided keys into "123 1 100" form: let keys_str = keys_collected.join(" "); let slot_hex = calculate_slot(layout, &keys_str); @@ -192,7 +138,7 @@ fn main() { #[test] fn test_calculate_slot() { - let layout = "mapping(uint256 => mapping(uint256 => uint256)[])"; + let layout = "mapping(uint256 => mapping(uint256 => uint256)[]) public test;"; let keys = "100 1 123"; let slot = calculate_slot(layout, keys);