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): add preconf from taiko-mono helder branch #15

Merged
merged 21 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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 @@
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 @@
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 @@

// 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 @@ -146,7 +146,7 @@
for (uint blockId = lastVerifiedBlockIdBefore + 1; blockId <= lastVerifiedBlockIdAfter; blockId++) {
Block storage blk = blocks[blockId];

// TODO(Brecht): Verify that all the verifers used to prove the block are still valid

Check failure on line 149 in packages/protocol/contracts/L1/BasedOperator.sol

View workflow job for this annotation

GitHub Actions / codespell

verifers ==> verifiers

// Find out who the prover is
TaikoData.Block memory previousBlock = taiko.getBlock(uint64(blockId) - 1);
Expand All @@ -162,7 +162,7 @@
}
}

// Additinal proposer rules

Check failure on line 165 in packages/protocol/contracts/L1/BasedOperator.sol

View workflow job for this annotation

GitHub Actions / codespell

Additinal ==> Additional
function _isProposerPermitted(
TaikoData.BlockMetadata memory _block
)
Expand All @@ -170,7 +170,7 @@
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 @@ -7,7 +7,7 @@
pragma solidity ^0.8.20;

/// @title TaikoErrors
/// @notice This abstract contract provides custom error declartions used in

Check failure on line 10 in packages/protocol/contracts/L1/TaikoErrors.sol

View workflow job for this annotation

GitHub Actions / codespell

declartions ==> declarations
/// the Taiko protocol. Each error corresponds to specific situations where
/// exceptions might be thrown.
abstract contract TaikoErrors {
Expand All @@ -26,11 +26,14 @@
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();
}
}

adaki2004 marked this conversation as resolved.
Show resolved Hide resolved
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"
}
Loading