diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index c53f2e5e0be..c327bf711d6 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -2,6 +2,10 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; +import {IRegistry} from "@aztec/core/interfaces/messagebridge/IRegistry.sol"; +import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol"; +import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol"; + import {MockVerifier} from "@aztec/mock/MockVerifier.sol"; import {Decoder} from "./Decoder.sol"; @@ -20,10 +24,12 @@ contract Rollup is Decoder { event L2BlockProcessed(uint256 indexed blockNum); MockVerifier public immutable VERIFIER; + IRegistry public immutable REGISTRY; bytes32 public rollupStateHash; - constructor() { + constructor(IRegistry _registry) { VERIFIER = new MockVerifier(); + REGISTRY = _registry; } /** @@ -41,7 +47,7 @@ contract Rollup is Decoder { bytes32[] memory l1ToL2Msgs ) = _decode(_l2Block); - // @todo Proper genesis state. If the state is empty, we allow anything for now. + // @todo @LHerskind Proper genesis state. If the state is empty, we allow anything for now. if (rollupStateHash != bytes32(0) && rollupStateHash != oldStateHash) { revert InvalidStateHash(rollupStateHash, oldStateHash); } @@ -55,6 +61,13 @@ contract Rollup is Decoder { rollupStateHash = newStateHash; + // @todo (issue #605) handle fee collector + IInbox inbox = REGISTRY.getInbox(); + inbox.batchConsume(l1ToL2Msgs, msg.sender); + + IOutbox outbox = REGISTRY.getOutbox(); + outbox.sendL1Messages(l2ToL1Msgs); + emit L2BlockProcessed(l2BlockNumber); } } diff --git a/l1-contracts/src/core/messagebridge/Inbox.sol b/l1-contracts/src/core/messagebridge/Inbox.sol index f1a3c5090bf..463448cd6b6 100644 --- a/l1-contracts/src/core/messagebridge/Inbox.sol +++ b/l1-contracts/src/core/messagebridge/Inbox.sol @@ -124,13 +124,16 @@ contract Inbox is MessageBox, IInbox { function batchConsume(bytes32[] memory _entryKeys, address _feeCollector) external onlyRollup { uint256 totalFee = 0; for (uint256 i = 0; i < _entryKeys.length; i++) { + if (_entryKeys[i] == bytes32(0)) continue; DataStructures.Entry memory entry = get(_entryKeys[i]); // cant consume if we are already past deadline. if (block.timestamp > entry.deadline) revert Inbox__PastDeadline(); _consume(_entryKeys[i]); totalFee += entry.fee; } - feesAccrued[_feeCollector] += totalFee; + if (totalFee > 0) { + feesAccrued[_feeCollector] += totalFee; + } } /** diff --git a/l1-contracts/src/core/messagebridge/Outbox.sol b/l1-contracts/src/core/messagebridge/Outbox.sol index af68a98d588..01ab4b51c7d 100644 --- a/l1-contracts/src/core/messagebridge/Outbox.sol +++ b/l1-contracts/src/core/messagebridge/Outbox.sol @@ -37,6 +37,7 @@ contract Outbox is MessageBox, IOutbox { */ function sendL1Messages(bytes32[] memory _entryKeys) external onlyRollup { for (uint256 i = 0; i < _entryKeys.length; i++) { + if (_entryKeys[i] == bytes32(0)) continue; _insert(_entryKeys[i], 0, 0); emit MessageAdded(_entryKeys[i]); } diff --git a/l1-contracts/test/Decoder.t.sol b/l1-contracts/test/Decoder.t.sol index 22e24a9e922..44b870fe1d8 100644 --- a/l1-contracts/test/Decoder.t.sol +++ b/l1-contracts/test/Decoder.t.sol @@ -5,7 +5,6 @@ pragma solidity >=0.8.18; import {Test} from "forge-std/Test.sol"; import {Decoder} from "@aztec/core/Decoder.sol"; -import {Rollup} from "@aztec/core/Rollup.sol"; import {DecoderHelper} from "./DecoderHelper.sol"; /** @@ -13,21 +12,19 @@ import {DecoderHelper} from "./DecoderHelper.sol"; * Main use of these test is shorter cycles when updating the decoder contract. */ contract DecoderTest is Test { - Rollup internal rollup; DecoderHelper internal helper; - bytes block_empty_1 = + bytes internal block_empty_1 = hex"000000010668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e15000000002d39729fd006096882acfbd350c91fd61883578b4fe35b63cdce3c1993a497ea000000082f8dc86ba80d8fcf491fb7a255f4163e4f9601d022ba0be35f13297531073fd80000000019c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb671000000012b36b22912aa963f143c490227bd21e7a44338026b2f6a389cb98e82167c3718000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb0668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e150000000019c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb671000000010668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e15000000102d39729fd006096882acfbd350c91fd61883578b4fe35b63cdce3c1993a497ea000000182f8dc86ba80d8fcf491fb7a255f4163e4f9601d022ba0be35f13297531073fd800000004238b20b7bc1d5190f8e928eb2aa2094412588f9cad6c7862f69c09a9b246d6ed0000000225d4ca531bca7d097a93bc47d7aa2c4dbcc8d0d5ecf4138849104e363eb52c03000000022b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb0668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e1500000010238b20b7bc1d5190f8e928eb2aa2094412588f9cad6c7862f69c09a9b246d6ed000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - bytes block_mixed_1 = + bytes internal block_mixed_1 = hex"000000010668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e15000000002d39729fd006096882acfbd350c91fd61883578b4fe35b63cdce3c1993a497ea000000082f8dc86ba80d8fcf491fb7a255f4163e4f9601d022ba0be35f13297531073fd80000000019c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb671000000012b36b22912aa963f143c490227bd21e7a44338026b2f6a389cb98e82167c3718000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb0668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e150000000019c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb671000000010813349a787d3f13ec3492de8b6a5c06ba871cb7d2533b8859f3c4069338450100000010069dae963409c321ded6da153196448d64875d356f0ed54bfcf4ba554d6519ba00000018279f38b90665ef7dae8a59f015029274d7837545f62f1f00ab64ffb714d043e90000000412e58befb4676abe3a279ec129e4d48b53eb1b1724a6c01274b39f6122dfc0bf00000002128683784c66165b4b7acf1502ee0f2ed6e5e614f9992375e5f98b1566f2d20a000000022d9b8d2353587ca56bdf967b4bb8847af3671bd6901e9e28f82c240c6e33129a2be9dc687a1bbe5b10ecac6869ca85a46d9c9afe064f55d2e8e237ba01f4faa3000000101a3cc59d6b87c8046f558f7c16e2880c120ad353f83c20c604fdb34458b15a5100000002000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000012100000000000000000000000000000000000000000000000000000000000001220000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001410000000000000000000000000000000000000000000000000000000000000142000000000000000000000000000000000000000000000000000000000000014300000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000161000000000000000000000000000000000000000000000000000000000000016200000000000000000000000000000000000000000000000000000000000001630000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000100000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002410000000000000000000000000000000000000000000000000000000000000242000000000000000000000000000000000000000000000000000000000000024300000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000261000000000000000000000000000000000000000000000000000000000000026200000000000000000000000000000000000000000000000000000000000002630000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000100000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000052a0000000000000000000000000000000000000000000000000000000000000521000000000000000000000000000000000000000000000000000000000000052b0000000000000000000000000000000000000000000000000000000000000522000000000000000000000000000000000000000000000000000000000000052c0000000000000000000000000000000000000000000000000000000000000523000000000000000000000000000000000000000000000000000000000000052d0000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d00000008000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003210000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000361000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000426fcb9639d15aabe6d792e23ab12fb9633046d4be6911a60d64471d7560d3f6809143b7d4943a3485115d37e7596938a16c91b6055f3837640d8c36b8303bb3c06fb5fb553496e5e0b48834087e036acf99d6d935dc2ebf43c82788cb5ed1c6a2f4bd77ac2bb5474d48c2856135d18168cd6f69f77143c60b3cc370319419dac0000000000000000000000000000000000000000000000000000000000001020212121212121212121212121212121212121212100000000000000000000000000000000000000000000000000000000000010404141414141414141414141414141414141414141000000000000000000000000000000000000000000000000000000000000106061616161616161616161616161616161616161610000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000010000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410"; - function setUp() public { - rollup = new Rollup(); + function setUp() public virtual { helper = new DecoderHelper(); } - function testEmptyBlock() public { + function testEmptyBlock() public virtual { (bytes32 diffRoot, bytes32 l1ToL2MessagesHash) = helper.computeDiffRootAndMessagesHash(block_empty_1); assertEq( @@ -68,19 +65,15 @@ contract DecoderTest is Test { "Invalid public input hash" ); - rollup.process(bytes(""), block_empty_1); - for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { assertEq(l2ToL1Msgs[i], bytes32(0), "Invalid l2ToL1Msgs"); } for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { assertEq(l1ToL2Msgs[i], bytes32(0), "Invalid l1ToL2Msgs"); } - - assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); } - function testMixBlock() public { + function testMixBlock() public virtual { (bytes32 diffRoot, bytes32 l1ToL2MessagesHash) = helper.computeDiffRootAndMessagesHash(block_mixed_1); assertEq( @@ -129,9 +122,5 @@ contract DecoderTest is Test { for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { assertEq(l1ToL2Msgs[i], bytes32(uint256(0x401 + i)), "Invalid l1ToL2Msgs"); } - - rollup.process(bytes(""), block_mixed_1); - - assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); } } diff --git a/l1-contracts/test/Inbox.t.sol b/l1-contracts/test/Inbox.t.sol index 1905b2b31ad..19fa846f6ff 100644 --- a/l1-contracts/test/Inbox.t.sol +++ b/l1-contracts/test/Inbox.t.sol @@ -181,15 +181,17 @@ contract InboxTest is Test { inbox.batchConsume(entryKeys, address(0x1)); } - function testFuzzRevertIfConsumingAMessageThatDoesntExist(bytes32[] memory _entryKeys) public { - if (_entryKeys.length == 0) { - _entryKeys = new bytes32[](1); - _entryKeys[0] = bytes32("random"); + function testFuzzRevertIfConsumingAMessageThatDoesntExist(bytes32 _entryKey) public { + bytes32[] memory entryKeys = new bytes32[](1); + if (_entryKey == bytes32(0)) { + entryKeys[0] = bytes32("random"); + } else { + entryKeys[0] = _entryKey; } vm.expectRevert( - abi.encodeWithSelector(MessageBox.MessageBox__NothingToConsume.selector, _entryKeys[0]) + abi.encodeWithSelector(MessageBox.MessageBox__NothingToConsume.selector, entryKeys[0]) ); - inbox.batchConsume(_entryKeys, address(0x1)); + inbox.batchConsume(entryKeys, address(0x1)); } function testRevertIfConsumingTheSameMessageMoreThanTheCountOfEntries() public { diff --git a/l1-contracts/test/Outbox.t.sol b/l1-contracts/test/Outbox.t.sol index 4b9c82599dc..61e66d78cce 100644 --- a/l1-contracts/test/Outbox.t.sol +++ b/l1-contracts/test/Outbox.t.sol @@ -47,12 +47,14 @@ contract OutboxTest is Test { function testFuzzBatchInsert(bytes32[] memory _entryKeys) public { // expected events for (uint256 i = 0; i < _entryKeys.length; i++) { + if (_entryKeys[i] == bytes32(0)) continue; vm.expectEmit(true, false, false, false); emit MessageAdded(_entryKeys[i]); } outbox.sendL1Messages(_entryKeys); for (uint256 i = 0; i < _entryKeys.length; i++) { + if (_entryKeys[i] == bytes32(0)) continue; bytes32 key = _entryKeys[i]; DataStructures.Entry memory entry = outbox.get(key); assertGt(entry.count, 0); diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol new file mode 100644 index 00000000000..5961818ae75 --- /dev/null +++ b/l1-contracts/test/Rollup.t.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; + +import {DecoderTest} from "./Decoder.t.sol"; + +import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; + +import {Registry} from "@aztec/core/messagebridge/Registry.sol"; +import {Inbox} from "@aztec/core/messagebridge/Inbox.sol"; +import {Outbox} from "@aztec/core/messagebridge/Outbox.sol"; + +import {Decoder} from "@aztec/core/Decoder.sol"; +import {Rollup} from "@aztec/core/Rollup.sol"; + +/** + * Blocks are generated using the `integration_l1_publisher.test.ts` tests. + * Main use of these test is shorter cycles when updating the decoder contract. + */ +contract RollupTest is DecoderTest { + Registry internal registry; + Inbox internal inbox; + Outbox internal outbox; + Rollup internal rollup; + + function setUp() public override(DecoderTest) { + super.setUp(); + registry = new Registry(); + inbox = new Inbox(address(registry)); + outbox = new Outbox(address(registry)); + rollup = new Rollup(registry); + + registry.setAddresses(address(rollup), address(inbox), address(outbox)); + } + + function testEmptyBlock() public override(DecoderTest) { + (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = + helper.decode(block_empty_1); + + vm.record(); + rollup.process(bytes(""), block_empty_1); + + (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); + (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); + + assertEq(inboxWrites.length, 0, "Invalid inbox writes"); + assertEq(outboxWrites.length, 0, "Invalid outbox writes"); + + for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { + assertEq(l2ToL1Msgs[i], bytes32(0), "Invalid l2ToL1Msgs"); + assertFalse(outbox.contains(l2ToL1Msgs[i]), "msg in outbox"); + } + for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + assertEq(l1ToL2Msgs[i], bytes32(0), "Invalid l1ToL2Msgs"); + assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg in inbox"); + } + + assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); + } + + function testMixBlock() public override(DecoderTest) { + (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = + helper.decode(block_mixed_1); + + for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + _insertInboxEntry(l1ToL2Msgs[i]); + assertTrue(inbox.contains(l1ToL2Msgs[i]), "msg not in inbox"); + } + + vm.record(); + rollup.process(bytes(""), block_mixed_1); + + (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); + (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); + + assertEq(inboxWrites.length, 16, "Invalid inbox writes"); + assertEq(outboxWrites.length, 8, "Invalid outbox writes"); + + for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { + // recreate the value generated by `integration_l1_publisher.test.ts`. + bytes32 expectedValue = bytes32(uint256(0x300 + 32 * (1 + i / 2) + i % 2)); + assertEq(l2ToL1Msgs[i], expectedValue, "Invalid l2ToL1Msgs"); + assertTrue(outbox.contains(l2ToL1Msgs[i]), "msg not in outbox"); + } + + for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + assertEq(l1ToL2Msgs[i], bytes32(uint256(0x401 + i)), "Invalid l1ToL2Msgs"); + assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg not consumed"); + } + + assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); + } + + function _insertInboxEntry(bytes32 _entryHash) internal { + // Compute where exactly we need to shove the entry + bytes32 slot = keccak256(abi.encodePacked(_entryHash, uint256(0))); + uint256 value = uint256(1) | uint256(type(uint32).max) << 128; + vm.store(address(inbox), slot, bytes32(value)); + } +} diff --git a/yarn-project/end-to-end/src/deploy_l1_contracts.ts b/yarn-project/end-to-end/src/deploy_l1_contracts.ts index e207bd196b9..618659ad15f 100644 --- a/yarn-project/end-to-end/src/deploy_l1_contracts.ts +++ b/yarn-project/end-to-end/src/deploy_l1_contracts.ts @@ -3,6 +3,12 @@ import { DebugLogger } from '@aztec/foundation/log'; import { DecoderHelperAbi, DecoderHelperBytecode, + InboxAbi, + InboxBytecode, + OutboxAbi, + OutboxBytecode, + RegistryAbi, + RegistryBytecode, RollupAbi, RollupBytecode, UnverifiedDataEmitterAbi, @@ -18,6 +24,8 @@ import { WalletClient, createPublicClient, createWalletClient, + getAddress, + getContract, http, } from 'viem'; import { HDAccount, PrivateKeyAccount } from 'viem/accounts'; @@ -49,9 +57,36 @@ export const deployL1Contracts = async ( transport: http(rpcUrl), }); - const rollupAddress = await deployL1Contract(walletClient, publicClient, RollupAbi, RollupBytecode); + const registryAddress = await deployL1Contract(walletClient, publicClient, RegistryAbi, RegistryBytecode); + logger(`Deployed Registry at ${registryAddress}`); + + const inboxAddress = await deployL1Contract(walletClient, publicClient, InboxAbi, InboxBytecode, [ + getAddress(registryAddress.toString()), + ]); + logger(`Deployed Inbox at ${inboxAddress}`); + + const outboxAddress = await deployL1Contract(walletClient, publicClient, OutboxAbi, OutboxBytecode, [ + getAddress(registryAddress.toString()), + ]); + logger(`Deployed Outbox at ${outboxAddress}`); + + const rollupAddress = await deployL1Contract(walletClient, publicClient, RollupAbi, RollupBytecode, [ + getAddress(registryAddress.toString()), + ]); logger(`Deployed Rollup at ${rollupAddress}`); + // We need to call a function on the registry to set the various contract addresses. + const registryContract = getContract({ + address: getAddress(registryAddress.toString()), + abi: RegistryAbi, + publicClient, + walletClient, + }); + await registryContract.write.setAddresses( + [getAddress(rollupAddress.toString()), getAddress(inboxAddress.toString()), getAddress(outboxAddress.toString())], + { account }, + ); + const unverifiedDataEmitterAddress = await deployL1Contract( walletClient, publicClient, @@ -68,6 +103,9 @@ export const deployL1Contracts = async ( return { rollupAddress, + registryAddress, + inboxAddress, + outboxAddress, unverifiedDataEmitterAddress, decoderHelperAddress, }; @@ -86,10 +124,12 @@ async function deployL1Contract( publicClient: PublicClient, abi: Narrow, bytecode: Hex, + args: readonly unknown[] | undefined = undefined, ): Promise { const hash = await walletClient.deployContract({ abi, bytecode, + args: args, }); const receipt = await publicClient.waitForTransactionReceipt({ hash }); diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 8ba40e88758..453d08e13fb 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -13,7 +13,7 @@ import { } from '@aztec/circuits.js'; import { fr, makeNewContractData, makeProof } from '@aztec/circuits.js/factories'; import { createDebugLogger } from '@aztec/foundation/log'; -import { DecoderHelperAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { DecoderHelperAbi, InboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { EmptyRollupProver, L1Publisher, @@ -41,6 +41,7 @@ import { getAddress, getContract, http, + keccak256, } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { foundry } from 'viem/chains'; @@ -60,10 +61,14 @@ describe('L1Publisher integration', () => { let publicClient: PublicClient; let rollupAddress: Address; + let inboxAddress: Address; + let outboxAddress: Address; let unverifiedDataEmitterAddress: Address; let decoderHelperAddress: Address; let rollup: GetContractReturnType>; + let inbox: GetContractReturnType>; + let outbox: GetContractReturnType>; let decoderHelper: GetContractReturnType>; let publisher: L1Publisher; @@ -76,11 +81,15 @@ describe('L1Publisher integration', () => { const deployerAccount = privateKeyToAccount(deployerPK); const { rollupAddress: rollupAddress_, + inboxAddress: inboxAddress_, + outboxAddress: outboxAddress_, unverifiedDataEmitterAddress: unverifiedDataEmitterAddress_, decoderHelperAddress: decoderHelperAddress_, } = await deployL1Contracts(config.rpcUrl, deployerAccount, logger, true); rollupAddress = getAddress(rollupAddress_.toString()); + inboxAddress = getAddress(inboxAddress_.toString()); + outboxAddress = getAddress(outboxAddress_.toString()); unverifiedDataEmitterAddress = getAddress(unverifiedDataEmitterAddress_.toString()); decoderHelperAddress = getAddress(decoderHelperAddress_!.toString()); @@ -95,6 +104,16 @@ describe('L1Publisher integration', () => { abi: RollupAbi, publicClient, }); + inbox = getContract({ + address: inboxAddress, + abi: InboxAbi, + publicClient, + }); + outbox = getContract({ + address: outboxAddress, + abi: OutboxAbi, + publicClient, + }); decoderHelper = getContract({ address: decoderHelperAddress!, abi: DecoderHelperAbi, @@ -144,6 +163,20 @@ describe('L1Publisher integration', () => { return tx; }; + const forceInsertionInInbox = async (l1ToL2Messages: Fr[]) => { + for (let i = 0; i < l1ToL2Messages.length; i++) { + const slot = keccak256(Buffer.concat([l1ToL2Messages[i].toBuffer(), fr(0).toBuffer()])); + const value = 1n | ((2n ** 32n - 1n) << 128n); + // we are using Fr for the value as an easy way to get a correctly sized buffer and string. + const params = `["${inboxAddress}", "${slot}", "0x${new Fr(value).toBuffer().toString('hex')}"]`; + await fetch(config.rpcUrl, { + body: `{"jsonrpc":"2.0", "method": "anvil_setStorageAt", "params": ${params}, "id": 1}`, + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }); + } + }; + it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => { const stateInRollup_ = await rollup.read.rollupStateHash(); expect(hexStringToBuffer(stateInRollup_.toString())).toEqual(Buffer.alloc(32, 0)); @@ -152,6 +185,8 @@ describe('L1Publisher integration', () => { for (let i = 0; i < numberOfConsecutiveBlocks; i++) { const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 128 * i + 1 + 0x400).map(fr); + await forceInsertionInInbox(l1ToL2Messages); + const txs = [ await makeBloatedProcessedTx(128 * i + 32), await makeBloatedProcessedTx(128 * i + 64), @@ -160,6 +195,17 @@ describe('L1Publisher integration', () => { ]; const [block] = await builder.buildL2Block(1 + i, txs, l1ToL2Messages); + // check that values are in the inbox + for (let j = 0; j < l1ToL2Messages.length; j++) { + if (l1ToL2Messages[j].isZero()) continue; + expect(await inbox.read.contains([`0x${l1ToL2Messages[j].toBuffer().toString('hex')}`])).toBeTruthy(); + } + + // check that values are not in the outbox + for (let j = 0; j < block.newL2ToL1Msgs.length; j++) { + expect(await outbox.read.contains([`0x${block.newL2ToL1Msgs[j].toBuffer().toString('hex')}`])).toBeFalsy(); + } + /*// Useful for sol tests block generation const encoded = block.encode(); console.log(`Size (${encoded.length}): ${encoded.toString('hex')}`); @@ -205,6 +251,16 @@ describe('L1Publisher integration', () => { expect(block.getPublicInputsHash().toBuffer()).toEqual(hexStringToBuffer(decodedRes[3].toString())); expect(block.getCalldataHash()).toEqual(hexStringToBuffer(decodedHashes[0].toString())); expect(block.getL1ToL2MessagesHash()).toEqual(hexStringToBuffer(decodedHashes[1].toString())); + + // check that values have been consumed from the inbox + for (let j = 0; j < l1ToL2Messages.length; j++) { + if (l1ToL2Messages[j].isZero()) continue; + expect(await inbox.read.contains([`0x${l1ToL2Messages[j].toBuffer().toString('hex')}`])).toBeFalsy(); + } + // check that values are inserted into the outbox + for (let j = 0; j < block.newL2ToL1Msgs.length; j++) { + expect(await outbox.read.contains([`0x${block.newL2ToL1Msgs[j].toBuffer().toString('hex')}`])).toBeTruthy(); + } } }, 60_000); diff --git a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh index d4b0bcba04b..a71fcd3a64c 100755 --- a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh +++ b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh @@ -11,6 +11,9 @@ target_dir=./generated CONTRACTS=( "l1-contracts:DecoderHelper" + "l1-contracts:Registry" + "l1-contracts:Inbox" + "l1-contracts:Outbox" "l1-contracts:Rollup" "l1-contracts:UnverifiedDataEmitter" )