From 9e9ac85f5633f359fbeb9603e6c486d0ee2632aa Mon Sep 17 00:00:00 2001 From: Eugenio Date: Tue, 30 Apr 2024 16:54:08 -0300 Subject: [PATCH 1/5] add evm_version to avoid NOT_ACTIVATED issues --- foundry.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/foundry.toml b/foundry.toml index d672a2c..85ad840 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,6 +2,7 @@ out = 'out' libs = ['lib'] ffi = true +evm_version = "cancun" fs_permissions = [ { access = "read", path = "./test/auth/mocks/AuthWrappers.huff" }, { access = "read", path = "./test/auth/mocks/OwnedWrappers.huff" }, From 3ccca4955fef958799d3a996986175a6be83e477 Mon Sep 17 00:00:00 2001 From: Eugenio Date: Tue, 30 Apr 2024 16:56:41 -0300 Subject: [PATCH 2/5] Refactor to Hashmap using BALLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gas snapshot; ``` forge snapshot --mc Hash --ffi --fuzz-seed=11 --diff [⠊] Compiling... No files changed, compilation skipped Ran 6 tests for test/data-structures/Hashmap.t.sol:HashmapTest [PASS] testGetKey(bytes32) (runs: 1006, μ: 7550, ~: 7550) [PASS] testGetKeys(bytes32,bytes32) (runs: 1006, μ: 7623, ~: 7623) [PASS] testSetKey(bytes32,bytes32) (runs: 1006, μ: 28964, ~: 28984) [PASS] testSetKeys(bytes32,bytes32,bytes32) (runs: 1006, μ: 29153, ~: 29153) [PASS] testSetKeys2D(bytes32,bytes32,bytes32,bytes32) (runs: 1006, μ: 29497, ~: 29497) [PASS] testSetKeys3D(bytes32,bytes32,bytes32,bytes32,bytes32) (runs: 1006, μ: 29888, ~: 29888) Suite result: ok. 6 passed; 0 failed; 0 skipped; finished in 54.73ms (226.84ms CPU time) Ran 1 test suite in 58.31ms (54.73ms CPU time): 6 tests passed, 0 failed, 0 skipped (6 total tests) testGetKey(bytes32) (gas: 0 (0.000%)) testGetKeys(bytes32,bytes32) (gas: 0 (0.000%)) testSetKey(bytes32,bytes32) (gas: 0 (0.000%)) testSetKeys(bytes32,bytes32,bytes32) (gas: 0 (0.000%)) testSetKeys2D(bytes32,bytes32,bytes32,bytes32) (gas: -12 (-0.041%)) testSetKeys3D(bytes32,bytes32,bytes32,bytes32,bytes32) (gas: -24 (-0.080%)) Overall gas change: -36 (-0.027%) `` --- src/data-structures/Hashmap.balls | 100 +++++++++++++ src/data-structures/Hashmap.huff | 229 +++++++++++++++--------------- 2 files changed, 216 insertions(+), 113 deletions(-) create mode 100644 src/data-structures/Hashmap.balls diff --git a/src/data-structures/Hashmap.balls b/src/data-structures/Hashmap.balls new file mode 100644 index 0000000..2c53003 --- /dev/null +++ b/src/data-structures/Hashmap.balls @@ -0,0 +1,100 @@ +/// @title HashMap +/// @notice SPDX-License-Identifier: MIT +/// @author asnared + +/// @notice A Module Encapsulating HashMap Methods +/// @notice Adapted from + +/// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. +/// @notice Port to BALLs by eugenioclrc taken from https://github.com/huff-language/huffmate/blob/4e2c9bd3412ab8cc65f6ceadafc01a1ff1815796/src/data-structures/Hashmap.huff + +/// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. +fn GET_SLOT_FROM_KEY(key) -> (hashed) { + // Load the data into memory and hash it, while preserving the memory location. + mstore(mem_ptr, key) + // Hash the data, generating a key. + hashed = sha3(mem_ptr, 0x20) +} + +/// @notice Given two keys (ie a slot and a key), hash them together, generating a slot for a secondary hashmap. +fn GET_SLOT_FROM_KEYS(slot, key) -> (hashed) { + // Load the data into memory. + mstore(add(mem_ptr, 0x20), slot) + mstore(mem_ptr, key) + + + // Hash the data, generating a slot. + hashed = sha3(mem_ptr, 0x40) +} + + +/// @notice Calculate the slot from two keys +fn GET_SLOT_FROM_KEYS_2D(slot, key1, key2) -> (hashed) { + // Load the data into memory. + mstore(add(mem_ptr, 0x20), slot) + mstore(mem_ptr, key1) + sha3(mem_ptr, 0x40) + + mstore(add(mem_ptr, 0x20), key2) + + // Hash the data, generating a slot. + hashed = sha3(mem_ptr, 0x40) +} + +/// @notice Calculate the slot from three keys +fn GET_SLOT_FROM_KEYS_3D(slot, key1, key2, key3) -> (hashed) { + // Load the data into memory + mstore(add(mem_ptr, 0x20), slot) + // concat the first two keys + mstore(mem_ptr, key1) + sha3(mem_ptr, 0x40) + + // put key2 in memory, before slot1 + mstore(add(mem_ptr, 0x20), key2) + sha3(mem_ptr, 0x40) + + // put key3 in memory, before slot2 + mstore(add(mem_ptr, 0x20), key3) + // Hash the data, generating the final slot3 + hashed = sha3(mem_ptr, 0x40) +} + +/// @notice Load an element onto the stack from a key +fn LOAD_ELEMENT(key) -> (value) { + value = sload(GET_SLOT_FROM_KEY(key)) +} + +/// @notice Load an element onto the stack from two keys +fn LOAD_ELEMENT_FROM_KEYS(key1, key2) -> (value) { + value = sload(GET_SLOT_FROM_KEYS(key1, key2)) +} + +/// @notice Load an element onto the stack from a slot and two keys +fn LOAD_ELEMENT_FROM_KEYS_2D(slot, key1, key2) -> (value) { + value = sload(GET_SLOT_FROM_KEYS_2D(slot, key1, key2)) +} + +/// @notice Load an element onto the stack from a slot and three keys +fn LOAD_ELEMENT_FROM_KEYS_3D(slot, key1, key2, key3) -> (value) { + value = sload(GET_SLOT_FROM_KEYS_3D(slot, key1, key2, key3)) +} + +/// @notice Store an element from a key +fn STORE_ELEMENT(key, value) { + sstore(GET_SLOT_FROM_KEY(key), value) +} + +/// @notice Store an element from two keys +fn STORE_ELEMENT_FROM_KEYS(key1, key2, value) { + sstore(GET_SLOT_FROM_KEYS(key1, key2), value) +} + +/// @notice Store an element from a slot and two keys +fn STORE_ELEMENT_FROM_KEYS_2D(slot, key1, key2, value) { + sstore(GET_SLOT_FROM_KEYS_2D(slot, key1, key2), value) +} + +/// @notice Store an element from a slot and three keys +fn STORE_ELEMENT_FROM_KEYS_3D(slot, key1, key2, key3, value) { + sstore(GET_SLOT_FROM_KEYS_3D(slot, key1, key2, key3), value) +} diff --git a/src/data-structures/Hashmap.huff b/src/data-structures/Hashmap.huff index 91d8ab2..9fe44be 100644 --- a/src/data-structures/Hashmap.huff +++ b/src/data-structures/Hashmap.huff @@ -1,160 +1,163 @@ /// @title HashMap /// @notice SPDX-License-Identifier: MIT /// @author asnared + /// @notice A Module Encapsulating HashMap Methods /// @notice Adapted from /// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. -#define macro GET_SLOT_FROM_KEY(mem_ptr) = takes(1) returns (1) { - // Input stack: [key] - // Load the data into memory and hash it, while preserving the memory location. - // [, key] - mstore // [] +/// @notice Port to BALLs by eugenioclrc taken from https://github.com/huff-language/huffmate/blob/4e2c9bd3412ab8cc65f6ceadafc01a1ff1815796/src/data-structures/Hashmap.huff + +/// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. - // Hash the data, generating a key. - 0x20 // [32] - // [, 32] - sha3 // [slot] +/// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. +#define macro GET_SLOT_FROM_KEY(mem_ptr) = takes(1) returns(1) { + // takes: [key] + // [key, mem_ptr] + mstore // [] + 0x20 // [0x20] + // [0x20, mem_ptr] + sha3 // [hashed] + // returns: [hashed] } /// @notice Given two keys (ie a slot and a key), hash them together, generating a slot for a secondary hashmap. -#define macro GET_SLOT_FROM_KEYS(mem_ptr) = takes(2) returns (1) { - // Input stack: [slot, key] - // Load the data into memory. - 0x20 add // [ + 32, slot, key] - mstore // [key] - // [, key] - mstore // [] - - // Hash the data, generating a slot. - 0x40 // [64] - // [, 64] - sha3 // [slot] +#define macro GET_SLOT_FROM_KEYS(mem_ptr) = takes(2) returns(1) { + // takes: [key, slot] + // [key, slot, mem_ptr] + 0x20 // [key, slot, mem_ptr, 0x20] + add // [key, slot, add(0x20, mem_ptr)] + mstore // [key] + // [key, mem_ptr] + mstore // [] + 0x40 // [0x40] + // [0x40, mem_ptr] + sha3 // [hashed] + // returns: [hashed] } /// @notice Calculate the slot from two keys -#define macro GET_SLOT_FROM_KEYS_2D(mem_ptr) = takes(3) returns (1) { - // Input stack: [slot, key1, key2] - // Load the data into memory - 0x20 add // [ + 32, slot, key1, key2] - mstore // [key1, key2] - - // next byte - // [, key1, key2] - mstore // [key2] - - 0x40 // [0x40, key2] - // [, 0x40, key2] - sha3 // [hash, key2] - - // concat the two keys - 0x20 add // [ + 32, hash, key2] put hash in memory - mstore // [key2] - - // next byte - // [, key2] - mstore // [] - - // Hash the data, generating a slot. - 0x40 // [0x40] - // [, 0x40] - sha3 // [slot] +#define macro GET_SLOT_FROM_KEYS_2D(mem_ptr) = takes(3) returns(1) { + // takes: [key2, key1, slot] + 0x20 // [key2, key1, slot, 0x20] + // [key2, key1, slot, 0x20, mem_ptr] + add // [key2, key1, slot, add(mem_ptr, 0x20)] + mstore // [key2, key1] + // [key2, key1, mem_ptr] + mstore // [key2] + 0x20 // [key2, 0x20] + // [key2, 0x20, mem_ptr] + 0x40 // [key2, 0x20, mem_ptr, 0x40] + // [key2, 0x20, mem_ptr, 0x40, mem_ptr] + sha3 // [key2, 0x20, mem_ptr, sha3(mem_ptr, 0x40)] + pop // [key2, 0x20, mem_ptr] + add // [key2, add(mem_ptr, 0x20)] + mstore // [] + 0x40 // [0x40] + // [0x40, mem_ptr] + sha3 // [hashed] + // returns: [hashed] } /// @notice Calculate the slot from three keys -#define macro GET_SLOT_FROM_KEYS_3D(mem_ptr) = takes(4) returns (1) { - // Input stack: [slot, key1, key2, key3] - // Load the data into memory - 0x20 add // [ + 32, slot, key1, key2, key3] - swap1 dup2 // [ + 32, slot, + 32, key1, key2, key3] - mstore // [ + 32, key1, key2, key3] - - swap1 // [, key1, + 32, key2, key3] - mstore // [ + 32, key2, key3] - - 0x40 // [0x40, + 32, key2, key3] - // [, 0x40, + 32, key2, key3] - sha3 // [slot1, + 32, key2, key3] - - // concat the first two keys - dup2 // [ + 32, slot1, + 32, key2, key3] put slot1 in memory - mstore // [ + 32, key2, key3] - - // put key2 in memory, before slot1 - swap1 // [key2, + 32, key3] - // [, key2, + 32, key3] - mstore // [key3] - - 0x40 // [0x40, + 32, key3] - // [, 0x40, + 32, key3] - sha3 // [slot2, + 32, key3] - - // concat with the third key - swap1 // [ + 32, slot2, key3] put slot2 in memory - mstore // [key3] - - // put key3 in memory, before slot2 - // [, key3] - mstore // [] - - // Hash the data, generating the final slot3 - 0x40 // [0x40] - // [, 0x40] - sha3 // [slot3] +#define macro GET_SLOT_FROM_KEYS_3D(mem_ptr) = takes(4) returns(1) { + // takes: [key3, key2, key1, slot] + 0x20 // [key3, key2, key1, slot, 0x20] + // [key3, key2, key1, slot, 0x20, mem_ptr] + add // [key3, key2, key1, slot, add(mem_ptr, 0x20)] + mstore // [key3, key2, key1] + // [key3, key2, key1, mem_ptr] + mstore // [key3, key2] + 0x20 // [key3, key2, 0x20] + 0x40 // [key3, key2, 0x20, 0x40] + // [key3, key2, 0x20, 0x40, mem_ptr] + sha3 // [key3, key2, 0x20, sha3(mem_ptr, 0x40)] + pop // [key3, key2, 0x20] + // [key3, key2, 0x20, mem_ptr] + add // [key3, key2, add(mem_ptr, 0x20)] + mstore // [key3] + 0x20 // [key3, 0x20] + // [key3, 0x20, mem_ptr] + add // [key3, add(mem_ptr, 0x20)] + 0x40 // [key3, add(mem_ptr, 0x20), 0x40] + // [key3, add(mem_ptr, 0x20), 0x40, mem_ptr] + sha3 // [key3, add(mem_ptr, 0x20), sha3(mem_ptr, 0x40)] + pop // [key3, add(mem_ptr, 0x20)] + mstore // [] + 0x40 // [0x40] + // [0x40, mem_ptr] + sha3 // [hashed] + // returns: [hashed] } /// @notice Load an element onto the stack from a key #define macro LOAD_ELEMENT(mem_ptr) = takes(1) returns(1) { - // Input stack: [key] - GET_SLOT_FROM_KEY() // [slot] - sload // [value] + // takes: [key] + GET_SLOT_FROM_KEY() + // [GET_SLOT_FROM_KEY(key)] + sload // [value] + // returns: [value] } /// @notice Load an element onto the stack from two keys #define macro LOAD_ELEMENT_FROM_KEYS(mem_ptr) = takes(2) returns(1) { - // Input stack: [key1, key2] - GET_SLOT_FROM_KEYS() // [slot] - sload // [value] + // takes: [key2, key1] + GET_SLOT_FROM_KEYS() + // [GET_SLOT_FROM_KEYS(key1, key2)] + sload // [value] + // returns: [value] } /// @notice Load an element onto the stack from a slot and two keys #define macro LOAD_ELEMENT_FROM_KEYS_2D(mem_ptr) = takes(3) returns(1) { - // Input stack: [slot, key1, key2] - GET_SLOT_FROM_KEYS_2D() // [slot] - sload // [value] + // takes: [key2, key1, slot] + GET_SLOT_FROM_KEYS_2D() + // [GET_SLOT_FROM_KEYS_2D(slot, key1, key2)] + sload // [value] + // returns: [value] } /// @notice Load an element onto the stack from a slot and three keys #define macro LOAD_ELEMENT_FROM_KEYS_3D(mem_ptr) = takes(4) returns(1) { - // Input stack: [slot, key1, key2, key3] - GET_SLOT_FROM_KEYS_3D() // [slot] - sload // [value] + // takes: [key3, key2, key1, slot] + GET_SLOT_FROM_KEYS_3D() + // [GET_SLOT_FROM_KEYS_3D(slot, key1, key2, key3)] + sload // [value] + // returns: [value] } /// @notice Store an element from a key #define macro STORE_ELEMENT(mem_ptr) = takes(2) returns(0) { - // Input stack: [key, value] - GET_SLOT_FROM_KEY() // [slot, value] - sstore // [] + // takes: [value, key] + GET_SLOT_FROM_KEY() + // [value, GET_SLOT_FROM_KEY(key)] + sstore // [] + // returns: [] } /// @notice Store an element from two keys -#define macro STORE_ELEMENT_FROM_KEYS(mem_ptr) = takes(3) returns (0) { - // Input stack: [key1, key2, value] - GET_SLOT_FROM_KEYS() // [slot, value] - sstore // [] +#define macro STORE_ELEMENT_FROM_KEYS(mem_ptr) = takes(3) returns(0) { + // takes: [value, key2, key1] + GET_SLOT_FROM_KEYS() + // [value, GET_SLOT_FROM_KEYS(key1, key2)] + sstore // [] + // returns: [] } /// @notice Store an element from a slot and two keys -#define macro STORE_ELEMENT_FROM_KEYS_2D(mem_ptr) = takes(4) returns (0) { - // Input stack: [slot, key1, key2, value] - GET_SLOT_FROM_KEYS_2D() // [slot, value] - sstore // [] +#define macro STORE_ELEMENT_FROM_KEYS_2D(mem_ptr) = takes(4) returns(0) { + // takes: [value, key2, key1, slot] + GET_SLOT_FROM_KEYS_2D() + // [value, GET_SLOT_FROM_KEYS_2D(slot, key1, key2)] + sstore // [] + // returns: [] } /// @notice Store an element from a slot and three keys -#define macro STORE_ELEMENT_FROM_KEYS_3D(mem_ptr) = takes(5) returns (0) { - // Input stack: [slot, key1, key2, key3, value] - GET_SLOT_FROM_KEYS_3D() // [slot, value] - sstore // [] +#define macro STORE_ELEMENT_FROM_KEYS_3D(mem_ptr) = takes(5) returns(0) { + // takes: [value, key3, key2, key1, slot] + GET_SLOT_FROM_KEYS_3D() + // [value, GET_SLOT_FROM_KEYS_3D(slot, key1, key2, key3)] + sstore // [] + // returns: [] } \ No newline at end of file From af937058d2c643bc4aab0837aa9b203bba26f91a Mon Sep 17 00:00:00 2001 From: Eugenio Date: Tue, 30 Apr 2024 23:33:29 -0300 Subject: [PATCH 3/5] Add extra test to ensure slot is the expected ` --- test/data-structures/Hashmap.t.sol | 37 +++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/test/data-structures/Hashmap.t.sol b/test/data-structures/Hashmap.t.sol index e0b5337..915a4e6 100644 --- a/test/data-structures/Hashmap.t.sol +++ b/test/data-structures/Hashmap.t.sol @@ -47,9 +47,14 @@ contract HashmapTest is Test { /// @notice Test set a key function testSetKey(bytes32 key, bytes32 value) public { - assertEq(hmap.loadElement(key), bytes32(0)); + bytes32 expectedSlot = keccak256(abi.encode(key)); + assertEq(hmap.loadElement(key), bytes32(0), "Expected key to be empty"); + assertEq(vm.load(address(hmap), expectedSlot), bytes32(0), "Expected slot to be empty"); + hmap.storeElement(key, value); - assertEq(hmap.loadElement(key), value); + + assertEq(hmap.loadElement(key), value, "Expected key to be filled with value"); + assertEq(vm.load(address(hmap), expectedSlot), value, "Expected slot to be filled with value"); } /// @notice Test get with keys @@ -60,9 +65,14 @@ contract HashmapTest is Test { /// @notice Test set with keys function testSetKeys(bytes32 key_one, bytes32 key_two, bytes32 value) public { - assertEq(hmap.loadElementFromKeys(key_one, key_two), bytes32(0)); + bytes32 expectedSlot = keccak256(abi.encode(key_two, key_one)); + assertEq(hmap.loadElementFromKeys(key_one, key_two), bytes32(0), "Expected key to be empty"); + assertEq(vm.load(address(hmap), expectedSlot), bytes32(0), "Expected slot to be empty"); + hmap.storeElementFromKeys(key_one, key_two, value); - assertEq(hmap.loadElementFromKeys(key_one, key_two), value); + + assertEq(hmap.loadElementFromKeys(key_one, key_two), value, "Expected slot to be filled with value"); + assertEq(vm.load(address(hmap), expectedSlot), value, "Expected slot to be filled with value"); } /// @notice Test set with slot and 2 keys @@ -72,9 +82,16 @@ contract HashmapTest is Test { bytes32 key_two, bytes32 value ) public { - assertEq(hmap.loadElementFromKeys2D(slot, key_one, key_two), bytes32(0)); + bytes32 expectedSlot = keccak256(abi.encode(key_one, slot )); + expectedSlot = keccak256(abi.encode(key_two, expectedSlot)); + + assertEq(hmap.loadElementFromKeys2D(slot, key_one, key_two), bytes32(0), "Expected key to be empty"); + assertEq(vm.load(address(hmap), expectedSlot), bytes32(0), "Expected slot to be empty"); + hmap.storeElementFromKeys2D(slot, key_one, key_two, value); + assertEq(hmap.loadElementFromKeys2D(slot, key_one, key_two), value); + assertEq(vm.load(address(hmap), expectedSlot), value, "Expected slot to be filled with value"); } /// @notice Test set with slot and 3 keys @@ -85,8 +102,16 @@ contract HashmapTest is Test { bytes32 key_three, bytes32 value ) public { - assertEq(hmap.loadElementFromKeys3D(slot, key_one, key_two, key_three), bytes32(0)); + bytes32 expectedSlot = keccak256(abi.encode(key_one, slot )); + expectedSlot = keccak256(abi.encode(key_two, expectedSlot)); + expectedSlot = keccak256(abi.encode(key_three, expectedSlot)); + + assertEq(hmap.loadElementFromKeys3D(slot, key_one, key_two, key_three), bytes32(0), "Expected key to be empty"); + assertEq(vm.load(address(hmap), expectedSlot), bytes32(0), "Expected slot to be empty"); + hmap.storeElementFromKeys3D(slot, key_one, key_two, key_three, value); + assertEq(hmap.loadElementFromKeys3D(slot, key_one, key_two, key_three), value); + assertEq(vm.load(address(hmap), expectedSlot), value, "Expected slot to be filled with value"); } } From 5c7b2968b94370caadac701387f3cfb178504972 Mon Sep 17 00:00:00 2001 From: Eugenio Date: Wed, 1 May 2024 00:12:29 -0300 Subject: [PATCH 4/5] Fix missing hash operations ``` testGetKey(bytes32) (gas: 0 (0.000%)) testGetKeys(bytes32,bytes32) (gas: 0 (0.000%)) testSetKey(bytes32,bytes32) (gas: 0 (0.000%)) testSetKeys(bytes32,bytes32,bytes32) (gas: 0 (0.000%)) testSetKeys2D(bytes32,bytes32,bytes32,bytes32) (gas: 0 (0.000%)) testSetKeys3D(bytes32,bytes32,bytes32,bytes32,bytes32) (gas: -9 (-0.026%)) Overall gas change: -9 (-0.006%) `` --- src/data-structures/Hashmap.balls | 26 ++++++------ src/data-structures/Hashmap.huff | 66 +++++++++++++++---------------- 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/data-structures/Hashmap.balls b/src/data-structures/Hashmap.balls index 2c53003..5346695 100644 --- a/src/data-structures/Hashmap.balls +++ b/src/data-structures/Hashmap.balls @@ -22,7 +22,6 @@ fn GET_SLOT_FROM_KEYS(slot, key) -> (hashed) { mstore(add(mem_ptr, 0x20), slot) mstore(mem_ptr, key) - // Hash the data, generating a slot. hashed = sha3(mem_ptr, 0x40) } @@ -30,31 +29,30 @@ fn GET_SLOT_FROM_KEYS(slot, key) -> (hashed) { /// @notice Calculate the slot from two keys fn GET_SLOT_FROM_KEYS_2D(slot, key1, key2) -> (hashed) { - // Load the data into memory. - mstore(add(mem_ptr, 0x20), slot) mstore(mem_ptr, key1) - sha3(mem_ptr, 0x40) - - mstore(add(mem_ptr, 0x20), key2) + + _ptr_plus_32 = add(mem_ptr, 0x20) + mstore(_ptr_plus_32, slot) + mstore(_ptr_plus_32, sha3(mem_ptr, 0x40)) + mstore(mem_ptr, key2) // Hash the data, generating a slot. hashed = sha3(mem_ptr, 0x40) } /// @notice Calculate the slot from three keys fn GET_SLOT_FROM_KEYS_3D(slot, key1, key2, key3) -> (hashed) { - // Load the data into memory - mstore(add(mem_ptr, 0x20), slot) - // concat the first two keys mstore(mem_ptr, key1) - sha3(mem_ptr, 0x40) - // put key2 in memory, before slot1 - mstore(add(mem_ptr, 0x20), key2) - sha3(mem_ptr, 0x40) + _ptr_plus_32 = add(mem_ptr, 0x20) + mstore(_ptr_plus_32, slot) + mstore(_ptr_plus_32, sha3(mem_ptr, 0x40)) + + mstore(mem_ptr, key2) + mstore(_ptr_plus_32, sha3(mem_ptr, 0x40)) // put key3 in memory, before slot2 - mstore(add(mem_ptr, 0x20), key3) + mstore(mem_ptr, key3) // Hash the data, generating the final slot3 hashed = sha3(mem_ptr, 0x40) } diff --git a/src/data-structures/Hashmap.huff b/src/data-structures/Hashmap.huff index 9fe44be..1ac4fbe 100644 --- a/src/data-structures/Hashmap.huff +++ b/src/data-structures/Hashmap.huff @@ -8,8 +8,6 @@ /// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. /// @notice Port to BALLs by eugenioclrc taken from https://github.com/huff-language/huffmate/blob/4e2c9bd3412ab8cc65f6ceadafc01a1ff1815796/src/data-structures/Hashmap.huff -/// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. - /// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. #define macro GET_SLOT_FROM_KEY(mem_ptr) = takes(1) returns(1) { // takes: [key] @@ -41,17 +39,18 @@ // takes: [key2, key1, slot] 0x20 // [key2, key1, slot, 0x20] // [key2, key1, slot, 0x20, mem_ptr] - add // [key2, key1, slot, add(mem_ptr, 0x20)] - mstore // [key2, key1] - // [key2, key1, mem_ptr] + add // [key2, key1, slot, _ptr_plus_32] + swap2 // [key2, _ptr_plus_32, slot, key1] + // [key2, _ptr_plus_32, slot, key1, mem_ptr] + mstore // [key2, _ptr_plus_32, slot] + dup2 // [key2, _ptr_plus_32, slot, _ptr_plus_32] + mstore // [key2, _ptr_plus_32] + 0x40 // [key2, _ptr_plus_32, 0x40] + // [key2, _ptr_plus_32, 0x40, mem_ptr] + sha3 // [key2, _ptr_plus_32, sha3(mem_ptr, 0x40)] + swap1 // [key2, sha3(mem_ptr, 0x40), _ptr_plus_32] mstore // [key2] - 0x20 // [key2, 0x20] - // [key2, 0x20, mem_ptr] - 0x40 // [key2, 0x20, mem_ptr, 0x40] - // [key2, 0x20, mem_ptr, 0x40, mem_ptr] - sha3 // [key2, 0x20, mem_ptr, sha3(mem_ptr, 0x40)] - pop // [key2, 0x20, mem_ptr] - add // [key2, add(mem_ptr, 0x20)] + // [key2, mem_ptr] mstore // [] 0x40 // [0x40] // [0x40, mem_ptr] @@ -62,27 +61,28 @@ /// @notice Calculate the slot from three keys #define macro GET_SLOT_FROM_KEYS_3D(mem_ptr) = takes(4) returns(1) { // takes: [key3, key2, key1, slot] - 0x20 // [key3, key2, key1, slot, 0x20] - // [key3, key2, key1, slot, 0x20, mem_ptr] - add // [key3, key2, key1, slot, add(mem_ptr, 0x20)] - mstore // [key3, key2, key1] - // [key3, key2, key1, mem_ptr] - mstore // [key3, key2] - 0x20 // [key3, key2, 0x20] - 0x40 // [key3, key2, 0x20, 0x40] - // [key3, key2, 0x20, 0x40, mem_ptr] - sha3 // [key3, key2, 0x20, sha3(mem_ptr, 0x40)] - pop // [key3, key2, 0x20] - // [key3, key2, 0x20, mem_ptr] - add // [key3, key2, add(mem_ptr, 0x20)] - mstore // [key3] - 0x20 // [key3, 0x20] - // [key3, 0x20, mem_ptr] - add // [key3, add(mem_ptr, 0x20)] - 0x40 // [key3, add(mem_ptr, 0x20), 0x40] - // [key3, add(mem_ptr, 0x20), 0x40, mem_ptr] - sha3 // [key3, add(mem_ptr, 0x20), sha3(mem_ptr, 0x40)] - pop // [key3, add(mem_ptr, 0x20)] + // [key3, key2, key1, slot, mem_ptr] + 0x20 // [key3, key2, key1, slot, mem_ptr, 0x20] + add // [key3, key2, key1, slot, _ptr_plus_32] + swap2 // [key3, key2, _ptr_plus_32, slot, key1] + // [key3, key2, _ptr_plus_32, slot, key1, mem_ptr] + mstore // [key3, key2, _ptr_plus_32, slot] + dup2 // [key3, key2, _ptr_plus_32, slot, _ptr_plus_32] + mstore // [key3, key2, _ptr_plus_32] + // [key3, key2, _ptr_plus_32, mem_ptr] + swap2 // [key3, mem_ptr, _ptr_plus_32, key2] + // [key3, mem_ptr, _ptr_plus_32, key2, mem_ptr] + 0x40 // [key3, mem_ptr, _ptr_plus_32, key2, mem_ptr, 0x40] + // [key3, mem_ptr, _ptr_plus_32, key2, mem_ptr, 0x40, mem_ptr] + sha3 // [key3, mem_ptr, _ptr_plus_32, key2, mem_ptr, sha3(mem_ptr, 0x40)] + dup4 // [key3, mem_ptr, _ptr_plus_32, key2, mem_ptr, sha3(mem_ptr, 0x40), _ptr_plus_32] + mstore // [key3, mem_ptr, _ptr_plus_32, key2, mem_ptr] + mstore // [key3, mem_ptr, _ptr_plus_32] + 0x40 // [key3, mem_ptr, _ptr_plus_32, 0x40] + // [key3, mem_ptr, _ptr_plus_32, 0x40, mem_ptr] + sha3 // [key3, mem_ptr, _ptr_plus_32, sha3(mem_ptr, 0x40)] + swap1 // [key3, mem_ptr, sha3(mem_ptr, 0x40), _ptr_plus_32] + mstore // [key3, mem_ptr] mstore // [] 0x40 // [0x40] // [0x40, mem_ptr] From 8f6cd1a0c5e90248e20316a98f02493ced9291fb Mon Sep 17 00:00:00 2001 From: Eugenio Date: Fri, 17 May 2024 12:46:19 -0300 Subject: [PATCH 5/5] Update SafeMath.huff remove `0x01 LABEL jumpi` for `LABEL jump` --- src/math/SafeMath.huff | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/math/SafeMath.huff b/src/math/SafeMath.huff index e735e84..0c0ad8c 100644 --- a/src/math/SafeMath.huff +++ b/src/math/SafeMath.huff @@ -46,7 +46,7 @@ dup1 // [num1, num1, num2] is_not_zero jumpi // [num1, num2] mul // [result] - 0x01 is_not_overflow jumpi + is_not_overflow jump is_not_zero: // [num1, num2] dup2 // [num2, num1, num2] dup2 // [num1, num2, num1, num2] @@ -82,4 +82,4 @@ [ARITHMETIC_OVERFLOW] PANIC() is_not_mod_zero: mod // [result] -} \ No newline at end of file +}