diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index 74292083eb..d1f99416ac 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -164,6 +164,7 @@ library TaikoData { // this block is not verified as the last block in a batch, verifiedTransitionId // will remain zero. uint32 verifiedTransitionId; + uint16 minTier; } /// @dev Struct representing an Ethereum deposit. diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index 8f42af838c..54e1cfaae3 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -198,12 +198,18 @@ library LibProposing { emit CalldataTxList(meta_.id, _txList); } + uint16 minTier; { ITierRouter tierRouter = ITierRouter(_resolver.resolve(LibStrings.B_TIER_ROUTER, false)); ITierProvider tierProvider = ITierProvider(tierRouter.getProvider(local.b.numBlocks)); - // Use the difficulty as a random number - meta_.minTier = tierProvider.getMinTier(uint256(meta_.difficulty)); + if (local.postFork) { + minTier = + tierProvider.getMinTier(uint256(bytes32(block.prevrandao) ^ meta_.difficulty)); + } else { + // Use the difficulty as a random number + meta_.minTier = tierProvider.getMinTier(uint256(meta_.difficulty)); + } } // Create the block that will be stored onchain @@ -217,7 +223,8 @@ library LibProposing { // For a new block, the next transition ID is always 1, not 0. nextTransitionId: 1, // For unverified block, its verifiedTransitionId is always 0. - verifiedTransitionId: 0 + verifiedTransitionId: 0, + minTier: minTier }); // Store the block in the ring buffer diff --git a/packages/protocol/contracts/L1/libs/LibProving.sol b/packages/protocol/contracts/L1/libs/LibProving.sol index d6b6941cef..3526b2e2cc 100644 --- a/packages/protocol/contracts/L1/libs/LibProving.sol +++ b/packages/protocol/contracts/L1/libs/LibProving.sol @@ -25,6 +25,7 @@ library LibProving { uint64 slot; uint64 blockId; uint32 tid; + uint16 blockMinTier; bool lastUnpausedAt; bool isTopTier; bool inProvingWindow; @@ -165,6 +166,7 @@ library LibProving { TaikoData.Block storage blk = _state.blocks[local.slot]; local.proposedAt = local.postFork ? meta.proposedAt : blk.proposedAt; + local.blockMinTier = meta.minTier == 0 ? blk.minTier : meta.minTier; if (LibUtils.shouldSyncStateRoot(_config.stateRootSyncInternal, local.blockId)) { local.stateRoot = tran.stateRoot; @@ -197,7 +199,7 @@ library LibProving { // The new proof must meet or exceed the minimum tier required by the // block or the previous proof; it cannot be on a lower tier. - if (proof.tier == 0 || proof.tier < meta.minTier || proof.tier < ts.tier) { + if (proof.tier == 0 || proof.tier < local.blockMinTier || proof.tier < ts.tier) { revert L1_INVALID_TIER(); } @@ -208,7 +210,7 @@ library LibProving { ITierProvider tierProvider = ITierProvider(tierRouter.getProvider(local.blockId)); local.tier = tierProvider.getTier(proof.tier); - local.minTier = tierProvider.getTier(meta.minTier); + local.minTier = tierProvider.getTier(local.blockMinTier); } local.inProvingWindow = !LibUtils.isPostDeadline({