Skip to content

Commit

Permalink
refactor(protocol): optimize storage reads/writes in proveBlock (#17532)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Wang <[email protected]>
Co-authored-by: D <[email protected]>
  • Loading branch information
3 people authored Jun 12, 2024
1 parent 7fa3b55 commit ba5c25b
Show file tree
Hide file tree
Showing 8 changed files with 13 additions and 56 deletions.
3 changes: 1 addition & 2 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ library TaikoData {
}

/// @dev Struct representing state transition data.
/// 10 slots reserved for upgradability, 6 slots used.
/// 6 slots used.
struct TransitionState {
bytes32 key; // slot 1, only written/read for the 1st state transition.
bytes32 blockHash; // slot 2
Expand All @@ -106,7 +106,6 @@ library TaikoData {
uint96 contestBond;
uint64 timestamp; // slot 6 (90 bits)
uint16 tier;
uint8 __reserved1;
}

/// @dev Struct containing data required for verifying a block.
Expand Down
35 changes: 12 additions & 23 deletions packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ library LibProving {
ITierProvider.Tier minTier;
bytes32 metaHash;
address assignedProver;
uint96 livenessBond;
uint64 slot;
uint64 blockId;
uint32 tid;
Expand Down Expand Up @@ -125,6 +126,7 @@ library LibProving {

local.blockId = blk.blockId;
local.assignedProver = blk.assignedProver;
local.livenessBond = blk.livenessBond;
local.metaHash = blk.metaHash;

// Check the integrity of the block data. It's worth noting that in
Expand All @@ -138,7 +140,7 @@ library LibProving {
// blockHash and stateRoot open for later updates as higher-tier proofs
// become available. In cases where a transition with the specified
// parentHash does not exist, the transition ID (tid) will be set to 0.
TaikoData.TransitionState storage ts;
TaikoData.TransitionState memory ts;
(local.tid, ts) = _fetchOrCreateTransition(_state, blk, _tran, local);

// The new proof must meet or exceed the minimum tier required by the
Expand Down Expand Up @@ -279,6 +281,8 @@ library LibProving {
}

ts.timestamp = uint64(block.timestamp);
_state.transitions[local.slot][local.tid] = ts;

return local.tier.maxBlocksToVerifyPerProof;
}

Expand All @@ -290,7 +294,7 @@ library LibProving {
Local memory _local
)
private
returns (uint32 tid_, TaikoData.TransitionState storage ts_)
returns (uint32 tid_, TaikoData.TransitionState memory ts_)
{
tid_ = LibUtils.getTransitionId(_state, _blk, _local.slot, _tran.parentHash);

Expand All @@ -313,15 +317,7 @@ library LibProving {
// Keep in mind that state.transitions are also reusable storage
// slots, so it's necessary to reinitialize all transition fields
// below.
ts_ = _state.transitions[_local.slot][tid_];
ts_.blockHash = 0;
ts_.stateRoot = 0;
ts_.validityBond = 0;
ts_.contester = address(0);
ts_.contestBond = 1; // to save gas
ts_.timestamp = _blk.proposedAt;
ts_.tier = 0;
ts_.__reserved1 = 0;

if (tid_ == 1) {
// This approach serves as a cost-saving technique for the
Expand All @@ -343,19 +339,14 @@ library LibProving {
// such changes would require additional if-else logic.
ts_.prover = _local.assignedProver;
} else {
// In scenarios where this transition is not the first one, we
// straightforwardly reset the transition prover to address
// zero.
ts_.prover = address(0);

// Furthermore, we index the transition for future retrieval.
// It's worth emphasizing that this mapping for indexing is not
// reusable. However, given that the majority of blocks will
// only possess one transition — the correct one — we don't need
// to be concerned about the cost in this case.
_state.transitionIds[_local.blockId][_tran.parentHash] = tid_;

// There is no need to initialize ts.key here because it's only used when tid == 1
_state.transitionIds[_local.blockId][_tran.parentHash] = tid_;
}
} else {
// A transition with the provided parentHash has been located.
Expand All @@ -376,7 +367,7 @@ library LibProving {
// 6.5625.
function _overrideWithHigherProof(
TaikoData.Block storage _blk,
TaikoData.TransitionState storage _ts,
TaikoData.TransitionState memory _ts,
TaikoData.Transition memory _tran,
TaikoData.TierProof memory _proof,
Local memory _local,
Expand Down Expand Up @@ -411,17 +402,16 @@ library LibProving {
// - 2) the transition is contested.
reward = _rewardAfterFriction(_ts.validityBond);

uint256 livenessBond = _blk.livenessBond;
if (livenessBond != 0) {
if (_local.livenessBond != 0) {
// After the first proof, the block's liveness bond will always be reset to 0.
// This means liveness bond will be handled only once for any given block.
_blk.livenessBond = 0;

if (_returnLivenessBond(_local, _proof.data)) {
if (_blk.assignedProver == msg.sender) {
reward += livenessBond;
if (_local.assignedProver == msg.sender) {
reward += _local.livenessBond;
} else {
_tko.transfer(_blk.assignedProver, livenessBond);
_tko.transfer(_local.assignedProver, _local.livenessBond);
}
}
}
Expand All @@ -436,7 +426,6 @@ library LibProving {
}

_ts.validityBond = _local.tier.validityBond;
_ts.contestBond = 1; // to save gas
_ts.contester = address(0);
_ts.prover = msg.sender;
_ts.tier = _proof.tier;
Expand Down
9 changes: 0 additions & 9 deletions packages/protocol/test/L1/TaikoL1TestGroup1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_OPTIMISTIC);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Bob);
assertEq(ts.validityBond, tierOp.validityBond);
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -105,7 +104,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_OPTIMISTIC);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Bob);
assertEq(ts.validityBond, tierOp.validityBond);
assertEq(ts.timestamp, provenAt);
Expand Down Expand Up @@ -175,7 +173,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_OPTIMISTIC);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Taylor);
assertEq(ts.validityBond, tierOp.validityBond);
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -204,7 +201,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_OPTIMISTIC);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Taylor);
assertEq(ts.validityBond, tierOp.validityBond);
assertEq(ts.timestamp, provenAt);
Expand Down Expand Up @@ -258,7 +254,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {

TaikoData.TransitionState memory ts = L1.getTransition(meta.id, 2);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Taylor);
assertEq(ts.validityBond, tierOp.validityBond);

Expand Down Expand Up @@ -311,7 +306,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {

TaikoData.TransitionState memory ts = L1.getTransition(meta.id, 1);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Bob);
assertEq(ts.validityBond, tierOp.validityBond);

Expand Down Expand Up @@ -365,7 +359,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {

TaikoData.TransitionState memory ts = L1.getTransition(meta.id, 2);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Taylor);
assertEq(ts.validityBond, tierOp.validityBond);

Expand Down Expand Up @@ -435,7 +428,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_OPTIMISTIC);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Bob);
assertEq(ts.validityBond, tierOp.validityBond);
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -463,7 +455,6 @@ contract TaikoL1TestGroup1 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_OPTIMISTIC);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.prover, Bob);
assertEq(ts.validityBond, tierOp.validityBond);
assertEq(ts.timestamp, provenAt);
Expand Down
4 changes: 0 additions & 4 deletions packages/protocol/test/L1/TaikoL1TestGroup2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ contract TaikoL1TestGroup2 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, William);
assertEq(ts.timestamp, block.timestamp); // not zero
Expand Down Expand Up @@ -108,7 +107,6 @@ contract TaikoL1TestGroup2 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash);
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, William);

assertEq(tko.balanceOf(William), 10_000 ether + tierOp.contestBond * 7 / 8);
Expand Down Expand Up @@ -189,7 +187,6 @@ contract TaikoL1TestGroup2 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, William);
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -218,7 +215,6 @@ contract TaikoL1TestGroup2 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, William);

Expand Down
4 changes: 0 additions & 4 deletions packages/protocol/test/L1/TaikoL1TestGroup3.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ contract TaikoL1TestGroup3 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, William);
assertEq(ts.timestamp, block.timestamp); // not zero
Expand Down Expand Up @@ -112,7 +111,6 @@ contract TaikoL1TestGroup3 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash);
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, William);

assertEq(tko.balanceOf(William), 10_000 ether + tierOp.contestBond * 7 / 8);
Expand Down Expand Up @@ -197,7 +195,6 @@ contract TaikoL1TestGroup3 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, William);
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -227,7 +224,6 @@ contract TaikoL1TestGroup3 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, William);

Expand Down
4 changes: 0 additions & 4 deletions packages/protocol/test/L1/TaikoL1TestGroup4.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ contract TaikoL1TestGroup4 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1);
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, Taylor);
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -79,7 +78,6 @@ contract TaikoL1TestGroup4 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash2);
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, Taylor);

assertEq(tko.balanceOf(Taylor), 10_000 ether + tierOp.validityBond * 7 / 8);
Expand Down Expand Up @@ -135,7 +133,6 @@ contract TaikoL1TestGroup4 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1);
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, Taylor);
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -165,7 +162,6 @@ contract TaikoL1TestGroup4 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash2);
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, Taylor);

assertEq(tko.balanceOf(Taylor), 10_000 ether + tierOp.validityBond * 7 / 8);
Expand Down
8 changes: 0 additions & 8 deletions packages/protocol/test/L1/TaikoL1TestGroup5.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1);
assertEq(ts.validityBond, 0);
assertEq(ts.prover, address(gp));
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -83,7 +82,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1);
assertEq(ts.validityBond, 0);
assertEq(ts.prover, address(gp));
assertEq(ts.timestamp, block.timestamp);
Expand Down Expand Up @@ -121,7 +119,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash2);
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, address(gp));

assertEq(tko.balanceOf(Bob), 10_000 ether);
Expand Down Expand Up @@ -186,7 +183,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1);
assertEq(ts.validityBond, 0);
assertEq(ts.prover, address(gp));
assertEq(ts.timestamp, block.timestamp);
Expand All @@ -212,7 +208,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash2);
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, address(gp));

assertEq(tko.balanceOf(Bob), 10_000 ether - tierOp.validityBond);
Expand Down Expand Up @@ -280,7 +275,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1);
assertEq(ts.validityBond, 0);
assertEq(ts.prover, address(gp));
assertEq(ts.timestamp, block.timestamp);
Expand All @@ -307,7 +301,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash2);
assertEq(ts.stateRoot, stateRoot2);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, address(gp));

assertEq(tko.balanceOf(Bob), 10_000 ether - livenessBond);
Expand Down Expand Up @@ -351,7 +344,6 @@ contract TaikoL1TestGroup5 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_GUARDIAN);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1);
assertEq(ts.validityBond, 0);
assertEq(ts.prover, address(gp));
assertEq(ts.timestamp, block.timestamp);
Expand Down
2 changes: 0 additions & 2 deletions packages/protocol/test/L1/TaikoL1TestGroup6.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ contract TaikoL1TestGroup6 is TaikoL1TestGroupBase {
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contester, address(0));
assertEq(ts.contestBond, 1); // not zero
assertEq(ts.validityBond, tierSgx.validityBond);
assertEq(ts.prover, Bob);
assertEq(ts.timestamp, block.timestamp); // not zero
Expand Down Expand Up @@ -82,7 +81,6 @@ contract TaikoL1TestGroup6 is TaikoL1TestGroupBase {
assertEq(ts.blockHash, blockHash);
assertEq(ts.stateRoot, stateRoot);
assertEq(ts.tier, LibTiers.TIER_SGX);
assertEq(ts.contestBond, 1);
assertEq(ts.prover, Bob);

assertEq(tko.balanceOf(Taylor), 10_000 ether - tierOp.contestBond);
Expand Down

0 comments on commit ba5c25b

Please sign in to comment.