Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gwyneth): adap multi-block proposals to gwyneth #21

Merged
merged 1 commit into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions packages/protocol/contracts/L1/BasedOperator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,41 @@ contract BasedOperator is EssentialContract, TaikoErrors {

/// @dev Proposes a Taiko L2 block.
function proposeBlock(
bytes calldata params,
bytes calldata txList,
bytes[] calldata data,
bytes[] calldata txLists,
address prover
)
external
payable
nonReentrant
whenNotPaused
returns (TaikoData.BlockMetadata memory _block)
returns (TaikoData.BlockMetadata[] memory _blocks)
{
if(txLists.length != 0) {
require(data.length == txLists.length, "mismatched params length");
}

require(msg.value == PROVER_BOND, "Prover bond not expected");

_block = TaikoL1(resolve("taiko", false)).proposeBlock(params, txList);
_blocks = new TaikoData.BlockMetadata[](data.length);
for (uint i = 0; i < data.length; i++) {
if(txLists.length != 0) {
// If calldata, then pass forward the calldata
_blocks[i] = TaikoL1(resolve("taiko", false)).proposeBlock(data[i], txLists[i]);
}
else {
// Blob otherwise
_blocks[i] = TaikoL1(resolve("taiko", false)).proposeBlock(data[i], "");
}

// Check if we have whitelisted proposers
if (!_isProposerPermitted(_block)) {
revert L1_INVALID_PROPOSER();
}
// Check if we have whitelisted proposers
if (!_isProposerPermitted(_blocks[i])) {
revert L1_INVALID_PROPOSER();
}

// Store who paid for proving the block
blocks[_block.l2BlockNumber] = Block({ assignedProver: prover, bond: uint96(PROVER_BOND) });
// Store who paid for proving the block
blocks[_blocks[i].l2BlockNumber] = Block({ assignedProver: prover, bond: uint96(PROVER_BOND) });
}

// Verify some blocks
_verifyBlocks(MAX_BLOCKS_TO_VERIFY);
Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ library TaikoData {
uint64 timestamp;
uint24 txListByteOffset;
uint24 txListByteSize;
// todo: Do we need this below ?
// bytes32 blobId OR blobHash; ? as per in current taiko-mono's preconfirmation branch ?
bool blobUsed;
}

Expand Down
11 changes: 7 additions & 4 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
}

/// Proposes a Taiko L2 block.
/// @param data Block parameters, currently an encoded BlockParams object.
/// @param data Block parameters, currently an encoded BlockMetadata object.
/// @param txList txList data if calldata is used for DA.
/// @return _block The metadata of the proposed L2 block.
function proposeBlock(
Expand All @@ -64,8 +64,8 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
payable
nonReentrant
whenNotPaused
onlyFromNamed("operator")
returns (
//onlyFromNamed("operator")
TaikoData.BlockMetadata memory _block
)
{
Expand All @@ -85,7 +85,9 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
require(_block.blobUsed == (txList.length == 0), "INVALID_BLOB_USED");
// Verify DA data
if (_block.blobUsed) {
//require(_block.blobHash == blobhash(0), "invalid data blob");
// Todo: Is blobHash posisble to be checked and pre-calculated in input metadata off-chain ?
// or shall we do something with it to cross check ?
// require(_block.blobHash == blobhash(0), "invalid data blob");
require(
uint256(_block.txListByteOffset) + _block.txListByteSize <= MAX_BYTES_PER_BLOB,
"invalid blob size"
Expand All @@ -104,7 +106,8 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {

TaikoData.Block storage parentBlock = state.blocks[(state.numBlocks - 1)];

require(_block.parentMetaHash == parentBlock.metaHash, "invalid parentHash");
require(_block.parentMetaHash == parentBlock.metaHash, "invalid parentMetaHash");
require(_block.parentBlockHash == parentBlock.blockHash, "invalid parentHash");

// Verify the passed in L1 state block number.
// We only allow the L1 block to be 4 epochs old.
Expand Down
11 changes: 3 additions & 8 deletions packages/protocol/contracts/L1/actors/PBSActor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,16 @@ contract PBSActor {

/// @dev Proposes a Taiko L2 block.
function proposeBlock(
bytes calldata params,
bytes calldata txList,
bytes[] calldata data,
bytes[] calldata txLists,
bytes memory proverPaymentData,
bytes32 parentHash,
uint256 tip
)
external
payable
{
// TODO(Brecht): just pass in opaque data to make it general, though kind of doesn't matter
TaikoData.BlockMetadata memory _block =
operator.proposeBlock{ value: msg.value - tip }(params, txList, proverPaymentData);

// Check if parent block has the right meta hash
require(keccak256(abi.encode(_block)) == parentHash, "unexpected parent");
operator.proposeBlock{ value: msg.value - tip }(data, txLists, proverPaymentData);

// Do conditional payment
address(block.coinbase).sendEtherAndVerify(tip);
Expand Down
17 changes: 10 additions & 7 deletions packages/protocol/contracts/L1/actors/ProverPayment.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ contract ProverPayment {

/// @dev Proposes a Taiko L2 block.
function proposeBlock(
bytes calldata params,
bytes calldata txList,
bytes[] calldata data,
bytes[] calldata txLists,
bytes calldata proverAssignment
)
external
payable
returns (TaikoData.BlockMetadata memory _block)
returns (TaikoData.BlockMetadata[] memory _blocks)
{
// Decode the assignment data
ProverAssignment memory assignment = abi.decode(proverAssignment, (ProverAssignment));
Expand All @@ -51,19 +51,22 @@ contract ProverPayment {
balances[assignment.prover] -= operator.PROVER_BOND();

// Propose the block
_block = operator.proposeBlock{ value: operator.PROVER_BOND() }(
params, txList, assignment.prover
_blocks = operator.proposeBlock{ value: operator.PROVER_BOND() }(
data, txLists, assignment.prover
);

uint64 highestl2BlockNumber = _blocks[_blocks.length-1].l2BlockNumber;

// Hash the assignment with the blobHash, this hash will be signed by
// the prover, therefore, we add a string as a prefix.
// IMPORTANT!! Assignment now multi-block assignment!!
bytes32 hash = hashAssignment(assignment);
require(assignment.prover.isValidSignature(hash, assignment.signature), "invalid signature");

// Check assignment validity
require(
(assignment.metaHash != 0 || keccak256(abi.encode(_block)) != assignment.metaHash)
&& (assignment.maxBlockId != 0 || _block.l2BlockNumber > assignment.maxBlockId)
(assignment.metaHash != 0 || keccak256(abi.encode(_blocks)) != assignment.metaHash)
&& (assignment.maxBlockId != 0 || highestl2BlockNumber > assignment.maxBlockId)
&& (assignment.maxProposedIn != 0 || block.number > assignment.maxProposedIn),
"unexpected block"
);
Expand Down
24 changes: 17 additions & 7 deletions packages/protocol/test/L1/TaikoL1TestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -303,24 +303,34 @@

// hookcalls[0] = TaikoData.HookCall(address(assignmentHook), abi.encode(assignment));

bytes memory dummyTxList =
bytes[] memory dummyTxList = new bytes[](1);
dummyTxList[0] =
hex"0000000000000000000000000000000000000000000000000000000000000001";
bytes memory emptyTxList;

// If blob is used, empty tx list
bytes[] memory emptyTxList;

// Input metadata sturct can now support multiple block proposals per L1 TXN

Check failure on line 313 in packages/protocol/test/L1/TaikoL1TestBase.sol

View workflow job for this annotation

GitHub Actions / codespell

sturct ==> struct
bytes[] memory metasEncoded = new bytes[](1);
metasEncoded[0] = abi.encode(meta);

TaikoData.BlockMetadata[] memory _returnedBlocks = new TaikoData.BlockMetadata[](1);

if (revertReason == "") {
vm.prank(proposer, proposer);
meta = basedOperator.proposeBlock{ value: 1 ether / 10 }(
abi.encode(meta), meta.blobUsed == true ? emptyTxList : dummyTxList, prover
_returnedBlocks = basedOperator.proposeBlock{ value: 1 ether / 10 }(
metasEncoded, meta.blobUsed == true ? emptyTxList : dummyTxList, prover
);
} else {
vm.prank(proposer, proposer);
vm.expectRevert(revertReason);
meta = basedOperator.proposeBlock{ value: 1 ether / 10 }(
abi.encode(meta), meta.blobUsed == true ? emptyTxList : dummyTxList, prover
_returnedBlocks = basedOperator.proposeBlock{ value: 1 ether / 10 }(
metasEncoded, meta.blobUsed == true ? emptyTxList : dummyTxList, prover
);
return meta;
}

return meta;
return _returnedBlocks[0];
}

function proveBlock(address prover, bytes memory blockProof) internal {
Expand Down Expand Up @@ -511,12 +521,12 @@
bytes memory signature =
createSgxSignatureProof(transition, newInstance, prover, keccak256(abi.encode(meta)));

// The order is on purpose reversed, becase of the L1_INVALID_OR_DUPLICATE_VERIFIER() check

Check failure on line 524 in packages/protocol/test/L1/TaikoL1TestBase.sol

View workflow job for this annotation

GitHub Actions / codespell

becase ==> because
proofs[0].verifier = sv2;
proofs[0].proof = bytes.concat(bytes4(0), bytes20(newInstance), signature);

if (threeMockSGXProofs) {
// The order is on purpose reversed, becase of the L1_INVALID_OR_DUPLICATE_VERIFIER()

Check failure on line 529 in packages/protocol/test/L1/TaikoL1TestBase.sol

View workflow job for this annotation

GitHub Actions / codespell

becase ==> because
// check
proofs[1].verifier = sv1;
proofs[1].proof = bytes.concat(bytes4(0), bytes20(newInstance), signature);
Expand Down
Loading