Skip to content

Commit

Permalink
Read Abi initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Agusx1211 committed Jan 17, 2024
1 parent cefebf5 commit 61b4280
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 32 deletions.
66 changes: 42 additions & 24 deletions foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import "forge-std/console2.sol";
import { HuffConfig } from "foundry-huff/HuffConfig.sol";
import { HuffDeployer } from "foundry-huff/HuffDeployer.sol";

uint256 constant FMS = 0xa0;

contract L2CompressorHuffTests is AdvTest {
address public imp;

Expand All @@ -29,7 +31,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 1);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(uint256(0)), res);
}
Expand All @@ -42,7 +44,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 2);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(uint256(_val)), res);
}
Expand All @@ -55,7 +57,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 3);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(uint256(_val)), res);
}
Expand All @@ -70,7 +72,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 1 + _size);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

_content = abi.encodePacked(_content, bytes32(0));
uint256 expected;
Expand All @@ -92,7 +94,7 @@ contract L2CompressorHuffTests is AdvTest {
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, 1 + 20);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_addr), res);

Expand All @@ -104,7 +106,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 3);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_addr), res);

Expand All @@ -117,7 +119,7 @@ contract L2CompressorHuffTests is AdvTest {
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, 1 + 20);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_addr2), res);

Expand All @@ -129,7 +131,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 4);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_addr2), res);

Expand All @@ -140,7 +142,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 5);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_addr2), res);

Expand All @@ -151,7 +153,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 6);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_addr2), res);
}
Expand All @@ -165,7 +167,7 @@ contract L2CompressorHuffTests is AdvTest {
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, 1 + 32);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_b1), res);

Expand All @@ -177,7 +179,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 3);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_b1), res);

Expand All @@ -190,7 +192,7 @@ contract L2CompressorHuffTests is AdvTest {
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, 1 + 32);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_b2), res);

Expand All @@ -202,7 +204,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 4);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_b2), res);

Expand All @@ -213,7 +215,7 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 5);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_b2), res);

Expand All @@ -224,20 +226,36 @@ contract L2CompressorHuffTests is AdvTest {
assertTrue(s);
(rindex, windex, res) = abi.decode(r, (uint256, uint256, bytes));
assertEq(rindex, 6);
assertEq(windex, 0x80 + 32);
assertEq(windex, FMS + 32);

assertEq(abi.encode(_b2), res);
}

// function test_read_flag_bytes_n(bytes calldata _data, bytes calldata _extra) external {
// (bool s, bytes memory r) = imp.staticcall(
// abi.encodePacked(hex"2b", _data, _extra)
// );
function test_read_flag_bytes_n(bytes calldata _data, bytes calldata _extra) external {
(bool s, bytes memory r) = imp.staticcall(
abi.encodePacked(hex"2b", hex"04", uint32(_data.length), _data, _extra)
);

assertTrue(s);
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));

assertEq(rindex, _data.length + 1 + 1 + 4);
assertEq(windex, FMS + _data.length);
assertEq(res, _data);
}

function test_read_flag_abi_encode_1() external {
bytes4 selector = 0x9988aabb;
uint256 val = type(uint64).max;

// assertTrue(s);
// (uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));
(bool s, bytes memory r) = imp.staticcall(
abi.encodePacked(hex"2e", selector, hex"08", uint64(val))
);

// assertEq(rindex, _data.length + 1);
assertTrue(s);
console.logBytes(r);

// }
(uint256 rindex, uint256 windex, bytes memory res) = abi.decode(r, (uint256, uint256, bytes));
console.logBytes(res);
}
}
140 changes: 132 additions & 8 deletions src/L2Compressor.huff
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,16 @@
JUMP_READ_BYTES32_5 // 0x2a
JUMP_READ_N_BYTES // 0x2b
JUMP_READ_POWER_OF_2 // 0x2c
FLAG_ABI_0_PARAM // 0x2d
FLAG_ABI_1_PARAM // 0x2e
FLAG_ABI_2_PARAMS // 0x2f
FLAG_ABI_3_PARAMS // 0x20
FLAG_ABI_4_PARAMS // 0x31
FLAG_ABI_5_PARAMS // 0x32
FLAG_ABI_6_PARAMS // 0x33
}

#define constant HIGHEST_FLAG = 0x2c
#define constant HIGHEST_FLAG = 0x32

#define macro READ_FLAG() = takes (2) returns (2) {
nested_read_flag_start:
Expand Down Expand Up @@ -292,6 +299,28 @@
READ_POWER_OF_2() // [windex, rindex]
end jump

FLAG_ABI_0_PARAM:
READ_ABI(nested_read_flag_start, 0x00) // [windex, rindex]
end jump
FLAG_ABI_1_PARAM:
READ_ABI(nested_read_flag_start, 0x01) // [windex, rindex]
end jump
FLAG_ABI_2_PARAMS:
READ_ABI(nested_read_flag_start, 0x02) // [windex, rindex]
end jump
FLAG_ABI_3_PARAMS:
READ_ABI(nested_read_flag_start, 0x03) // [windex, rindex]
end jump
FLAG_ABI_4_PARAMS:
READ_ABI(nested_read_flag_start, 0x04) // [windex, rindex]
end jump
FLAG_ABI_5_PARAMS:
READ_ABI(nested_read_flag_start, 0x05) // [windex, rindex]
end jump
FLAG_ABI_6_PARAMS:
READ_ABI(nested_read_flag_start, 0x06) // [windex, rindex]
end jump

default:
// The default just pushes the flag as a byte (padded to 32 bytes)
// notice that we start at 0x01 since 0x00 can be pushed with the flag 0x00
Expand All @@ -304,23 +333,32 @@
end:

// If the NESTED memory slot is not 0, then we need to jump there
// it means that this READ_FLAG() is nested
// but each "return" only takes 2 bytes, so we need to only jump to
// to the last 2 bytes. Notice that this limits nested calls to a depth
// of 16 only.

[NESTED_READ_FLAG_RETURN_MSLOT] mload // [nrfr, windex, rindex]
0xffff and // [nrfr & 0xffff, windex, rindex]
dup1 jumpi // [windex, rindex]
}

#define macro PERFORM_NESTED_READ_FLAG(nrfs) = takes(0) returns (0) {
back // [back]
[NESTED_READ_FLAG_RETURN_MSLOT] // [nrfr, back]
mstore // []
// input stack: []

<nrfs> jump // []
[NESTED_READ_FLAG_RETURN_MSLOT] mload // [nrfr]
0x10 shl // [nrfr << 0x10]
back or // [nrfr << 0x10 | back]
[NESTED_READ_FLAG_RETURN_MSLOT] // [nrfr, new_nrfr]
mstore // []

<nrfs> jump // []

back:

// Clear the back pointer!
0x00 [NESTED_READ_FLAG_RETURN_MSLOT] mstore
// Clear the last callback pointer
[NESTED_READ_FLAG_RETURN_MSLOT] mload // [nrfr]
0x10 shr // [nrfr >> 0x10]
[NESTED_READ_FLAG_RETURN_MSLOT] mstore // []
}

#define macro BACKREAD_SINGLE_VALUE() = takes (1) returns (2) {
Expand Down Expand Up @@ -404,6 +442,92 @@
0x03 eq ASSERT() // []
}

#define macro READ_ABI(nrfs, nparams) = takes (3) returns (2) {
// input stack: [flag, windex, rindex]

pop // [windex, rindex]

// Reserve 32 bytes to store the size, dynamic values
// use the first 32 bytes to store the size of the value
0x20 // [0x20, windex, rindex]
add // [0x20 + windex, rindex]

0x04 // [0x04, windex, rindex]
dup1 // [0x04, 0x04, windex, rindex]
dup4 // [rindex, 0x04, 0x04, windex, rindex]
dup4 // [windex, rindex, 0x04, 0x04, windex, rindex]
calldatacopy // [0x04, windex, rindex]

dup2 // [windex, 0x04, windex, rindex]

swap3 // [rindex, 0x04, windex, windex]
add // [rindex + 0x04, windex, windex]

swap1 // [windex, rindex + 0x04, windex]
0x04 add // [windex + 0x04, rindex + 0x04, windex]
swap1 // [rindex + 0x04, windex + 0x04, windex]

0x00 // [i, rindex, windex, prev_windex]
read_param: // [i, rindex, windex, prev_windex]
swap2 // [windex, rindex, i, prev_windex]

PERFORM_NESTED_READ_FLAG(<nrfs>) // [windex, rindex, i, prev_windex]
BACKREAD_SINGLE_VALUE() // [val, windex, rindex, i, prev_windex]

dup2 // [windex, val, windex, rindex, i, prev_windex]
mstore // [windex, rindex, i, prev_windex]

0x20 add // [windex + 0x20, rindex, i, prev_windex]

swap2 // [i, rindex, windex + 0x20, prev_windex]

0x01 add // [i + 1, rindex, windex, prev_windex]

dup1 // [i + 1, i + 1, rindex, windex, prev_windex]
<nparams> lt // [i + 1 < nparams, i + 1, rindex, windex, prev_windex]
read_param // [read_param, i + 1 < nparams, i + 1, rindex, windex, prev_windex]
jumpi // [i + 1, rindex, windex, prev_windex]

pop // [rindex, windex, prev_windex]

// We need to fill the last 32 bytes with 0x00, dynamic values
// must be padded to 32 bytes

dup3 // [prev_windex, rindex, windex, prev_windex]
dup3 // [windex, prev_windex, rindex, windex, prev_windex]

sub // [size, rindex, windex, prev_index]
dup1 // [size, size, rindex, windex, prev_index]

0x1f and // [size % 32, size, rindex, windex, prev_index]
0x20 sub // [32 - size % 32, size, rindex, windex, prev_index]

// Zero out the memory, just in case

0x00 // [0x00, 32 - size % 32, size, rindex, windex, prev_index]
dup5 // [windex, 0x00, 32 - size % 32, size, rindex, windex, prev_index]
mstore // [32 - size % 32, size, rindex, windex, prev_index]

// Advance the windex by the number of required bytes
swap1 // [size, 32 - size % 32, rindex, windex, prev_index]
swap3 // [windex, 32 - size % 32, rindex, size, prev_index]
add // [windex, rindex, size, prev_index]

// Now we need to store the full size of the value
// luckly windex - prev_index should give us the padded index

swap2 // [size, rindex, windex, prev_index]
0x20 // [0x20, size, rindex, windex, prev_index]
dup5 // [prev_index, size, rindex, windex, prev_index]
sub // [(0x20 - prev_index), size, rindex, windex, prev_index]
mstore // [rindex, windex, prev_index]

swap2 // [prev_index, windex, rindex]
pop // [windex, rindex]

// output stack: [windex, rindex]
}

#define macro READ_BYTES32(shift_bits, read_bytes) = takes (3) returns (2) {
// input stack: [flag, windex, rindex]

Expand Down

0 comments on commit 61b4280

Please sign in to comment.