Skip to content

Commit 995e1b9

Browse files
authored
Merge pull request #7 from init4tech/anna/multiplex
feat: submit data via blobs OR calldata
2 parents 26dc704 + 6c7f37d commit 995e1b9

File tree

2 files changed

+55
-105
lines changed

2 files changed

+55
-105
lines changed

src/Zenith.sol

Lines changed: 35 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ contract Zenith is HostPassage, AccessControlDefaultAdminRules {
4444
/// @notice Emitted when a new rollup block is successfully submitted.
4545
/// @param sequencer - the address of the sequencer that signed the block.
4646
/// @param header - the block header information for the block.
47-
/// @param blobIndices - the indices of the 4844 blob hashes for the block data.
48-
event BlockSubmitted(address indexed sequencer, BlockHeader indexed header, uint32[] blobIndices);
47+
/// @param blockDataHash - keccak256(blockData). the Node will discard the block if the hash doens't match.
48+
event BlockSubmitted(address indexed sequencer, BlockHeader indexed header, bytes32 blockDataHash);
49+
50+
/// @notice Emit the entire block data for easy visibility
51+
event BlockData(bytes blockData);
4952

5053
/// @notice Initializes the Admin role.
5154
/// @dev See `AccessControlDefaultAdminRules` for information on contract administration.
@@ -54,94 +57,58 @@ contract Zenith is HostPassage, AccessControlDefaultAdminRules {
5457
/// @param admin - the address that will be the initial admin.
5558
constructor(address admin) AccessControlDefaultAdminRules(1 days, admin) {}
5659

57-
/// @notice Submit a rollup block with block data stored in 4844 blobs.
60+
/// @notice Submit a rollup block with block data submitted via calldata.
5861
/// @dev Blocks are submitted by Builders, with an attestation to the block data signed by a Sequencer.
5962
/// @param header - the header information for the rollup block.
60-
/// @param blobIndices - the indices of the 4844 blob hashes for the block data.
61-
/// @param v - the v component of the Sequencer's ECSDA signature over the block commitment.
62-
/// @param r - the r component of the Sequencer's ECSDA signature over the block commitment.
63-
/// @param s - the s component of the Sequencer's ECSDA signature over the block commitment.
63+
/// @param blockDataHash - keccak256(blockData). the Node will discard the block if the hash doens't match.
64+
/// @dev including blockDataHash allows the sequencer to sign over finalized block data, without needing to calldatacopy the `blockData` param.
65+
/// @param v - the v component of the Sequencer's ECSDA signature over the block header.
66+
/// @param r - the r component of the Sequencer's ECSDA signature over the block header.
67+
/// @param s - the s component of the Sequencer's ECSDA signature over the block header.
68+
/// @param blockData - block data information. could be packed blob hashes, or direct rlp-encoded transctions. blockData is ignored by the contract logic.
6469
/// @custom:reverts BadSequence if the sequence number is not the next block for the given rollup chainId.
6570
/// @custom:reverts BlockExpired if the confirmBy time has passed.
66-
/// @custom:reverts BadSignature if the signer is not a permissioned sequencer,
67-
/// OR if the signature provided commits to different block data.
71+
/// @custom:reverts BadSignature if the signer is not a permissioned sequencer,
72+
/// OR if the signature provided commits to a different header.
73+
/// @custom:reverts OneRollupBlockPerHostBlock if attempting to submit a second rollup block within one host block.
6874
/// @custom:emits BlockSubmitted if the block is successfully submitted.
69-
function submitBlock(BlockHeader memory header, uint32[] memory blobIndices, uint8 v, bytes32 r, bytes32 s)
70-
external
71-
{
75+
/// @custom:emits BlockData to expose the block calldata; as a convenience until calldata tracing is implemented in the Node.
76+
function submitBlock(
77+
BlockHeader memory header,
78+
bytes32 blockDataHash,
79+
uint8 v,
80+
bytes32 r,
81+
bytes32 s,
82+
bytes calldata blockData
83+
) external {
84+
_submitBlock(header, blockDataHash, v, r, s);
85+
emit BlockData(blockData);
86+
}
87+
88+
function _submitBlock(BlockHeader memory header, bytes32 blockDataHash, uint8 v, bytes32 r, bytes32 s) internal {
7289
// assert that the sequence number is valid and increment it
7390
uint256 _nextSequence = nextSequence[header.rollupChainId]++;
7491
if (_nextSequence != header.sequence) revert BadSequence(_nextSequence);
7592

7693
// assert that confirmBy time has not passed
7794
if (block.timestamp > header.confirmBy) revert BlockExpired();
7895

79-
// derive block commitment from sequence number and blobhashes
80-
bytes32 blockCommit = blockCommitment(header, blobIndices);
81-
82-
// derive sequencer from signature
96+
// derive sequencer from signature over block header
97+
bytes32 blockCommit = blockCommitment(header, blockDataHash);
8398
address sequencer = ecrecover(blockCommit, v, r, s);
8499

85100
// assert that signature is valid && sequencer is permissioned
86101
if (!hasRole(SEQUENCER_ROLE, sequencer)) revert BadSignature(sequencer);
87102

88-
// emit event
89-
emit BlockSubmitted(sequencer, header, blobIndices);
90-
}
91-
92-
/// @notice Construct hash of the block data that the sequencer signs.
93-
/// @dev See `getCommit` for hashed data encoding.
94-
/// @dev Used to easily generate a correct commit hash off-chain for the sequencer to sign.
95-
/// @param header - the header information for the rollup block.
96-
/// @param blobHashes - the 4844 blob hashes for the block data.
97-
/// @param commit - the hash of the encoded block details.
98-
function blockCommitment(BlockHeader memory header, bytes32[] memory blobHashes)
99-
external
100-
view
101-
returns (bytes32 commit)
102-
{
103-
commit = getCommit(header, packHashes(blobHashes));
104-
}
105-
106-
/// @notice Encode the array of blob hashes into a bytes string.
107-
/// @param blobHashes - the 4844 blob hashes for the block data.
108-
/// @return encodedHashes - the encoded blob hashes.
109-
function packHashes(bytes32[] memory blobHashes) public pure returns (bytes memory encodedHashes) {
110-
for (uint32 i = 0; i < blobHashes.length; i++) {
111-
encodedHashes = abi.encodePacked(encodedHashes, blobHashes[i]);
112-
}
113-
}
114-
115-
/// @notice Construct hash of block details that the sequencer signs.
116-
/// @dev See `getCommit` for hash data encoding.
117-
/// @dev Used within the transaction in which the block data is submitted as a 4844 blob.
118-
/// Relies on blob indices, which are used to read blob hashes from the transaction.
119-
/// @param header - the header information for the rollup block.
120-
/// @param blobIndices - the indices of the 4844 blob hashes for the block data.
121-
/// @param commit - the hash of the encoded block details.
122-
function blockCommitment(BlockHeader memory header, uint32[] memory blobIndices)
123-
internal
124-
view
125-
returns (bytes32 commit)
126-
{
127-
commit = getCommit(header, getHashes(blobIndices));
128-
}
129103

130-
/// @notice Encode an array of blob hashes, given their indices in the transaction.
131-
/// @param blobIndices - the indices of the 4844 blob hashes for the block data.
132-
/// @return encodedHashes - the encoded blob hashes.
133-
function getHashes(uint32[] memory blobIndices) internal view returns (bytes memory encodedHashes) {
134-
for (uint32 i = 0; i < blobIndices.length; i++) {
135-
encodedHashes = abi.encodePacked(encodedHashes, blobhash(blobIndices[i]));
136-
}
104+
// emit event
105+
emit BlockSubmitted(sequencer, header, blockDataHash);
137106
}
138107

139108
/// @notice Construct hash of block details that the sequencer signs.
140-
/// @dev Hash is keccak256(abi.encodePacked("init4.sequencer.v0", hostChainId, rollupChainId, blockSequence, rollupGasLimit, confirmBy, rewardAddress, numBlobs, encodedBlobHashes))
141109
/// @param header - the header information for the rollup block.
142-
/// @param encodedHashes - the encoded blob hashes.
143110
/// @return commit - the hash of the encoded block details.
144-
function getCommit(BlockHeader memory header, bytes memory encodedHashes) internal view returns (bytes32 commit) {
111+
function blockCommitment(BlockHeader memory header, bytes32 blockDataHash) public view returns (bytes32 commit) {
145112
bytes memory encoded = abi.encodePacked(
146113
"init4.sequencer.v0",
147114
block.chainid,
@@ -150,8 +117,7 @@ contract Zenith is HostPassage, AccessControlDefaultAdminRules {
150117
header.gasLimit,
151118
header.confirmBy,
152119
header.rewardAddress,
153-
encodedHashes.length / 32,
154-
encodedHashes
120+
blockDataHash
155121
);
156122
commit = keccak256(encoded);
157123
}

test/Zenith.t.sol

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ contract ZenithTest is Test {
88
Zenith public target;
99

1010
Zenith.BlockHeader header;
11-
bytes32[] blobHashes;
12-
uint32[] blobIndices;
1311
bytes32 commit;
12+
/// @dev blockData is ignored by the contract. it's included for the purpose of DA for the node.
13+
bytes blockData = "0x1234567890abcdef";
14+
bytes32 blockDataHash;
1415

1516
uint256 sequencerKey = 123;
1617
uint256 notSequencerKey = 300;
1718

18-
event BlockSubmitted(address indexed sequencer, Zenith.BlockHeader indexed header, uint32[] blobIndices);
19+
event BlockSubmitted(address indexed sequencer, Zenith.BlockHeader indexed header, bytes32 blockDataHash);
1920

2021
function setUp() public {
2122
target = new Zenith(address(this));
@@ -28,90 +29,73 @@ contract ZenithTest is Test {
2829
header.gasLimit = 30_000_000;
2930
header.rewardAddress = address(this);
3031

31-
// set default blob info
32-
blobIndices.push(0);
33-
blobHashes.push(bytes32("JUNK BLOBHASH"));
34-
// TODO: vm.blobhashes(blobHashes);
32+
blockDataHash = keccak256(blockData);
3533

36-
// derive block commitment from sequence number and blobhashes
37-
commit = target.blockCommitment(header, blobHashes);
34+
// derive block commitment from the header
35+
commit = target.blockCommitment(header, blockDataHash);
3836
}
3937

4038
// cannot submit block with incorrect sequence number
4139
function test_badSequence() public {
4240
// change to incorrect sequence number
4341
header.sequence = 1;
42+
commit = target.blockCommitment(header, blockDataHash);
4443

4544
// sign block commitmenet with sequencer key
4645
(uint8 v, bytes32 r, bytes32 s) = vm.sign(sequencerKey, commit);
4746

4847
vm.expectRevert(abi.encodeWithSelector(Zenith.BadSequence.selector, 0));
49-
target.submitBlock(header, blobIndices, v, r, s);
48+
target.submitBlock(header, blockDataHash, v, r, s, blockData);
5049
}
5150

5251
// cannot submit block with expired confirmBy time
5352
function test_blockExpired() public {
5453
// change to expired confirmBy time
5554
header.confirmBy = block.timestamp - 1;
55+
commit = target.blockCommitment(header, blockDataHash);
5656

5757
// sign block commitmenet with sequencer key
5858
(uint8 v, bytes32 r, bytes32 s) = vm.sign(sequencerKey, commit);
5959

6060
vm.expectRevert(abi.encodeWithSelector(Zenith.BlockExpired.selector));
61-
target.submitBlock(header, blobIndices, v, r, s);
61+
target.submitBlock(header, blockDataHash, v, r, s, blockData);
6262
}
6363

64-
// BLOCKED by PR supporting vm.blobhashes: https://github.com/foundry-rs/foundry/pull/7001
65-
// can submit block successfully with acceptable data & correct signature provided
66-
function BLOCKED_test_submitBlock() public {
64+
// can submit block successfully with acceptable header & correct signature provided
65+
function test_submitBlock() public {
6766
// sign block commitmenet with correct sequencer key
6867
(uint8 v, bytes32 r, bytes32 s) = vm.sign(sequencerKey, commit);
6968

7069
// should emit BlockSubmitted event
7170
vm.expectEmit();
72-
emit BlockSubmitted(vm.addr(sequencerKey), header, blobIndices);
73-
target.submitBlock(header, blobIndices, v, r, s);
71+
emit BlockSubmitted(vm.addr(sequencerKey), header, blockDataHash);
72+
target.submitBlock(header, blockDataHash, v, r, s, blockData);
7473

7574
// should increment sequence number
7675
assertEq(target.nextSequence(header.rollupChainId), header.sequence + 1);
7776
}
7877

7978
// cannot submit block with invalid sequencer signer from non-permissioned key
80-
function BLOCKED_test_notSequencer() public {
79+
function test_notSequencer() public {
8180
// sign block commitmenet with NOT sequencer key
8281
(uint8 v, bytes32 r, bytes32 s) = vm.sign(notSequencerKey, commit);
8382

8483
vm.expectRevert(abi.encodeWithSelector(Zenith.BadSignature.selector, vm.addr(notSequencerKey)));
85-
target.submitBlock(header, blobIndices, v, r, s);
84+
target.submitBlock(header, blockDataHash, v, r, s, blockData);
8685
}
8786

8887
// cannot submit block with sequencer signature over different block header data
89-
function BLOCKED_test_badSignature_header() public {
88+
function test_badSignature() public {
9089
// sign original block commitmenet with sequencer key
9190
(uint8 v, bytes32 r, bytes32 s) = vm.sign(sequencerKey, commit);
9291

9392
// change header data from what was signed by sequencer
9493
header.confirmBy = block.timestamp + 15 minutes;
95-
96-
bytes32 newCommit = target.blockCommitment(header, blobHashes);
94+
bytes32 newCommit = target.blockCommitment(header, blockDataHash);
9795
address derivedSigner = ecrecover(newCommit, v, r, s);
9896

9997
vm.expectRevert(abi.encodeWithSelector(Zenith.BadSignature.selector, derivedSigner));
100-
target.submitBlock(header, blobIndices, v, r, s);
98+
target.submitBlock(header, blockDataHash, v, r, s, blockData);
10199
}
102-
103-
// cannot submit block with sequencer signature over different blob hashes
104-
function BLOCKED_test_badSignature_blobs() public {
105-
// sign original block commitmenet with sequencer key
106-
(uint8 v, bytes32 r, bytes32 s) = vm.sign(sequencerKey, commit);
107-
108-
blobHashes[0] = bytes32("DIFFERENT BLOBHASH");
109-
// TODO: vm.blobhashes(blobHashes);
110-
111-
bytes32 newCommit = target.blockCommitment(header, blobHashes);
112-
address derivedSigner = ecrecover(newCommit, v, r, s);
113-
114-
vm.expectRevert(abi.encodeWithSelector(Zenith.BadSignature.selector, derivedSigner));
115-
target.submitBlock(header, blobIndices, v, r, s);
116100
}
117101
}

0 commit comments

Comments
 (0)