Skip to content

Commit

Permalink
feat(protocol): use num proposals to measure forced inclusion deadline (
Browse files Browse the repository at this point in the history
  • Loading branch information
dantaik authored Feb 1, 2025
1 parent 13113d8 commit 9e4f417
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 150 deletions.
4 changes: 4 additions & 0 deletions packages/protocol/contract_layout_layer1.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@

## ForkRouter

## contracts/layer1/forced-inclusion/TaikoWrapper

## contracts/layer1/forced-inclusion/ForcedInclusionStore

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "src/shared/common/EssentialContract.sol";
import "src/shared/libs/LibMath.sol";
import "src/shared/libs/LibAddress.sol";
import "src/shared/libs/LibStrings.sol";
import "src/layer1/based/ITaikoInbox.sol";
import "./IForcedInclusionStore.sol";

/// @title ForcedInclusionStore
Expand All @@ -19,19 +20,20 @@ contract ForcedInclusionStore is EssentialContract, IForcedInclusionStore {

uint256 private constant SECONDS_PER_BLOCK = 12;

uint256 public immutable inclusionDelay;
uint8 public immutable inclusionDelay;
uint64 public immutable feeInGwei;

mapping(uint256 id => ForcedInclusion inclusion) public queue; // slot 1
uint64 public head; // slot 2
uint64 public tail;
uint128 private __reserved1;
uint64 public lastProcessedAtBatchId;
uint64 private __reserved1;

uint256[48] private __gap;

constructor(
address _resolver,
uint256 _inclusionDelay,
uint8 _inclusionDelay,
uint64 _feeInGwei
)
EssentialContract(_resolver)
Expand Down Expand Up @@ -60,10 +62,12 @@ contract ForcedInclusionStore is EssentialContract, IForcedInclusionStore {
require(blobHash != bytes32(0), BlobNotFound());
require(msg.value == feeInGwei * 1 gwei, IncorrectFee());

ITaikoInbox inbox = ITaikoInbox(resolve(LibStrings.B_TAIKO, false));

ForcedInclusion memory inclusion = ForcedInclusion({
blobHash: blobHash,
feeInGwei: uint64(msg.value / 1 gwei),
createdAt: uint64(block.timestamp),
createdAtBatchId: inbox.getStats2().numBatches,
blobByteOffset: blobByteOffset,
blobByteSize: blobByteSize
});
Expand All @@ -73,23 +77,47 @@ contract ForcedInclusionStore is EssentialContract, IForcedInclusionStore {
emit ForcedInclusionStored(inclusion);
}

function consumeForcedInclusion(address _feeRecipient)
function consumeOldestForcedInclusion(address _feeRecipient)
external
nonReentrant
onlyFromNamed(LibStrings.B_TAIKO_FORCED_INCLUSION_INBOX)
onlyFromNamed(LibStrings.B_TAIKO_WRAPPER)
returns (ForcedInclusion memory inclusion_)
{
// we only need to check the first one, since it will be the oldest.
uint64 _head = head;
ForcedInclusion storage inclusion = queue[_head];
require(inclusion.createdAtBatchId != 0, NoForcedInclusionFound());

ITaikoInbox inbox = ITaikoInbox(resolve(LibStrings.B_TAIKO, false));

inclusion_ = inclusion;
delete queue[_head];

if (inclusion.createdAt != 0 && block.timestamp >= inclusionDelay + inclusion.createdAt) {
inclusion_ = inclusion;
_feeRecipient.sendEtherAndVerify(inclusion.feeInGwei * 1 gwei);
delete queue[_head];
unchecked {
lastProcessedAtBatchId = inbox.getStats2().numBatches;
head = _head + 1;
emit ForcedInclusionConsumed(inclusion);
}

emit ForcedInclusionConsumed(inclusion_);
_feeRecipient.sendEtherAndVerify(inclusion_.feeInGwei * 1 gwei);
}

function getForcedInclusion(uint256 index) external view returns (ForcedInclusion memory) {
return queue[index];
}

function getOldestForcedInclusionDeadline() public view returns (uint256) {
unchecked {
ForcedInclusion storage inclusion = queue[head];
return inclusion.createdAtBatchId == 0
? type(uint64).max
: uint256(lastProcessedAtBatchId).max(inclusion.createdAtBatchId) + inclusionDelay;
}
}

function isOldestForcedInclusionDue() external view returns (bool) {
ITaikoInbox inbox = ITaikoInbox(resolve(LibStrings.B_TAIKO, false));
return inbox.getStats2().numBatches >= getOldestForcedInclusionDeadline();
}

// @dev Override this function for easier testing blobs
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ interface IForcedInclusionStore {
/// @dev Error thrown when the fee is incorrect.
error IncorrectFee();

error NoForcedInclusionFound();

/// @dev Event emitted when a forced inclusion is stored.
event ForcedInclusionStored(ForcedInclusion forcedInclusion);
/// @dev Event emitted when a forced inclusion is consumed.
Expand All @@ -19,16 +21,30 @@ interface IForcedInclusionStore {
struct ForcedInclusion {
bytes32 blobHash;
uint64 feeInGwei;
uint64 createdAt;
uint64 createdAtBatchId;
uint32 blobByteOffset;
uint32 blobByteSize;
}

/// @dev Retrieve a forced inclusion request by its index.
/// @param index The index of the forced inclusion request in the queue.
/// @return The forced inclusion request at the specified index.
function getForcedInclusion(uint256 index) external view returns (ForcedInclusion memory);

/// @dev Get the deadline for the oldest forced inclusion.
/// @return The deadline for the oldest forced inclusion.
function getOldestForcedInclusionDeadline() external view returns (uint256);

/// @dev Check if the oldest forced inclusion is due.
/// @return True if the oldest forced inclusion is due, false otherwise.
function isOldestForcedInclusionDue() external view returns (bool);

/// @dev Consume a forced inclusion request.
/// The inclusion request must be marked as processed and the priority fee must be paid to the
/// caller.
/// @param _feeRecipient The address to receive the priority fee.
/// @return inclusion_ The forced inclusion request.
function consumeForcedInclusion(address _feeRecipient)
function consumeOldestForcedInclusion(address _feeRecipient)
external
returns (ForcedInclusion memory);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import "src/layer1/verifiers/IVerifier.sol";
import "src/layer1/based/TaikoInbox.sol";
import "./ForcedInclusionStore.sol";

/// @title ForcedInclusionInbox
/// @title TaikoWrapper
/// @dev This contract is part of a delayed inbox implementation to enforce the inclusion of
/// transactions.
/// The current design is a simplified and can be improved with the following ideas:
Expand All @@ -38,12 +38,18 @@ import "./ForcedInclusionStore.sol";
/// consumption.
///
/// @custom:security-contact [email protected]
contract ForcedInclusionInbox is EssentialContract {

contract TaikoWrapper is EssentialContract {
using LibMath for uint256;

/// @dev Event emitted when a forced inclusion is processed.
event ForcedInclusionProcessed(IForcedInclusionStore.ForcedInclusion);
/// @dev Error thrown when the oldest forced inclusion is due.

error OldestForcedInclusionDue();

uint16 public constant MAX_FORCED_TXS_PER_FORCED_INCLUSION = 512;

uint256[50] private __gap;

constructor(address _resolver) EssentialContract(_resolver) { }
Expand All @@ -52,12 +58,14 @@ contract ForcedInclusionInbox is EssentialContract {
__Essential_init(_owner);
}

/// @notice Proposes a batch of blocks.
/// @notice Proposes a batch of blocks with forced inclusion.
/// @param _forcedInclusionParams An optional ABI-encoded BlockParams for the forced inclusion
/// batch.
/// @param _params ABI-encoded BlockParams.
/// @param _txList The transaction list in calldata. If the txList is empty, blob will be used
/// for data availability.
/// @return info_ The info of the proposed batch.
/// @return meta_ The metadata of the proposed batch.
function proposeBatchWithForcedInclusion(
bytes calldata _forcedInclusionParams,
bytes calldata _params,
Expand All @@ -68,21 +76,18 @@ contract ForcedInclusionInbox is EssentialContract {
returns (ITaikoInbox.BatchInfo memory info_, ITaikoInbox.BatchMetadata memory meta_)
{
ITaikoInbox inbox = ITaikoInbox(resolve(LibStrings.B_TAIKO, false));
(info_, meta_) = inbox.proposeBatch(_params, _txList);

// Process the next forced inclusion.
IForcedInclusionStore store =
IForcedInclusionStore(resolve(LibStrings.B_FORCED_INCLUSION_STORE, false));

IForcedInclusionStore.ForcedInclusion memory inclusion =
store.consumeForcedInclusion(msg.sender);
if (_forcedInclusionParams.length == 0) {
require(!store.isOldestForcedInclusionDue(), OldestForcedInclusionDue());
} else {
IForcedInclusionStore.ForcedInclusion memory inclusion =
store.consumeOldestForcedInclusion(msg.sender);

if (inclusion.createdAt != 0) {
ITaikoInbox.BatchParams memory params;

if (_forcedInclusionParams.length != 0) {
params = abi.decode(_forcedInclusionParams, (ITaikoInbox.BatchParams));
}
ITaikoInbox.BatchParams memory params =
abi.decode(_forcedInclusionParams, (ITaikoInbox.BatchParams));

// Overwrite the batch params to have only 1 block and up to
// MAX_FORCED_TXS_PER_FORCED_INCLUSION transactions
Expand All @@ -102,5 +107,7 @@ contract ForcedInclusionInbox is EssentialContract {
inbox.proposeBatch(abi.encode(params), "");
emit ForcedInclusionProcessed(inclusion);
}

(info_, meta_) = inbox.proposeBatch(_params, _txList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.24;
import "src/shared/common/EssentialContract.sol";
import "src/shared/libs/LibStrings.sol";
import "src/layer1/based/TaikoInbox.sol";
import "src/layer1/forced-inclusion/IForcedInclusionInbox.sol";
import "src/layer1/forced-inclusion/TaikoWrapper.sol";
import "../iface/IPreconfRouter.sol";
import "../iface/IPreconfWhitelist.sol";

Expand Down Expand Up @@ -34,14 +34,14 @@ contract PreconfRouter is EssentialContract, IPreconfRouter {
require(msg.sender == selectedOperator, NotTheOperator());

// check if we have a forced inclusion inbox
address forcedInclusionInbox = resolve(LibStrings.B_TAIKO_FORCED_INCLUSION_INBOX, true);
if (forcedInclusionInbox == address(0)) {
address wrapper = resolve(LibStrings.B_TAIKO_WRAPPER, true);
if (wrapper == address(0)) {
// Call the proposeBatch function on the TaikoInbox
address taikoInbox = resolve(LibStrings.B_TAIKO, false);
(, meta_) = ITaikoInbox(taikoInbox).proposeBatch(_batchParams, _batchTxList);
} else {
// Call the proposeBatchWithForcedInclusion function on the ForcedInclusionInbox
(, meta_) = IForcedInclusionInbox(forcedInclusionInbox).proposeBatchWithForcedInclusion(
(, meta_) = TaikoWrapper(wrapper).proposeBatchWithForcedInclusion(
_forcedInclusionParams, _batchParams, _batchTxList
);
}
Expand Down
3 changes: 1 addition & 2 deletions packages/protocol/contracts/shared/libs/LibStrings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ library LibStrings {
bytes32 internal constant B_SGX_WATCHDOG = bytes32("sgx_watchdog");
bytes32 internal constant B_SIGNAL_SERVICE = bytes32("signal_service");
bytes32 internal constant B_TAIKO = bytes32("taiko");
bytes32 internal constant B_TAIKO_FORCED_INCLUSION_INBOX =
bytes32("taiko_forced_inclusion_inbox");
bytes32 internal constant B_TAIKO_TOKEN = bytes32("taiko_token");
bytes32 internal constant B_TAIKO_WRAPPER = bytes32("taiko_wrapper");
bytes32 internal constant B_WITHDRAWER = bytes32("withdrawer");
bytes32 internal constant H_SIGNAL_ROOT = keccak256("SIGNAL_ROOT");
bytes32 internal constant H_STATE_ROOT = keccak256("STATE_ROOT");
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/script/gen-layouts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ contracts_layer1=(
"contracts/layer1/team/TokenUnlock.sol:TokenUnlock"
"contracts/layer1/provers/ProverSet.sol:ProverSet"
"contracts/layer1/based/ForkRouter.sol:ForkRouter"
"contracts/layer1/forced-inclusion/ForcedInclusionInbox"
"contracts/layer1/forced-inclusion/TaikoWrapper"
"contracts/layer1/forced-inclusion/ForcedInclusionStore"
)

Expand Down
10 changes: 5 additions & 5 deletions packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import "src/layer1/devnet/verifiers/DevnetVerifier.sol";
import "src/layer1/mainnet/MainnetInbox.sol";
import "src/layer1/based/TaikoInbox.sol";
import "src/layer1/fork-router/ForkRouter.sol";
import "src/layer1/forced-inclusion/ForcedInclusionInbox.sol";
import "src/layer1/forced-inclusion/TaikoWrapper.sol";
import "src/layer1/forced-inclusion/ForcedInclusionStore.sol";
import "src/layer1/mainnet/multirollup/MainnetBridge.sol";
import "src/layer1/mainnet/multirollup/MainnetERC1155Vault.sol";
Expand Down Expand Up @@ -413,7 +413,7 @@ contract DeployProtocolOnL1 is DeployCapability {
impl: address(
new ForcedInclusionStore(
resolver,
vm.envUint("INCLUSION_WINDOW"),
uint8(vm.envUint("INCLUSION_WINDOW")),
uint64(vm.envUint("INCLUSION_FEE_IN_GWEI"))
)
),
Expand All @@ -422,9 +422,9 @@ contract DeployProtocolOnL1 is DeployCapability {
});

forcedInclusionInbox = deployProxy({
name: "taiko_forced_inclusion_inbox",
impl: address(new ForcedInclusionInbox(resolver)),
data: abi.encodeCall(ForcedInclusionInbox.init, (owner)),
name: "taiko_wrapper",
impl: address(new TaikoWrapper(resolver)),
data: abi.encodeCall(TaikoWrapper.init, (owner)),
registerTo: resolver
});

Expand Down
14 changes: 7 additions & 7 deletions packages/protocol/test/layer1/Layer1Test.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.24;

import "src/layer1/based/TaikoInbox.sol";
import "src/layer1/forced-inclusion/ForcedInclusionInbox.sol";
import "src/layer1/forced-inclusion/TaikoWrapper.sol";
import "src/layer1/forced-inclusion/ForcedInclusionStore.sol";
import "src/layer1/token/TaikoToken.sol";
import "src/layer1/verifiers/SgxVerifier.sol";
Expand Down Expand Up @@ -66,18 +66,18 @@ abstract contract Layer1Test is CommonTest {
);
}

function deployForcedInclusionInbox() internal returns (ForcedInclusionInbox) {
return ForcedInclusionInbox(
function deployForcedInclusionInbox() internal returns (TaikoWrapper) {
return TaikoWrapper(
deploy({
name: "taiko_forced_inclusion_inbox",
impl: address(new ForcedInclusionInbox(address(resolver))),
data: abi.encodeCall(ForcedInclusionInbox.init, (address(0)))
name: "taiko_wrapper",
impl: address(new TaikoWrapper(address(resolver))),
data: abi.encodeCall(TaikoWrapper.init, (address(0)))
})
);
}

function deployForcedInclusionStore(
uint256 inclusionDelay,
uint8 inclusionDelay,
uint64 feeInGwei,
address owner
)
Expand Down
Loading

0 comments on commit 9e4f417

Please sign in to comment.