Skip to content

Commit

Permalink
fix(protocol): switch back to selector-based fork router (#18834)
Browse files Browse the repository at this point in the history
  • Loading branch information
dantaik authored Jan 24, 2025
1 parent a89cbcb commit 925191c
Show file tree
Hide file tree
Showing 21 changed files with 254 additions and 302 deletions.
11 changes: 0 additions & 11 deletions packages/protocol/contracts/layer1/based/IFork.sol

This file was deleted.

9 changes: 5 additions & 4 deletions packages/protocol/contracts/layer1/based/ITaikoInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ interface ITaikoInbox {
uint256 batchId_mod_batchRingBufferSize
=> mapping(uint24 transitionId => TransitionState ts)
) transitions;
bytes32 __reserve1; // Used as a ring buffer for Ether deposits
bytes32 __reserve1; // slot 4 - was used as a ring buffer for Ether deposits
Stats1 stats1; // slot 5
Stats2 stats2; // slot 6
mapping(address account => uint256 bond) bondBalance;
Expand Down Expand Up @@ -266,6 +266,7 @@ interface ITaikoInbox {
error CustomProposerMissing();
error CustomProposerNotAllowed();
error EtherNotPaidAsBond();
error ForkNotActivated();
error InsufficientBond();
error InvalidBlobParams();
error InvalidGenesisBlockHash();
Expand Down Expand Up @@ -346,7 +347,7 @@ interface ITaikoInbox {
/// @param _batchId The batch ID.
/// @param _tid The transition ID.
/// @return The specified transition state.
function getTransition(
function getTransitionById(
uint64 _batchId,
uint24 _tid
)
Expand All @@ -359,7 +360,7 @@ interface ITaikoInbox {
/// @param _batchId The batch ID.
/// @param _parentHash The parent hash.
/// @return The specified transition state.
function getTransition(
function getTransitionByParentHash(
uint64 _batchId,
bytes32 _parentHash
)
Expand Down Expand Up @@ -395,5 +396,5 @@ interface ITaikoInbox {

/// @notice Retrieves the current protocol configuration.
/// @return The current configuration.
function getConfig() external view returns (Config memory);
function pacayaConfig() external view returns (Config memory);
}
172 changes: 93 additions & 79 deletions packages/protocol/contracts/layer1/based/TaikoInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ import "src/shared/libs/LibNetwork.sol";
import "src/shared/libs/LibStrings.sol";
import "src/shared/signal/ISignalService.sol";
import "src/layer1/verifiers/IVerifier.sol";
import "./IFork.sol";
import "./ITaikoInbox.sol";

// import "forge-std/src/console2.sol";

/// @title TaikoInbox
/// @notice Acts as the inbox for the Taiko Alethia protocol, a simplified version of the
/// original Taiko-Based Contestable Rollup (BCR). The tier-based proof system and
Expand All @@ -28,7 +25,7 @@ import "./ITaikoInbox.sol";
///
/// @dev Registered in the address resolver as "taiko".
/// @custom:security-contact [email protected]
abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko {
using LibMath for uint256;

State public state; // storage layout much match Ontake fork
Expand Down Expand Up @@ -58,8 +55,9 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
{
Stats2 memory stats2 = state.stats2;
require(!stats2.paused, ContractPaused());
require(stats2.numBatches >= pacayaConfig().forkHeights.pacaya, ForkNotActivated());

Config memory config = getConfig();
Config memory config = pacayaConfig();

unchecked {
require(
Expand Down Expand Up @@ -213,13 +211,15 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
Stats2 memory stats2 = state.stats2;
require(stats2.paused == false, ContractPaused());

Config memory config = getConfig();
Config memory config = pacayaConfig();
IVerifier.Context[] memory ctxs = new IVerifier.Context[](metas.length);

bool hasConflictingProof;
for (uint256 i; i < metas.length; ++i) {
BatchMetadata memory meta = metas[i];

require(meta.batchId >= pacayaConfig().forkHeights.pacaya, ForkNotActivated());

require(meta.batchId > stats2.lastVerifiedBatchId, BatchNotFound());
require(meta.batchId < stats2.numBatches, BatchNotFound());

Expand Down Expand Up @@ -313,6 +313,14 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
}
}

/// @notice Verify batches by providing the length of the batches to verify.
/// @dev This function is necessary to upgrade from this fork to the next one.
/// @param _length Specifis how many batches to verify. The max number of batches to verify is
/// `pacayaConfig().maxBatchesToVerify * _length`.
function verifyBatches(uint64 _length) external nonZeroValue(_length) nonReentrant {
_verifyBatches(pacayaConfig(), state.stats2, _length);
}

/// @notice Manually write a transition for a batch.
/// @dev This function is supposed to be used by the owner to force prove a transition for a
/// block that has not been verified.
Expand All @@ -330,7 +338,7 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
require(_blockHash != 0 && _parentHash != 0 && _stateRoot != 0, InvalidParams());
require(_batchId > state.stats2.lastVerifiedBatchId, BatchVerified());

Config memory config = getConfig();
Config memory config = pacayaConfig();
uint256 slot = _batchId % config.batchRingBufferSize;
Batch storage batch = state.batches[slot];
require(batch.batchId == _batchId, BatchNotFound());
Expand Down Expand Up @@ -393,15 +401,15 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
}

/// @inheritdoc ITaikoInbox
function getTransition(
function getTransitionById(
uint64 _batchId,
uint24 _tid
)
external
view
returns (TransitionState memory)
{
Config memory config = getConfig();
Config memory config = pacayaConfig();
uint256 slot = _batchId % config.batchRingBufferSize;
Batch storage batch = state.batches[slot];
require(batch.batchId == _batchId, BatchNotFound());
Expand All @@ -410,15 +418,15 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
}

/// @inheritdoc ITaikoInbox
function getTransition(
function getTransitionByParentHash(
uint64 _batchId,
bytes32 _parentHash
)
external
view
returns (TransitionState memory)
{
Config memory config = getConfig();
Config memory config = pacayaConfig();
uint256 slot = _batchId % config.batchRingBufferSize;
Batch storage batch = state.batches[slot];
require(batch.batchId == _batchId, BatchNotFound());
Expand Down Expand Up @@ -462,11 +470,6 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
return true;
}

// @inheritdoc IFork
function isForkActive() external view override returns (bool) {
return state.stats2.numBatches >= getConfig().forkHeights.pacaya;
}

// Public functions -------------------------------------------------------------------------

/// @inheritdoc EssentialContract
Expand All @@ -481,7 +484,7 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {

/// @inheritdoc ITaikoInbox
function getBatch(uint64 _batchId) public view returns (Batch memory batch_) {
Config memory config = getConfig();
Config memory config = pacayaConfig();

batch_ = state.batches[_batchId % config.batchRingBufferSize];
require(batch_.batchId == _batchId, BatchNotFound());
Expand All @@ -493,7 +496,7 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
view
returns (TransitionState memory ts_)
{
Config memory config = getConfig();
Config memory config = pacayaConfig();

uint64 slot = _batchId % config.batchRingBufferSize;
Batch storage batch = state.batches[slot];
Expand All @@ -505,7 +508,7 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
}

/// @inheritdoc ITaikoInbox
function getConfig() public view virtual returns (Config memory);
function pacayaConfig() public view virtual returns (Config memory);

// Internal functions ----------------------------------------------------------------------

Expand Down Expand Up @@ -575,85 +578,96 @@ abstract contract TaikoInbox is EssentialContract, ITaikoInbox, ITaiko, IFork {
private
{
uint64 batchId = _stats2.lastVerifiedBatchId;
uint256 slot = batchId % _config.batchRingBufferSize;
Batch storage batch = state.batches[slot];
uint24 tid = batch.verifiedTransitionId;
bytes32 blockHash = state.transitions[slot][tid].blockHash;

SyncBlock memory synced;

uint256 stopBatchId;
bool canVerifyBlocks;
unchecked {
stopBatchId = (_config.maxBatchesToVerify * _length + _stats2.lastVerifiedBatchId + 1)
.min(_stats2.numBatches);
uint64 pacayaForkHeight = pacayaConfig().forkHeights.pacaya;
canVerifyBlocks = pacayaForkHeight == 0 || batchId >= pacayaForkHeight - 1;
}

for (++batchId; batchId < stopBatchId; ++batchId) {
slot = batchId % _config.batchRingBufferSize;
batch = state.batches[slot];
uint24 nextTransitionId = batch.nextTransitionId;
if (canVerifyBlocks) {
uint256 slot = batchId % _config.batchRingBufferSize;
Batch storage batch = state.batches[slot];
uint24 tid = batch.verifiedTransitionId;
bytes32 blockHash = state.transitions[slot][tid].blockHash;

if (nextTransitionId <= 1) break;
SyncBlock memory synced;

TransitionState storage ts = state.transitions[slot][1];
if (ts.parentHash == blockHash) {
tid = 1;
} else if (nextTransitionId > 2) {
uint24 _tid = state.transitionIds[batchId][blockHash];
if (_tid == 0) break;
tid = _tid;
ts = state.transitions[slot][tid];
} else {
break;
uint256 stopBatchId;
unchecked {
stopBatchId = (
_config.maxBatchesToVerify * _length + _stats2.lastVerifiedBatchId + 1
).min(_stats2.numBatches);
}

blockHash = ts.blockHash;
for (++batchId; batchId < stopBatchId; ++batchId) {
slot = batchId % _config.batchRingBufferSize;
batch = state.batches[slot];
uint24 nextTransitionId = batch.nextTransitionId;

uint96 bondToReturn = ts.inProvingWindow ? batch.livenessBond : batch.livenessBond / 2;
_creditBond(ts.prover, bondToReturn);
if (nextTransitionId <= 1) break;

if (batchId % _config.stateRootSyncInternal == 0) {
synced.batchId = batchId;
synced.blockId = batch.lastBlockId;
synced.tid = tid;
synced.stateRoot = ts.stateRoot;
}
TransitionState storage ts = state.transitions[slot][1];
if (ts.parentHash == blockHash) {
tid = 1;
} else if (nextTransitionId > 2) {
uint24 _tid = state.transitionIds[batchId][blockHash];
if (_tid == 0) break;
tid = _tid;
ts = state.transitions[slot][tid];
} else {
break;
}

blockHash = ts.blockHash;

uint96 bondToReturn =
ts.inProvingWindow ? batch.livenessBond : batch.livenessBond / 2;
_creditBond(ts.prover, bondToReturn);

if (batchId % _config.stateRootSyncInternal == 0) {
synced.batchId = batchId;
synced.blockId = batch.lastBlockId;
synced.tid = tid;
synced.stateRoot = ts.stateRoot;
}

for (uint24 i = 2; i < nextTransitionId; ++i) {
ts = state.transitions[slot][i];
delete state.transitionIds[batchId][ts.parentHash];
for (uint24 i = 2; i < nextTransitionId; ++i) {
ts = state.transitions[slot][i];
delete state.transitionIds[batchId][ts.parentHash];
}
}
}

unchecked {
--batchId;
}
unchecked {
--batchId;
}

if (_stats2.lastVerifiedBatchId != batchId) {
_stats2.lastVerifiedBatchId = batchId;
if (_stats2.lastVerifiedBatchId != batchId) {
_stats2.lastVerifiedBatchId = batchId;

batch = state.batches[_stats2.lastVerifiedBatchId % _config.batchRingBufferSize];
batch.verifiedTransitionId = tid;
emit BatchesVerified(_stats2.lastVerifiedBatchId, blockHash);
batch = state.batches[_stats2.lastVerifiedBatchId % _config.batchRingBufferSize];
batch.verifiedTransitionId = tid;
emit BatchesVerified(_stats2.lastVerifiedBatchId, blockHash);

if (synced.batchId != 0) {
if (synced.batchId != _stats2.lastVerifiedBatchId) {
// We write the synced batch's verifiedTransitionId to storage
batch = state.batches[synced.batchId % _config.batchRingBufferSize];
batch.verifiedTransitionId = synced.tid;
}
if (synced.batchId != 0) {
if (synced.batchId != _stats2.lastVerifiedBatchId) {
// We write the synced batch's verifiedTransitionId to storage
batch = state.batches[synced.batchId % _config.batchRingBufferSize];
batch.verifiedTransitionId = synced.tid;
}

Stats1 memory stats1 = state.stats1;
stats1.lastSyncedBatchId = batch.batchId;
stats1.lastSyncedAt = uint64(block.timestamp);
state.stats1 = stats1;
Stats1 memory stats1 = state.stats1;
stats1.lastSyncedBatchId = batch.batchId;
stats1.lastSyncedAt = uint64(block.timestamp);
state.stats1 = stats1;

emit Stats1Updated(stats1);
emit Stats1Updated(stats1);

// Ask signal service to write cross chain signal
ISignalService(resolve(LibStrings.B_SIGNAL_SERVICE, false)).syncChainData(
_config.chainId, LibStrings.H_STATE_ROOT, synced.blockId, synced.stateRoot
);
// Ask signal service to write cross chain signal
ISignalService(resolve(LibStrings.B_SIGNAL_SERVICE, false)).syncChainData(
_config.chainId, LibStrings.H_STATE_ROOT, synced.blockId, synced.stateRoot
);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/layer1/devnet/DevnetInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ contract DevnetInbox is TaikoInbox {
constructor(address _resolver) TaikoInbox(_resolver) { }

/// @inheritdoc ITaikoInbox
function getConfig() public pure override returns (ITaikoInbox.Config memory) {
function pacayaConfig() public pure override returns (ITaikoInbox.Config memory) {
return ITaikoInbox.Config({
chainId: 167_001,
maxUnverifiedBatches: 324_000,
Expand Down
Loading

0 comments on commit 925191c

Please sign in to comment.