Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(protocol): multiple improvements on implementation and tests #18483

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/guardian-prover-health-check-ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ jobs:
# vercel_org_id: ${{ secrets.VERCEL_ORG_ID }}
# vercel_token: ${{ secrets.VERCEL_TOKEN }}



deploy_guardians-ui_hekla_preview:
if: ${{ github.event.pull_request.draft == false && !startsWith(github.head_ref, 'release-please') }}
needs: build-and-test
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ on:
- "!packages/protocol/docs/**"
- "!packages/protocol/simulation/**"
- "!packages/protocol/deployments/**"
- "!packages/protocol/script/layer2/hekla/**"
- "!packages/protocol/script/layer2/mainnet/**"
- "!packages/protocol/script/layer1/hekla/**"
- "!packages/protocol/script/layer1/mainnet/**"
- "!packages/protocol/script/layer1/preconf/**"
- "!packages/protocol/script/layer1/provers/**"
- "!packages/protocol/script/layer1/team/**"
branches-ignore:
- release-please--branches--**

Expand Down
1,572 changes: 622 additions & 950 deletions packages/protocol/contract_layout_layer1.md

Large diffs are not rendered by default.

806 changes: 407 additions & 399 deletions packages/protocol/contract_layout_layer2.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ contract AutomataDcapV3Attestation is IAttestation, EssentialContract {
for (uint256 i; i < 3; ++i) {
bool isPckCert = i == 0; // additional parsing for PCKCert
bool certDecodedSuccessfully;
// todo! move decodeCert offchain
// TODO(Yue): move decodeCert offchain
(certDecodedSuccessfully, parsedQuoteCerts[i]) = pemCertLib.decodeCert(
authDataV3.certification.decodedCertDataArray[i], isPckCert
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ library V3Struct {

struct CertificationData {
uint16 certType;
// todo! In encoded path, we need to calculate the size of certDataArray
// TODO(Yue): In encoded path, we need to calculate the size of certDataArray
// certDataSize = len(join((BEGIN_CERT, certArray[i], END_CERT) for i in 0..3))
// But for plain bytes path, we don't need that.
uint32 certDataSize;
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/contracts/layer1/based/ITaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,5 @@ interface ITaikoL1 {

/// @notice Gets the configuration of the TaikoL1 contract.
/// @return Config struct containing configuration parameters.
function getConfig() external pure returns (TaikoData.Config memory);
function getConfig() external view returns (TaikoData.Config memory);
}
18 changes: 9 additions & 9 deletions packages/protocol/contracts/layer1/based/LibBonds.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "src/shared/common/IAddressResolver.sol";
import "src/shared/common/LibAddress.sol";
import "src/shared/common/LibStrings.sol";
import "src/shared/common/IResolver.sol";
import "src/shared/libs/LibAddress.sol";
import "src/shared/libs/LibStrings.sol";
import "./TaikoData.sol";

/// @title LibBonds
Expand Down Expand Up @@ -43,7 +43,7 @@ library LibBonds {
/// @param _amount The amount of tokens to deposit.
function depositBond(
TaikoData.State storage _state,
IAddressResolver _resolver,
IResolver _resolver,
uint256 _amount
)
public
Expand All @@ -58,7 +58,7 @@ library LibBonds {
/// @param _amount The amount of tokens to withdraw.
function withdrawBond(
TaikoData.State storage _state,
IAddressResolver _resolver,
IResolver _resolver,
uint256 _amount
)
public
Expand Down Expand Up @@ -97,7 +97,7 @@ library LibBonds {
/// @param _amount The amount of tokens to debit.
function debitBond(
TaikoData.State storage _state,
IAddressResolver _resolver,
IResolver _resolver,
address _user,
uint256 _blockId,
uint256 _amount
Expand Down Expand Up @@ -142,7 +142,7 @@ library LibBonds {
/// @param _resolver The address resolver.
/// @param _user The user who made the deposit
/// @param _amount The amount of tokens or Ether to deposit.
function _handleDeposit(IAddressResolver _resolver, address _user, uint256 _amount) private {
function _handleDeposit(IResolver _resolver, address _user, uint256 _amount) private {
address bondToken = _bondToken(_resolver);

if (bondToken != address(0)) {
Expand All @@ -158,7 +158,7 @@ library LibBonds {
/// is used as bond asset.
/// @param _resolver The address resolver.
/// @return The IERC20 interface of the TAIKO token.
function _bondToken(IAddressResolver _resolver) private view returns (address) {
return _resolver.resolve(LibStrings.B_BOND_TOKEN, true);
function _bondToken(IResolver _resolver) private view returns (address) {
return _resolver.resolve(block.chainid, LibStrings.B_BOND_TOKEN, true);
}
}
107 changes: 60 additions & 47 deletions packages/protocol/contracts/layer1/based/LibProposing.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "src/shared/common/LibAddress.sol";
import "src/shared/common/LibNetwork.sol";
import "src/shared/libs/LibAddress.sol";
import "src/shared/libs/LibNetwork.sol";
import "./LibBonds.sol";
import "./LibData.sol";
import "./LibUtils.sol";
Expand All @@ -17,7 +17,6 @@ library LibProposing {
uint256 internal constant SECONDS_PER_BLOCK = 12;

struct Local {
TaikoData.SlotB b;
TaikoData.BlockParamsV2 params;
ITierProvider tierProvider;
bytes32 parentMetaHash;
Expand Down Expand Up @@ -55,7 +54,7 @@ library LibProposing {
function proposeBlocks(
TaikoData.State storage _state,
TaikoData.Config memory _config,
IAddressResolver _resolver,
IResolver _resolver,
bytes[] calldata _paramsArr,
bytes[] calldata _txListArr
)
Expand All @@ -67,12 +66,14 @@ library LibProposing {
}

metas_ = new TaikoData.BlockMetadataV2[](_paramsArr.length);
TaikoData.SlotB memory slotB;

for (uint256 i; i < _paramsArr.length; ++i) {
metas_[i] = _proposeBlock(_state, _config, _resolver, _paramsArr[i], _txListArr[i]);
(metas_[i], slotB) =
_proposeBlock(_state, _config, _resolver, _paramsArr[i], _txListArr[i]);
}

if (!_state.slotB.provingPaused) {
if (!slotB.provingPaused) {
for (uint256 i; i < _paramsArr.length; ++i) {
if (LibUtils.shouldVerifyBlocks(_config, metas_[i].id, false)) {
LibVerifying.verifyBlocks(_state, _config, _resolver, _config.maxBlocksToVerify);
Expand All @@ -91,16 +92,17 @@ library LibProposing {
function proposeBlock(
TaikoData.State storage _state,
TaikoData.Config memory _config,
IAddressResolver _resolver,
IResolver _resolver,
bytes calldata _params,
bytes calldata _txList
)
internal
returns (TaikoData.BlockMetadataV2 memory meta_)
{
meta_ = _proposeBlock(_state, _config, _resolver, _params, _txList);
TaikoData.SlotB memory slotB;
(meta_, slotB) = _proposeBlock(_state, _config, _resolver, _params, _txList);

if (!_state.slotB.provingPaused) {
if (!slotB.provingPaused) {
if (LibUtils.shouldVerifyBlocks(_config, meta_.id, false)) {
LibVerifying.verifyBlocks(_state, _config, _resolver, _config.maxBlocksToVerify);
}
Expand All @@ -117,29 +119,33 @@ library LibProposing {
function _proposeBlock(
TaikoData.State storage _state,
TaikoData.Config memory _config,
IAddressResolver _resolver,
IResolver _resolver,
bytes calldata _params,
bytes calldata _txList
)
private
returns (TaikoData.BlockMetadataV2 memory meta_)
returns (TaikoData.BlockMetadataV2 memory meta_, TaikoData.SlotB memory slotB)
{
// Checks proposer access.
Local memory local;
local.b = _state.slotB;
// SLOAD #1 {{
slotB = _state.slotB;
// SLOAD #1 }}

// It's essential to ensure that the ring buffer for proposed blocks still has space for at
// least one more block.
require(local.b.numBlocks >= _config.ontakeForkHeight, L1_FORK_HEIGHT_ERROR());
require(slotB.numBlocks >= _config.ontakeForkHeight, L1_FORK_HEIGHT_ERROR());

unchecked {
require(
local.b.numBlocks < local.b.lastVerifiedBlockId + _config.blockMaxProposals + 1,
slotB.numBlocks < slotB.lastVerifiedBlockId + _config.blockMaxProposals + 1,
L1_TOO_MANY_BLOCKS()
);
}

address preconfTaskManager = _resolver.resolve(LibStrings.B_PRECONF_TASK_MANAGER, true);
address preconfTaskManager =
_resolver.resolve(block.chainid, LibStrings.B_PRECONF_TASK_MANAGER, true);

Local memory local;

if (preconfTaskManager != address(0)) {
require(preconfTaskManager == msg.sender, L1_INVALID_PROPOSER());
local.allowCustomProposer = true;
Expand All @@ -149,22 +155,22 @@ library LibProposing {
local.params = abi.decode(_params, (TaikoData.BlockParamsV2));
}

_validateParams(_state, _config, local);
_validateParams(_state, _config, slotB, local);

// Initialize metadata to compute a metaHash, which forms a part of the block data to be
// stored on-chain for future integrity checks. If we choose to persist all data fields in
// the metadata, it will require additional storage slots.
meta_ = TaikoData.BlockMetadataV2({
anchorBlockHash: blockhash(local.params.anchorBlockId),
difficulty: keccak256(abi.encode("TAIKO_DIFFICULTY", local.b.numBlocks)),
difficulty: keccak256(abi.encode("TAIKO_DIFFICULTY", slotB.numBlocks)),
blobHash: 0, // to be initialized below
// Encode _config.baseFeeConfig into extraData to allow L2 block execution without
// metadata. Metadata might be unavailable until the block is proposed on-chain. In
// preconfirmation scenarios, multiple blocks may be built but not yet proposed, making
// metadata unavailable.
extraData: _encodeBaseFeeConfig(_config.baseFeeConfig),
extraData: _encodeBaseFeeConfig(_config.baseFeeConfig), // TODO(daniel):remove outside and compute only once.
coinbase: local.params.coinbase,
id: local.b.numBlocks,
id: slotB.numBlocks,
gasLimit: _config.blockMaxGasLimit,
timestamp: local.params.timestamp,
anchorBlockId: local.params.anchorBlockId,
Expand All @@ -191,50 +197,57 @@ library LibProposing {
emit CalldataTxList(meta_.id, _txList);
}

local.tierProvider = ITierProvider(
ITierRouter(_resolver.resolve(LibStrings.B_TIER_ROUTER, false)).getProvider(
local.b.numBlocks
)
);
local.tierProvider =
ITierProvider(_resolver.resolve(block.chainid, LibStrings.B_TIER_PROVIDER, false));

// Use the difficulty as a random number
meta_.minTier = local.tierProvider.getMinTier(meta_.proposer, uint256(meta_.difficulty));

// Create the block that will be stored onchain
TaikoData.BlockV2 memory blk = TaikoData.BlockV2({
metaHash: keccak256(abi.encode(meta_)),
assignedProver: address(0),
livenessBond: 0,
blockId: local.b.numBlocks,
proposedAt: local.params.timestamp, // = params.timestamp post Ontake
proposedIn: local.params.anchorBlockId, // = params.anchorBlockId post Ontake
nextTransitionId: 1, // For a new block, the next transition ID is always 1, not 0.
livenessBondReturned: false,
// For unverified block, its verifiedTransitionId is always 0.
verifiedTransitionId: 0
});
meta_.minTier = local.tierProvider.getMinTier(
slotB.numBlocks, meta_.proposer, uint256(meta_.difficulty)
);

// Use a storage pointer for the block in the ring buffer
TaikoData.BlockV2 storage blk = _state.blocks[slotB.numBlocks % _config.blockRingBufferSize];

// Store the block in the ring buffer
_state.blocks[local.b.numBlocks % _config.blockRingBufferSize] = blk;
// Store each field of the block separately
// SSTORE #1 {{
blk.metaHash = keccak256(abi.encode(meta_));
// SSTORE #1 }}

// SSTORE #2 {{
blk.blockId = slotB.numBlocks;
blk.proposedAt = local.params.timestamp;
blk.proposedIn = local.params.anchorBlockId;
blk.nextTransitionId = 1;
blk.livenessBondReturned = false;
blk.verifiedTransitionId = 0;
// SSTORE #2 }}

// Increment the counter (cursor) by 1.
unchecked {
++_state.slotB.numBlocks;
// Increment the counter (cursor) by 1.
slotB.numBlocks += 1;
slotB.lastProposedIn = uint56(block.number);

// SSTORE #3 {{
_state.slotB = slotB; // TODO(daniel): save this only once.
// SSTORE #3 }}
}
_state.slotB.lastProposedIn = uint56(block.number);

// SSTORE #4 {{
LibBonds.debitBond(_state, _resolver, local.params.proposer, meta_.id, _config.livenessBond);
// SSTORE #4 }}

emit BlockProposedV2(meta_.id, meta_);
}

/// @dev Validates the parameters for proposing a block.
/// @param _state Pointer to the protocol's storage.
/// @param _config The configuration parameters for the Taiko protocol.
/// @param _slotB The SlotB struct.
/// @param _local The local struct.
function _validateParams(
TaikoData.State storage _state,
TaikoData.Config memory _config,
TaikoData.SlotB memory _slotB,
Local memory _local
)
private
Expand Down Expand Up @@ -266,7 +279,7 @@ library LibProposing {
// Verify params against the parent block.
TaikoData.BlockV2 storage parentBlk;
unchecked {
parentBlk = _state.blocks[(_local.b.numBlocks - 1) % _config.blockRingBufferSize];
parentBlk = _state.blocks[(_slotB.numBlocks - 1) % _config.blockRingBufferSize];
}

// Verify the passed in L1 state block number to anchor.
Expand Down
Loading
Loading