Skip to content

Commit

Permalink
add preconf from taiko-mono helder branch
Browse files Browse the repository at this point in the history
  • Loading branch information
Keszey Dániel authored and Keszey Dániel committed Jul 3, 2024
1 parent af3743d commit 346959e
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 24 deletions.
12 changes: 6 additions & 6 deletions packages/protocol/contracts/L1/BasedOperator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ contract BasedOperator is EssentialContract {
require(_isProposerPermitted(_block), "proposer not allowed");

// Store who paid for proving the block
blocks[_block.id] = Block({
blocks[_block.l2BlockNumber] = Block({
assignedProver: prover,
bond: uint96(PROVER_BOND)
});
Expand All @@ -94,9 +94,9 @@ contract BasedOperator is EssentialContract {
ProofBatch memory proofBatch = abi.decode(data, (ProofBatch));

// Check who can prove the block
TaikoData.Block memory taikoBlock = taiko.getBlock(proofBatch._block.id);
if (block.timestamp < taikoBlock.proposedAt + PROVING_WINDOW) {
require(proofBatch.prover == blocks[proofBatch._block.id].assignedProver, "assigned prover not the prover");
TaikoData.Block memory taikoBlock = taiko.getBlock(proofBatch._block.l2BlockNumber);
if (block.timestamp < taikoBlock.timestamp + PROVING_WINDOW) {
require(proofBatch.prover == blocks[proofBatch._block.l2BlockNumber].assignedProver, "assigned prover not the prover");
}

// Verify the proofs
Expand All @@ -118,7 +118,7 @@ contract BasedOperator is EssentialContract {

// Only allow an already proven block to be overwritten when the verifiers used are now invalid
// Get the currently stored transition
TaikoData.TransitionState memory storedTransition = taiko.getTransition(proofBatch._block.id, proofBatch.transition.parentHash);
TaikoData.TransitionState memory storedTransition = taiko.getTransition(proofBatch._block.l2BlockNumber, proofBatch.transition.parentHash);
if (storedTransition.blockHash != proofBatch.transition.blockHash) {
// TODO(Brecht): Check that one of the verifiers is now poissoned
} else {
Expand Down Expand Up @@ -170,7 +170,7 @@ contract BasedOperator is EssentialContract {
view
returns (bool)
{
if (_block.id == 1) {
if (_block.l2BlockNumber == 1) {
// Only proposer_one can propose the first block after genesis
address proposerOne = resolve("proposer_one", true);
if (proposerOne != address(0) && msg.sender != proposerOne) {
Expand Down
10 changes: 5 additions & 5 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ library TaikoData {
bytes32 blockHash;
bytes32 parentMetaHash;
bytes32 l1Hash;
uint difficulty;
uint256 difficulty;
bytes32 blobHash;
bytes32 extraData;
address coinbase;
uint64 id;
uint64 l2BlockNumber;
uint32 gasLimit;
uint32 l1StateBlockNumber;
uint64 timestamp;
uint64 l1Height;
uint24 txListByteOffset;
uint24 txListByteSize;
bool blobUsed;
Expand All @@ -57,8 +57,8 @@ library TaikoData {
bytes32 blockHash;
bytes32 metaHash;
uint64 blockId;
uint64 proposedAt;
uint64 proposedIn;
uint64 timestamp;
uint32 l1StateBlockNumber;
}

/// @dev Struct holding the state variables for the {TaikoL1} contract.
Expand Down
3 changes: 3 additions & 0 deletions packages/protocol/contracts/L1/TaikoErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ abstract contract TaikoErrors {
error L1_INVALID_BLOCK_ID();
error L1_INVALID_CONFIG();
error L1_INVALID_ETH_DEPOSIT();
error L1_INVALID_L1_STATE_BLOCK();
error L1_INVALID_PARAM();
error L1_INVALID_PAUSE_STATUS();
error L1_INVALID_PROOF();
error L1_INVALID_PROPOSER();
error L1_INVALID_PROVER();
error L1_INVALID_TIER();
error L1_INVALID_TIMESTAMP();
error L1_INVALID_TRANSITION();
error L1_LIVENESS_BOND_NOT_RECEIVED();
error L1_NOT_ASSIGNED_PROVER();
Expand Down
59 changes: 49 additions & 10 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
pragma solidity ^0.8.20;

import "../common/EssentialContract.sol";
import "./preconfs/ISequencerRegistry.sol";
import "./TaikoErrors.sol";
import "./TaikoEvents.sol";

Expand Down Expand Up @@ -41,7 +42,7 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
// Init the genesis block
TaikoData.Block storage blk = state.blocks[0];
blk.blockHash = _genesisBlockHash;
blk.proposedAt = uint64(block.timestamp);
blk.timestamp = uint64(block.timestamp);

emit BlockVerified({
blockId: 0,
Expand All @@ -64,15 +65,24 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
onlyFromNamed("operator")
returns (TaikoData.BlockMetadata memory _block)
{
// If there's a sequencer registry, check if the block can be proposed by the current
// proposer
ISequencerRegistry sequencerRegistry =
ISequencerRegistry(resolve("sequencer_registry", true));
if (sequencerRegistry != ISequencerRegistry(address(0))) {
if (!sequencerRegistry.isEligibleSigner(msg.sender)) {
revert L1_INVALID_PROPOSER();
}
}

TaikoData.Config memory config = getConfig();

// Decode the block data
_block = abi.decode(data, (TaikoData.BlockMetadata));

// Verify L1 data
// TODO(Brecht): needs to be more configurable for preconfirmations
require(_block.l1Height == uint64(block.number - 1), "INVALID_L1_HEIGHT");
require(_block.l1Hash == blockhash(block.number - 1), "INVALID_L1_BLOCKHASH");
require(_block.l1Hash == blockhash(_block.l1StateBlockNumber), "INVALID_L1_BLOCKHASH");
require(_block.difficulty == block.prevrandao, "INVALID_DIFFICULTY");
require(_block.timestamp == uint64(block.timestamp), "INVALID_TIMESTAMP");
// Verify misc data
Expand All @@ -91,27 +101,56 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
// Check that the tx length is non-zero and within the supported range
require(_block.txListByteSize == 0 || _block.txListByteSize > config.blockMaxTxListBytes, "invalid txlist size");

TaikoData.Block storage parentBlock =
state.blocks[(state.numBlocks - 1)];
require(_block.parentMetaHash == parentBlock.metaHash, "invalid parentMetaHash");

// Verify the passed in L1 state block number.
// We only allow the L1 block to be 4 epochs old.
// The other constraint is that the L1 block number needs to be larger than or equal the one
// in the previous L2 block.
if (
_block.l1StateBlockNumber + 128 < block.number
|| _block.l1StateBlockNumber >= block.number
|| _block.l1StateBlockNumber < parentBlock.l1StateBlockNumber
) {
revert L1_INVALID_L1_STATE_BLOCK();
}

// Verify the passed in timestamp.
// We only allow the timestamp to be 4 epochs old.
// The other constraint is that the timestamp needs to be larger than or equal the one
// in the previous L2 block.
if (
_block.timestamp + 128 * 12 < block.timestamp
|| _block.timestamp > block.timestamp
|| _block.timestamp < parentBlock.timestamp
) {
revert L1_INVALID_TIMESTAMP();
}

// Create the block that will be stored onchain
TaikoData.Block memory blk = TaikoData.Block({
blockHash: _block.blockHash,
metaHash: keccak256(data),
blockId: state.numBlocks,
proposedAt: uint64(block.timestamp),
proposedIn: uint64(block.number)
timestamp: _block.timestamp,
l1StateBlockNumber: _block.l1StateBlockNumber
});

// Store the block
state.blocks[state.numBlocks] = blk;

// Store the passed in block hash as in
state.transitions[blk.blockId][_block.parentMetaHash].blockHash = _block.blockHash;
// For now it does not matter - we are not going to prove anyways
state.transitions[blk.blockId][_block.parentMetaHash].verifiableAfter = uint64(block.timestamp) + 365 days;

// Increment the counter (cursor) by 1.
state.numBlocks++;

emit BlockProposed({
blockId: _block.id,
blockId: _block.l2BlockNumber,
meta: _block
});
}
Expand All @@ -131,23 +170,23 @@ contract TaikoL1 is EssentialContract, TaikoEvents, TaikoErrors {
onlyFromNamed("operator")
{
// Check that the block has been proposed but has not yet been verified.
if (_block.id <= state.lastVerifiedBlockId || _block.id >= state.numBlocks) {
if (_block.l2BlockNumber <= state.lastVerifiedBlockId || _block.l2BlockNumber >= state.numBlocks) {
revert L1_INVALID_BLOCK_ID();
}

TaikoData.Block storage blk = state.blocks[_block.id];
TaikoData.Block storage blk = state.blocks[_block.l2BlockNumber];

// Make sure the correct block was proven
require(blk.metaHash != keccak256(abi.encode(_block)), "incorrect block");

// Store the transition
TaikoData.TransitionState storage storedTransition = state.transitions[_block.id][transition.parentHash];
TaikoData.TransitionState storage storedTransition = state.transitions[_block.l2BlockNumber][transition.parentHash];
storedTransition.blockHash = transition.blockHash;
storedTransition.prover = prover;
storedTransition.verifiableAfter = uint32(block.timestamp + SECURITY_DELAY_AFTER_PROVEN);

emit TransitionProved({
blockId: _block.id,
blockId: _block.l2BlockNumber,
tran: transition,
prover: prover
});
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/L1/actors/ProverPayment.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ contract ProverPayment {

// Check assignment validity
require((assignment.metaHash != 0 || keccak256(abi.encode(_block)) != assignment.metaHash)
&& (assignment.maxBlockId != 0 || _block.id > assignment.maxBlockId)
&& (assignment.maxBlockId != 0 || _block.l2BlockNumber > assignment.maxBlockId)
&& (assignment.maxProposedIn != 0 || block.number > assignment.maxProposedIn),
"unexpected block"
);
Expand Down
10 changes: 10 additions & 0 deletions packages/protocol/contracts/L1/preconfs/ISequencerRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/// @title ISequencerRegistry
/// @custom:security-contact [email protected]
interface ISequencerRegistry {
/// @notice Return true if the specified address can propose blocks, false otherwise
/// @param _proposer The address proposing a block
function isEligibleSigner(address _proposer) external returns (bool);
}
50 changes: 50 additions & 0 deletions packages/protocol/contracts/L1/preconfs/SequencerRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../common/EssentialContract.sol";
import "./ISequencerRegistry.sol";

/// @title SequencerRegistry
/// A dummy implementation that only whitelist some trusted addresses. A real
/// implementation would only allow a single proposer address to propose a block
/// using some selection mechanism.
/// @custom:security-contact [email protected]
contract SequencerRegistry is EssentialContract, ISequencerRegistry {
/// @dev Emitted when the status of a sequencer is updated.
/// @param sequencer The address of the sequencer whose state has updated.
/// @param enabled If the sequencer is now enabled or not.
event SequencerUpdated(address indexed sequencer, bool enabled);

/// @notice Whitelisted sequencers
mapping(address sequencer => bool enabled) public sequencers;

uint256[49] private __gap;

/// @notice Initializes the contract with the provided address manager.
/// @param _owner The address of the owner.
function init(address _owner) external initializer {
__Essential_init(_owner);
}

/// @notice Sets/unsets an the imageId as trusted entity
/// @param _sequencers The list of sequencers
/// @param _enabled The corresponding list of the new status of the sequencers
function setSequencers(
address[] memory _sequencers,
bool[] memory _enabled
)
external
onlyOwner
{
require(_sequencers.length == _enabled.length, "invalid input data");
for (uint256 i = 0; i < _sequencers.length; i++) {
sequencers[_sequencers[i]] = _enabled[i];
emit SequencerUpdated(_sequencers[i], _enabled[i]);
}
}

/// @inheritdoc ISequencerRegistry
function isEligibleSigner(address _proposer) external view returns (bool) {
return sequencers[_proposer];
}
}
2 changes: 1 addition & 1 deletion packages/protocol/contracts/L1/provers/GuardianProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ contract GuardianProver is Guardians {
returns (bool approved)
{
bytes32 hash = keccak256(abi.encode(meta, tran));
approved = approve(meta.id, hash);
approved = approve(meta.l2BlockNumber, hash);

if (approved) {
deleteApproval(hash);
Expand Down
7 changes: 6 additions & 1 deletion packages/protocol/deployments/deploy_l1.json
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
{}
{
"address_manager": "0x19A827174F66B3c66ad7063951D7b4F94f996e77",
"bridge": "0x1a76F7BA873f90805B49A51cBA617E699Cf142B0",
"erc721_vault": "0x9D46a79Ad6e0dcb36AbAb982e608e186E6826b7C",
"signal_service": "0x798684a55404079b77E19A86325e0c11eA5BB09D"
}

0 comments on commit 346959e

Please sign in to comment.