Skip to content

Commit

Permalink
move sequencer registry check & forge fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
Keszey Dániel authored and Keszey Dániel committed Jul 4, 2024
1 parent 346959e commit a66ba4d
Show file tree
Hide file tree
Showing 27 changed files with 188 additions and 227 deletions.
83 changes: 48 additions & 35 deletions packages/protocol/contracts/L1/BasedOperator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../common/AddressResolver.sol";
import "../common/EssentialContract.sol";
import "../libs/LibAddress.sol";
import "./preconfs/ISequencerRegistry.sol";
import "./TaikoL1.sol";
import "./TaikoData.sol";
import "./TaikoErrors.sol";
import "./VerifierRegistry.sol";
import "./verifiers/IVerifier.sol";

/// @title BasedOperator
/// @notice A based operator for Taiko.
contract BasedOperator is EssentialContract {
contract BasedOperator is EssentialContract, TaikoErrors {
using LibAddress for address;

struct Block {
Expand All @@ -44,16 +46,16 @@ contract BasedOperator is EssentialContract {
address prover;
}

uint public constant PROVER_BOND = 1 ether / 10;
uint public constant MAX_GAS_PROVER_PAYMENT = 50_000;
uint public constant MAX_BLOCKS_TO_VERIFY = 5;
uint public constant PROVING_WINDOW = 1 hours;
uint256 public constant PROVER_BOND = 1 ether / 10;
uint256 public constant MAX_GAS_PROVER_PAYMENT = 50_000;
uint256 public constant MAX_BLOCKS_TO_VERIFY = 5;
uint256 public constant PROVING_WINDOW = 1 hours;

TaikoL1 public taiko;
VerifierRegistry public verifierRegistry;
address public treasury;

mapping(uint => Block) public blocks;
mapping(uint256 => Block) public blocks;

/// @dev Proposes a Taiko L2 block.
function proposeBlock(
Expand All @@ -72,53 +74,58 @@ contract BasedOperator is EssentialContract {
_block = taiko.proposeBlock(params, txList);

// Check if we have whitelisted proposers
require(_isProposerPermitted(_block), "proposer not allowed");
if (!_isProposerPermitted(_block)) {
revert L1_INVALID_PROPOSER();
}

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

// Verify some blocks
_verifyBlocks(MAX_BLOCKS_TO_VERIFY);
}

/// @dev Proposes a Taiko L2 block.
function proveBlock(bytes calldata data)
external
nonReentrant
whenNotPaused
{
function proveBlock(bytes calldata data) external nonReentrant whenNotPaused {
// Decode the block data
ProofBatch memory proofBatch = abi.decode(data, (ProofBatch));

// Check who can prove the block
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");
require(
proofBatch.prover == blocks[proofBatch._block.l2BlockNumber].assignedProver,
"assigned prover not the prover"
);
}

// Verify the proofs
uint160 prevVerifier = uint160(0);
for (uint i = 0; i < proofBatch.proofs.length; i++) {
for (uint256 i = 0; i < proofBatch.proofs.length; i++) {
IVerifier verifier = proofBatch.proofs[i].verifier;
// Make sure each verifier is unique
require(prevVerifier >= uint160(address(verifier)), "duplicated verifier");
// Make sure it's a valid verifier
require(verifierRegistry.isVerifier(address(verifier)), "invalid verifier");
// Verify the proof
verifier.verifyProof(proofBatch._block, proofBatch.transition, proofBatch.prover, proofBatch.proofs[i].proof);
verifier.verifyProof(
proofBatch._block,
proofBatch.transition,
proofBatch.prover,
proofBatch.proofs[i].proof
);
prevVerifier = uint160(address(verifier));
}

// Make sure the supplied proofs are sufficient.
// Can use some custom logic here. but let's keep it simple
require(proofBatch.proofs.length >= 3, "insufficient number of proofs");

// Only allow an already proven block to be overwritten when the verifiers used are now invalid
// 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.l2BlockNumber, 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 All @@ -132,18 +139,22 @@ contract BasedOperator is EssentialContract {
_verifyBlocks(MAX_BLOCKS_TO_VERIFY);
}

function verifyBlocks(uint maxBlocksToVerify) external nonReentrant whenNotPaused {
function verifyBlocks(uint256 maxBlocksToVerify) external nonReentrant whenNotPaused {
_verifyBlocks(maxBlocksToVerify);
}

function _verifyBlocks(uint maxBlocksToVerify) internal {
uint lastVerifiedBlockIdBefore = taiko.getLastVerifiedBlockId();
function _verifyBlocks(uint256 maxBlocksToVerify) internal {
uint256 lastVerifiedBlockIdBefore = taiko.getLastVerifiedBlockId();
// Verify the blocks
taiko.verifyBlocks(maxBlocksToVerify);
uint lastVerifiedBlockIdAfter = taiko.getLastVerifiedBlockId();
uint256 lastVerifiedBlockIdAfter = taiko.getLastVerifiedBlockId();

// So some additional checks on top of the standard checks done in the rollup contract
for (uint blockId = lastVerifiedBlockIdBefore + 1; blockId <= lastVerifiedBlockIdAfter; blockId++) {
for (
uint256 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 160 in packages/protocol/contracts/L1/BasedOperator.sol

View workflow job for this annotation

GitHub Actions / codespell

verifers ==> verifiers
Expand All @@ -163,13 +174,7 @@ contract BasedOperator is EssentialContract {
}

// Additinal proposer rules

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

View workflow job for this annotation

GitHub Actions / codespell

Additinal ==> Additional
function _isProposerPermitted(
TaikoData.BlockMetadata memory _block
)
private
view
returns (bool)
{
function _isProposerPermitted(TaikoData.BlockMetadata memory _block) private returns (bool) {
if (_block.l2BlockNumber == 1) {
// Only proposer_one can propose the first block after genesis
address proposerOne = resolve("proposer_one", true);
Expand All @@ -178,7 +183,15 @@ contract BasedOperator is EssentialContract {
}
}

address proposer = resolve("proposer", true);
return proposer == address(0) || msg.sender == proposer;
// 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)) {
return false;
}
}
return true;
}
}
7 changes: 2 additions & 5 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,14 @@ library TaikoData {

/// @dev Struct holding the state variables for the {TaikoL1} contract.
struct State {
mapping(uint blockId => Block) blocks;
mapping(uint blockId => mapping(bytes32 parentBlockHash => TransitionState)) transitions;

mapping(uint256 blockId => Block) blocks;
mapping(uint256 blockId => mapping(bytes32 parentBlockHash => TransitionState)) transitions;
uint64 genesisHeight;
uint64 genesisTimestamp;

uint64 numBlocks;
uint64 lastVerifiedBlockId;
bool provingPaused;
uint64 lastUnpausedAt;

uint256[143] __gap;
}
}
16 changes: 3 additions & 13 deletions packages/protocol/contracts/L1/TaikoEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,12 @@ abstract contract TaikoEvents {
/// @param blockId The ID of the proposed block.
/// @param meta The block metadata containing information about the proposed
/// block.
event BlockProposed(
uint256 indexed blockId,
TaikoData.BlockMetadata meta
);
event BlockProposed(uint256 indexed blockId, TaikoData.BlockMetadata meta);
/// @dev Emitted when a block is verified.
/// @param blockId The ID of the verified block.
/// @param blockHash The hash of the verified block.
event BlockVerified(
uint256 indexed blockId,
bytes32 blockHash
);
event BlockVerified(uint256 indexed blockId, bytes32 blockHash);

/// @dev Emitted when a block transition is proved or re-proved.
event TransitionProved(
uint256 indexed blockId,
TaikoData.Transition tran,
address prover
);
event TransitionProved(uint256 indexed blockId, TaikoData.Transition tran, address prover);
}
Loading

0 comments on commit a66ba4d

Please sign in to comment.