Skip to content

Commit

Permalink
using AppendOnlyTreeSnapshot struct
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Jan 17, 2024
1 parent 6470cd9 commit 7b061fd
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 166 deletions.
4 changes: 2 additions & 2 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ contract Rollup is IRollup {
}

// @todo @LHerskind Proper genesis state. If the state is empty, we allow anything for now.
if (archive != bytes32(0) && archive != header.lastArchiveRoot) {
revert Errors.Rollup__InvalidArchive(archive, header.lastArchiveRoot);
if (archive != bytes32(0) && archive != header.lastArchive.root) {
revert Errors.Rollup__InvalidArchive(archive, header.lastArchive.root);
}
}

Expand Down
53 changes: 24 additions & 29 deletions l1-contracts/src/core/libraries/decoders/HeaderDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ import {Hash} from "../Hash.sol";
* | --- | --- | ---
*/
library HeaderDecoder {
struct AppendOnlyTreeSnapshot {
bytes32 root;
uint32 nextAvailableLeafIndex;
}

struct GlobalVariables {
uint256 chainId;
uint256 version;
Expand All @@ -56,28 +61,22 @@ library HeaderDecoder {
}

struct PartialStateReference {
bytes32 noteHashTreeRoot;
uint32 noteHashTreeNextAvailableLeafIndex;
bytes32 nullifierTreeRoot;
uint32 nullifierTreeNextAvailableLeafIndex;
bytes32 contractTreeRoot;
uint32 contractTreeNextAvailableLeafIndex;
bytes32 publicDataTreeRoot;
uint32 publicDataTreeNextAvailableLeafIndex;
AppendOnlyTreeSnapshot noteHashTree;
AppendOnlyTreeSnapshot nullifierTree;
AppendOnlyTreeSnapshot contractTree;
AppendOnlyTreeSnapshot publicDataTree;
}

struct StateReference {
bytes32 l1ToL2MessageTreeRoot;
uint32 l1ToL2MessageTreeNextAvailableLeafIndex;
AppendOnlyTreeSnapshot l1ToL2MessageTree;
// Note: Can't use "partial" name here as in yellow paper because it is a reserved solidity keyword
PartialStateReference partialStateReference;
}

struct Header {
GlobalVariables globalVariables;
StateReference stateReference;
bytes32 lastArchiveRoot;
uint32 lastArchiveNextAvailableLeafIndex;
AppendOnlyTreeSnapshot lastArchive;
bytes32 bodyHash;
}

Expand All @@ -94,23 +93,19 @@ library HeaderDecoder {
header.globalVariables.version = uint256(bytes32(_header[0x20:0x40]));
header.globalVariables.blockNumber = uint256(bytes32(_header[0x40:0x60]));
header.globalVariables.timestamp = uint256(bytes32(_header[0x60:0x80]));
header.stateReference.l1ToL2MessageTreeRoot = bytes32(_header[0x80:0xa0]);
header.stateReference.l1ToL2MessageTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0xa0:0xa4]));
header.stateReference.partialStateReference.noteHashTreeRoot = bytes32(_header[0xa4:0xc4]);
header.stateReference.partialStateReference.noteHashTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0xc4:0xc8]));
header.stateReference.partialStateReference.nullifierTreeRoot = bytes32(_header[0xc8:0xe8]);
header.stateReference.partialStateReference.nullifierTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0xe8:0xec]));
header.stateReference.partialStateReference.contractTreeRoot = bytes32(_header[0xec:0x10c]);
header.stateReference.partialStateReference.contractTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0x10c:0x110]));
header.stateReference.partialStateReference.publicDataTreeRoot = bytes32(_header[0x110:0x130]);
header.stateReference.partialStateReference.publicDataTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0x130:0x134]));
header.lastArchiveRoot = bytes32(_header[0x134:0x154]);
header.lastArchiveNextAvailableLeafIndex = uint32(bytes4(_header[0x154:0x158]));
header.stateReference.l1ToL2MessageTree =
AppendOnlyTreeSnapshot(bytes32(_header[0x80:0xa0]), uint32(bytes4(_header[0xa0:0xa4])));
header.stateReference.partialStateReference.noteHashTree =
AppendOnlyTreeSnapshot(bytes32(_header[0xa4:0xc4]), uint32(bytes4(_header[0xc4:0xc8])));
header.stateReference.partialStateReference.nullifierTree =
AppendOnlyTreeSnapshot(bytes32(_header[0xc8:0xe8]), uint32(bytes4(_header[0xe8:0xec])));
header.stateReference.partialStateReference.contractTree =
AppendOnlyTreeSnapshot(bytes32(_header[0xec:0x10c]), uint32(bytes4(_header[0x10c:0x110])));
header.stateReference.partialStateReference.publicDataTree =
AppendOnlyTreeSnapshot(bytes32(_header[0x110:0x130]), uint32(bytes4(_header[0x130:0x134])));
header.lastArchive =
AppendOnlyTreeSnapshot(bytes32(_header[0x134:0x154]), uint32(bytes4(_header[0x154:0x158])));

header.bodyHash = bytes32(_header[0x158:0x178]);

return header;
Expand Down
23 changes: 11 additions & 12 deletions l1-contracts/test/decoders/Base.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ pragma solidity >=0.8.18;
import {Test} from "forge-std/Test.sol";

contract DecoderBase is Test {
struct AppendOnlyTreeSnapshot {
uint32 nextAvailableLeafIndex;
bytes32 root;
}

// When I had data and messages as one combined struct it failed, but I can have this top-layer and it works :shrug:
// Note: Members of the struct (and substructs) have to be in ALPHABETICAL order!
struct Full {
Expand Down Expand Up @@ -37,8 +42,7 @@ contract DecoderBase is Test {
struct DecodedHeader {
bytes32 bodyHash;
GlobalVariables globalVariables;
uint256 lastArchiveNextAvailableLeafIndex;
bytes32 lastArchiveRoot;
AppendOnlyTreeSnapshot lastArchive;
StateReference stateReference;
}

Expand All @@ -50,20 +54,15 @@ contract DecoderBase is Test {
}

struct StateReference {
uint256 l1ToL2MessageTreeNextAvailableLeafIndex;
bytes32 l1ToL2MessageTreeRoot;
AppendOnlyTreeSnapshot l1ToL2MessageTree;
PartialStateReference partialStateReference;
}

struct PartialStateReference {
uint256 contractTreeNextAvailableLeafIndex;
bytes32 contractTreeRoot;
uint256 noteHashTreeNextAvailableLeafIndex;
bytes32 noteHashTreeRoot;
uint256 nullifierTreeNextAvailableLeafIndex;
bytes32 nullifierTreeRoot;
uint256 publicDataTreeNextAvailableLeafIndex;
bytes32 publicDataTreeRoot;
AppendOnlyTreeSnapshot contractTree;
AppendOnlyTreeSnapshot noteHashTree;
AppendOnlyTreeSnapshot nullifierTree;
AppendOnlyTreeSnapshot publicDataTree;
}

function load(string memory name) public view returns (Full memory) {
Expand Down
67 changes: 36 additions & 31 deletions l1-contracts/test/decoders/Decoder.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ contract DecoderTest is DecoderBase {

// L1 -> L2 messages
assertEq(
header.stateReference.l1ToL2MessageTreeNextAvailableLeafIndex,
stateReference.l1ToL2MessageTreeNextAvailableLeafIndex,
"Invalid l1ToL2MessageTreeNextAvailableLeafIndex"
header.stateReference.l1ToL2MessageTree.nextAvailableLeafIndex,
stateReference.l1ToL2MessageTree.nextAvailableLeafIndex,
"Invalid l1ToL2MessageTree.nextAvailableLeafIndex"
);
assertEq(
header.stateReference.l1ToL2MessageTreeRoot,
stateReference.l1ToL2MessageTreeRoot,
"Invalid l1ToL2MessageTreeRoot"
header.stateReference.l1ToL2MessageTree.root,
stateReference.l1ToL2MessageTree.root,
"Invalid l1ToL2MessageTree.root"
);

// PartialStateReference
Expand All @@ -96,55 +96,60 @@ contract DecoderTest is DecoderBase {

// NoteHashTree
assertEq(
header.stateReference.partialStateReference.noteHashTreeNextAvailableLeafIndex,
partialStateReference.noteHashTreeNextAvailableLeafIndex,
"Invalid noteHashTreeNextAvailableLeafIndex"
header.stateReference.partialStateReference.noteHashTree.nextAvailableLeafIndex,
partialStateReference.noteHashTree.nextAvailableLeafIndex,
"Invalid noteHashTree.nextAvailableLeafIndex"
);
assertEq(
header.stateReference.partialStateReference.noteHashTreeRoot,
partialStateReference.noteHashTreeRoot,
"Invalid noteHashTreeRoot"
header.stateReference.partialStateReference.noteHashTree.root,
partialStateReference.noteHashTree.root,
"Invalid noteHashTree.root"
);

// NullifierTree
assertEq(
header.stateReference.partialStateReference.nullifierTreeNextAvailableLeafIndex,
partialStateReference.nullifierTreeNextAvailableLeafIndex,
"Invalid nullifierTreeNextAvailableLeafIndex"
header.stateReference.partialStateReference.nullifierTree.nextAvailableLeafIndex,
partialStateReference.nullifierTree.nextAvailableLeafIndex,
"Invalid nullifierTree.nextAvailableLeafIndex"
);
assertEq(
header.stateReference.partialStateReference.nullifierTreeRoot,
partialStateReference.nullifierTreeRoot,
"Invalid nullifierTreeRoot"
header.stateReference.partialStateReference.nullifierTree.root,
partialStateReference.nullifierTree.root,
"Invalid nullifierTree.root"
);

// ContractTree
assertEq(
header.stateReference.partialStateReference.contractTreeNextAvailableLeafIndex,
partialStateReference.contractTreeNextAvailableLeafIndex,
"Invalid contractTreeNextAvailableLeafIndex"
header.stateReference.partialStateReference.contractTree.nextAvailableLeafIndex,
partialStateReference.contractTree.nextAvailableLeafIndex,
"Invalid contractTree.nextAvailableLeafIndex"
);
assertEq(
header.stateReference.partialStateReference.contractTreeRoot,
partialStateReference.contractTreeRoot,
"Invalid contractTreeRoot"
header.stateReference.partialStateReference.contractTree.root,
partialStateReference.contractTree.root,
"Invalid contractTree.root"
);

// PublicDataTree
assertEq(
header.stateReference.partialStateReference.publicDataTreeNextAvailableLeafIndex,
partialStateReference.publicDataTreeNextAvailableLeafIndex,
"Invalid publicDataTreeNextAvailableLeafIndex"
header.stateReference.partialStateReference.publicDataTree.nextAvailableLeafIndex,
partialStateReference.publicDataTree.nextAvailableLeafIndex,
"Invalid publicDataTree.nextAvailableLeafIndex"
);
assertEq(
header.stateReference.partialStateReference.publicDataTreeRoot,
partialStateReference.publicDataTreeRoot,
"Invalid publicDataTreeRoot"
header.stateReference.partialStateReference.publicDataTree.root,
partialStateReference.publicDataTree.root,
"Invalid publicDataTree.root"
);
}
}

assertEq(header.lastArchiveRoot, referenceHeader.lastArchiveRoot, "Invalid last archive");
assertEq(
header.lastArchive.nextAvailableLeafIndex,
referenceHeader.lastArchive.nextAvailableLeafIndex,
"Invalid lastArchive.nextAvailableLeafIndex"
);
assertEq(header.lastArchive.root, referenceHeader.lastArchive.root, "Invalid lastArchive.root");
assertEq(header.bodyHash, referenceHeader.bodyHash, "Invalid body hash");
}

Expand Down
36 changes: 24 additions & 12 deletions l1-contracts/test/fixtures/empty_block_0.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,32 @@
"timestamp": 0,
"version": 1
},
"lastArchiveNextAvailableLeafIndex": 1,
"lastArchiveRoot": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02",
"lastArchive": {
"nextAvailableLeafIndex": 1,
"root": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02"
},
"stateReference": {
"l1ToL2MessageTreeNextAvailableLeafIndex": 16,
"l1ToL2MessageTreeRoot": "0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80",
"l1ToL2MessageTree": {
"nextAvailableLeafIndex": 16,
"root": "0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80"
},
"partialStateReference": {
"contractTreeNextAvailableLeafIndex": 4,
"contractTreeRoot": "0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80",
"noteHashTreeNextAvailableLeafIndex": 256,
"noteHashTreeRoot": "0x16642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb",
"nullifierTreeNextAvailableLeafIndex": 384,
"nullifierTreeRoot": "0x0bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278",
"publicDataTreeNextAvailableLeafIndex": 96,
"publicDataTreeRoot": "0x1ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0"
"contractTree": {
"nextAvailableLeafIndex": 4,
"root": "0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80"
},
"noteHashTree": {
"nextAvailableLeafIndex": 256,
"root": "0x16642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb"
},
"nullifierTree": {
"nextAvailableLeafIndex": 384,
"root": "0x0bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278"
},
"publicDataTree": {
"nextAvailableLeafIndex": 96,
"root": "0x1ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0"
}
}
}
},
Expand Down
44 changes: 28 additions & 16 deletions l1-contracts/test/fixtures/empty_block_1.json

Large diffs are not rendered by default.

46 changes: 29 additions & 17 deletions l1-contracts/test/fixtures/mixed_block_0.json

Large diffs are not rendered by default.

50 changes: 31 additions & 19 deletions l1-contracts/test/fixtures/mixed_block_1.json

Large diffs are not rendered by default.

56 changes: 28 additions & 28 deletions yarn-project/end-to-end/src/integration_l1_publisher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe('L1Publisher integration', () => {
const chainId = createEthereumChain(config.rpcUrl, config.apiKey).chainInfo.id;

// To overwrite the test data, set this to true and run the tests.
const OVERWRITE_TEST_DATA = true;
const OVERWRITE_TEST_DATA = false;

beforeEach(async () => {
deployerAccount = privateKeyToAccount(deployerPK);
Expand Down Expand Up @@ -286,35 +286,35 @@ describe('L1Publisher integration', () => {
timestamp: Number(block.header.globalVariables.timestamp.toBigInt()),
version: Number(block.header.globalVariables.version.toBigInt()),
},
lastArchiveNextAvailableLeafIndex: block.header.lastArchive.nextAvailableLeafIndex,
lastArchiveRoot: `0x${block.header.lastArchive.root.toBuffer().toString('hex').padStart(64, '0')}`,
lastArchive: {
nextAvailableLeafIndex: block.header.lastArchive.nextAvailableLeafIndex,
root: `0x${block.header.lastArchive.root.toBuffer().toString('hex').padStart(64, '0')}`,
},
stateReference: {
l1ToL2MessageTreeNextAvailableLeafIndex: block.header.state.l1ToL2MessageTree.nextAvailableLeafIndex,
l1ToL2MessageTreeRoot: `0x${block.header.state.l1ToL2MessageTree.root
.toBuffer()
.toString('hex')
.padStart(64, '0')}`,
l1ToL2MessageTree: {
nextAvailableLeafIndex: block.header.state.l1ToL2MessageTree.nextAvailableLeafIndex,
root: `0x${block.header.state.l1ToL2MessageTree.root.toBuffer().toString('hex').padStart(64, '0')}`,
},
partialStateReference: {
contractTreeNextAvailableLeafIndex: block.header.state.partial.contractTree.nextAvailableLeafIndex,
contractTreeRoot: `0x${block.header.state.partial.contractTree.root
.toBuffer()
.toString('hex')
.padStart(64, '0')}`,
noteHashTreeNextAvailableLeafIndex: block.header.state.partial.noteHashTree.nextAvailableLeafIndex,
noteHashTreeRoot: `0x${block.header.state.partial.noteHashTree.root
.toBuffer()
.toString('hex')
.padStart(64, '0')}`,
nullifierTreeNextAvailableLeafIndex: block.header.state.partial.nullifierTree.nextAvailableLeafIndex,
nullifierTreeRoot: `0x${block.header.state.partial.nullifierTree.root
.toBuffer()
.toString('hex')
.padStart(64, '0')}`,
publicDataTreeNextAvailableLeafIndex: block.header.state.partial.publicDataTree.nextAvailableLeafIndex,
publicDataTreeRoot: `0x${block.header.state.partial.publicDataTree.root
.toBuffer()
.toString('hex')
.padStart(64, '0')}`,
contractTree: {
nextAvailableLeafIndex: block.header.state.partial.contractTree.nextAvailableLeafIndex,
root: `0x${block.header.state.partial.contractTree.root.toBuffer().toString('hex').padStart(64, '0')}`,
},
noteHashTree: {
nextAvailableLeafIndex: block.header.state.partial.noteHashTree.nextAvailableLeafIndex,
root: `0x${block.header.state.partial.noteHashTree.root.toBuffer().toString('hex').padStart(64, '0')}`,
},
nullifierTree: {
nextAvailableLeafIndex: block.header.state.partial.nullifierTree.nextAvailableLeafIndex,
root: `0x${block.header.state.partial.nullifierTree.root.toBuffer().toString('hex').padStart(64, '0')}`,
},
publicDataTree: {
nextAvailableLeafIndex: block.header.state.partial.publicDataTree.nextAvailableLeafIndex,
root: `0x${block.header.state.partial.publicDataTree.root
.toBuffer()
.toString('hex')
.padStart(64, '0')}`,
},
},
},
},
Expand Down

0 comments on commit 7b061fd

Please sign in to comment.