-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(protocol): switch back to selector-based fork router (#18834)
- Loading branch information
Showing
21 changed files
with
254 additions
and
302 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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 | ||
|
@@ -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( | ||
|
@@ -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()); | ||
|
||
|
@@ -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. | ||
|
@@ -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()); | ||
|
@@ -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()); | ||
|
@@ -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()); | ||
|
@@ -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 | ||
|
@@ -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()); | ||
|
@@ -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]; | ||
|
@@ -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 ---------------------------------------------------------------------- | ||
|
||
|
@@ -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 | ||
); | ||
} | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.