From 3f8f5d1f8bac098cff4cf684f7c943cc1ca88856 Mon Sep 17 00:00:00 2001 From: Mitch Date: Tue, 17 Sep 2024 15:55:34 -0400 Subject: [PATCH 1/7] define escrow contract interface implement mock escrow and include in rollup move signature lib --- l1-contracts/src/core/Rollup.sol | 6 +++- .../interfaces/IProofCommitmentEscrow.sol | 13 +++++++++ l1-contracts/src/core/interfaces/IRollup.sol | 2 +- .../src/core/libraries/DataStructures.sol | 11 +++++++ .../SignatureLib.sol | 4 ++- .../src/core/sequencer_selection/Leonidas.sol | 2 +- .../src/mock/MockProofCommitmentEscrow.sol | 29 +++++++++++++++++++ l1-contracts/test/Rollup.t.sol | 2 +- l1-contracts/test/sparta/Sparta.t.sol | 2 +- 9 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol rename l1-contracts/src/core/{sequencer_selection => libraries}/SignatureLib.sol (88%) create mode 100644 l1-contracts/src/mock/MockProofCommitmentEscrow.sol diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 283aafc4828..e7e025a12ac 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.18; // Interfaces import {IRollup, ITestRollup} from "./interfaces/IRollup.sol"; +import {IProofCommitmentEscrow} from "./interfaces/IProofCommitmentEscrow.sol"; import {IInbox} from "./interfaces/messagebridge/IInbox.sol"; import {IOutbox} from "./interfaces/messagebridge/IOutbox.sol"; import {IRegistry} from "./interfaces/messagebridge/IRegistry.sol"; @@ -15,13 +16,14 @@ import {HeaderLib} from "./libraries/HeaderLib.sol"; import {Errors} from "./libraries/Errors.sol"; import {Constants} from "./libraries/ConstantsGen.sol"; import {MerkleLib} from "./libraries/MerkleLib.sol"; -import {SignatureLib} from "./sequencer_selection/SignatureLib.sol"; +import {SignatureLib} from "./libraries/SignatureLib.sol"; import {SafeCast} from "@oz/utils/math/SafeCast.sol"; import {DataStructures} from "./libraries/DataStructures.sol"; import {TxsDecoder} from "./libraries/decoders/TxsDecoder.sol"; // Contracts import {MockVerifier} from "../mock/MockVerifier.sol"; +import {MockProofCommitmentEscrow} from "../mock/MockProofCommitmentEscrow.sol"; import {Inbox} from "./messagebridge/Inbox.sol"; import {Outbox} from "./messagebridge/Outbox.sol"; import {Leonidas} from "./sequencer_selection/Leonidas.sol"; @@ -55,6 +57,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { IRegistry public immutable REGISTRY; IInbox public immutable INBOX; IOutbox public immutable OUTBOX; + IProofCommitmentEscrow public immutable PROOF_COMMITMENT_ESCROW; uint256 public immutable VERSION; IFeeJuicePortal public immutable FEE_JUICE_PORTAL; IVerifier public verifier; @@ -84,6 +87,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { verifier = new MockVerifier(); REGISTRY = _registry; FEE_JUICE_PORTAL = _fpcJuicePortal; + PROOF_COMMITMENT_ESCROW = new MockProofCommitmentEscrow(); INBOX = new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT); OUTBOX = new Outbox(address(this)); vkTreeRoot = _vkTreeRoot; diff --git a/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol b/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol new file mode 100644 index 00000000000..8ef52a2e670 --- /dev/null +++ b/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {DataStructures} from "../libraries/DataStructures.sol"; + +interface IProofCommitmentEscrow { + function deposit(uint256 _amount) external; + function withdraw(uint256 _amount) external; + // returns the address of the bond provider + function stakeBond(DataStructures.EpochProofQuote calldata _quote) external returns (address); + function unstakeBond(uint256 _amount) external; +} diff --git a/l1-contracts/src/core/interfaces/IRollup.sol b/l1-contracts/src/core/interfaces/IRollup.sol index 1f02808bf96..4fe5e30dab2 100644 --- a/l1-contracts/src/core/interfaces/IRollup.sol +++ b/l1-contracts/src/core/interfaces/IRollup.sol @@ -5,7 +5,7 @@ pragma solidity >=0.8.18; import {IInbox} from "../interfaces/messagebridge/IInbox.sol"; import {IOutbox} from "../interfaces/messagebridge/IOutbox.sol"; -import {SignatureLib} from "../sequencer_selection/SignatureLib.sol"; +import {SignatureLib} from "../libraries/SignatureLib.sol"; import {DataStructures} from "../libraries/DataStructures.sol"; interface ITestRollup { diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index 5462e09fa1b..2b6438c3702 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -2,6 +2,8 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; +import {SignatureLib} from "./SignatureLib.sol"; + /** * @title Data Structures Library * @author Aztec Labs @@ -79,4 +81,13 @@ library DataStructures { bool ignoreDA; bool ignoreSignatures; } + + struct EpochProofQuote { + SignatureLib.Signature signature; + uint256 epochToProve; + uint256 validUntilSlot; + uint256 bondAmount; + address rollup; + uint32 basisPointFee; + } } diff --git a/l1-contracts/src/core/sequencer_selection/SignatureLib.sol b/l1-contracts/src/core/libraries/SignatureLib.sol similarity index 88% rename from l1-contracts/src/core/sequencer_selection/SignatureLib.sol rename to l1-contracts/src/core/libraries/SignatureLib.sol index 434e6945c3f..1bb8d6fb050 100644 --- a/l1-contracts/src/core/sequencer_selection/SignatureLib.sol +++ b/l1-contracts/src/core/libraries/SignatureLib.sol @@ -1,6 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. pragma solidity ^0.8.13; -import {Errors} from "../libraries/Errors.sol"; +import {Errors} from "./Errors.sol"; library SignatureLib { struct Signature { diff --git a/l1-contracts/src/core/sequencer_selection/Leonidas.sol b/l1-contracts/src/core/sequencer_selection/Leonidas.sol index 48cbaef0579..57438f6860a 100644 --- a/l1-contracts/src/core/sequencer_selection/Leonidas.sol +++ b/l1-contracts/src/core/sequencer_selection/Leonidas.sol @@ -6,8 +6,8 @@ import {DataStructures} from "../libraries/DataStructures.sol"; import {Errors} from "../libraries/Errors.sol"; import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol"; import {Ownable} from "@oz/access/Ownable.sol"; -import {SignatureLib} from "./SignatureLib.sol"; import {SampleLib} from "./SampleLib.sol"; +import {SignatureLib} from "../libraries/SignatureLib.sol"; import {Constants} from "../libraries/ConstantsGen.sol"; import {MessageHashUtils} from "@oz/utils/cryptography/MessageHashUtils.sol"; diff --git a/l1-contracts/src/mock/MockProofCommitmentEscrow.sol b/l1-contracts/src/mock/MockProofCommitmentEscrow.sol new file mode 100644 index 00000000000..d7bc1d847e4 --- /dev/null +++ b/l1-contracts/src/mock/MockProofCommitmentEscrow.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {DataStructures} from "../core/libraries/DataStructures.sol"; +import {IProofCommitmentEscrow} from "../core/interfaces/IProofCommitmentEscrow.sol"; + +contract MockProofCommitmentEscrow is IProofCommitmentEscrow { + function deposit(uint256 _amount) external override { + // do nothing + } + + function withdraw(uint256 _amount) external override { + // do nothing + } + + function unstakeBond(uint256 _amount) external override { + // do nothing + } + + function stakeBond(DataStructures.EpochProofQuote calldata) + external + pure + override + returns (address) + { + return address(0); + } +} diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 807d4563b05..084870f412d 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -6,6 +6,7 @@ import {DecoderBase} from "./decoders/Base.sol"; import {DataStructures} from "../src/core/libraries/DataStructures.sol"; import {Constants} from "../src/core/libraries/ConstantsGen.sol"; +import {SignatureLib} from "../src/core/libraries/SignatureLib.sol"; import {Registry} from "../src/core/messagebridge/Registry.sol"; import {Inbox} from "../src/core/messagebridge/Inbox.sol"; @@ -15,7 +16,6 @@ import {Rollup} from "../src/core/Rollup.sol"; import {IFeeJuicePortal} from "../src/core/interfaces/IFeeJuicePortal.sol"; import {FeeJuicePortal} from "../src/core/FeeJuicePortal.sol"; import {Leonidas} from "../src/core/sequencer_selection/Leonidas.sol"; -import {SignatureLib} from "../src/core/sequencer_selection/SignatureLib.sol"; import {NaiveMerkle} from "./merkle/Naive.sol"; import {MerkleTestUtil} from "./merkle/TestUtil.sol"; import {PortalERC20} from "./portals/PortalERC20.sol"; diff --git a/l1-contracts/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index 3454245ffbf..9a8e84d143b 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -6,7 +6,7 @@ import {DecoderBase} from "../decoders/Base.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; import {Constants} from "../../src/core/libraries/ConstantsGen.sol"; -import {SignatureLib} from "../../src/core/sequencer_selection/SignatureLib.sol"; +import {SignatureLib} from "../../src/core/libraries/SignatureLib.sol"; import {Registry} from "../../src/core/messagebridge/Registry.sol"; import {Inbox} from "../../src/core/messagebridge/Inbox.sol"; From a567dc3b276b1af78cad944ee5fb247ab8a31077 Mon Sep 17 00:00:00 2001 From: Mitch Date: Tue, 17 Sep 2024 19:20:04 -0400 Subject: [PATCH 2/7] prune if needed before propose and prove. --- l1-contracts/src/core/Rollup.sol | 61 ++++--- l1-contracts/src/core/libraries/Errors.sol | 1 - .../core/sequencer_selection/ILeonidas.sol | 3 + .../src/core/sequencer_selection/Leonidas.sol | 160 +++++++++--------- l1-contracts/test/Rollup.t.sol | 10 +- l1-contracts/test/sparta/Sparta.t.sol | 22 +-- 6 files changed, 136 insertions(+), 121 deletions(-) diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index e7e025a12ac..71a7f7f0f2b 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -131,32 +131,13 @@ contract Rollup is Leonidas, IRollup, ITestRollup { * @notice Prune the pending chain up to the last proven block * * @dev Will revert if there is nothing to prune or if the chain is not ready to be pruned - * - * @dev While in devnet, this will be guarded behind an `onlyOwner` */ - function prune() external override(IRollup) onlyOwner { - if (tips.pendingBlockNumber == tips.provenBlockNumber) { + function prune() external override(IRollup) { + if (!_canPrune()) { revert Errors.Rollup__NothingToPrune(); } - BlockLog storage firstPendingNotInProven = blocks[tips.provenBlockNumber + 1]; - uint256 prunableAtSlot = - uint256(firstPendingNotInProven.slotNumber) + TIMELINESS_PROVING_IN_SLOTS; - uint256 currentSlot = getCurrentSlot(); - - if (currentSlot < prunableAtSlot) { - revert Errors.Rollup__NotReadyToPrune(currentSlot, prunableAtSlot); - } - - uint256 pending = tips.pendingBlockNumber; - - // @note We are not deleting the blocks, but we are "winding back" the pendingTip to the last block that was proven. - // We can do because any new block proposed will overwrite a previous block in the block log, - // so no values should "survive". - // People must therefore read the chain using the pendingTip as a boundary. - tips.pendingBlockNumber = tips.provenBlockNumber; - - emit PrunedPending(tips.provenBlockNumber, pending); + _prune(); } /** @@ -214,6 +195,9 @@ contract Rollup is Leonidas, IRollup, ITestRollup { SignatureLib.Signature[] memory _signatures, bytes calldata _body ) external override(IRollup) { + if (_canPrune()) { + _prune(); + } bytes32 txsEffectsHash = TxsDecoder.decode(_body); // Decode and validate header @@ -298,6 +282,9 @@ contract Rollup is Leonidas, IRollup, ITestRollup { bytes calldata _aggregationObject, bytes calldata _proof ) external override(IRollup) { + if (_canPrune()) { + _prune(); + } HeaderLib.Header memory header = HeaderLib.decode(_header); if (header.globalVariables.blockNumber > tips.pendingBlockNumber) { @@ -493,6 +480,36 @@ contract Rollup is Leonidas, IRollup, ITestRollup { return tips.pendingBlockNumber; } + function _prune() internal { + uint256 pending = tips.pendingBlockNumber; + + // @note We are not deleting the blocks, but we are "winding back" the pendingTip to the last block that was proven. + // We can do because any new block proposed will overwrite a previous block in the block log, + // so no values should "survive". + // People must therefore read the chain using the pendingTip as a boundary. + tips.pendingBlockNumber = tips.provenBlockNumber; + + emit PrunedPending(tips.provenBlockNumber, pending); + } + + function _canPrune() internal view returns (bool) { + if (tips.pendingBlockNumber == tips.provenBlockNumber) { + return false; + } + + uint256 currentSlot = getCurrentSlot(); + uint256 oldestPendingEpoch = getEpochAt(blocks[tips.provenBlockNumber + 1].slotNumber); + uint256 startSlotOfPendingEpoch = oldestPendingEpoch * Constants.AZTEC_EPOCH_DURATION; + + // TODO: #8608 adds a proof claim, which will allow us to prune the chain more aggressively. + // That is what will add a `CLAIM_DURATION` to the pruning logic. + if (currentSlot < startSlotOfPendingEpoch + 2 * Constants.AZTEC_EPOCH_DURATION) { + return false; + } + + return true; + } + /** * @notice Get the archive root of a specific block * diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index db826807b5e..fab6b2bac33 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -60,7 +60,6 @@ library Errors { error Rollup__TimestampTooOld(); // 0x72ed9c81 error Rollup__UnavailableTxs(bytes32 txsHash); // 0x414906c3 error Rollup__NothingToPrune(); // 0x850defd3 - error Rollup__NotReadyToPrune(uint256 currentSlot, uint256 prunableAt); // 0x9fdf1614 error Rollup__NonSequentialProving(); // 0x1e5be132 // Registry diff --git a/l1-contracts/src/core/sequencer_selection/ILeonidas.sol b/l1-contracts/src/core/sequencer_selection/ILeonidas.sol index a9542975205..68a58572236 100644 --- a/l1-contracts/src/core/sequencer_selection/ILeonidas.sol +++ b/l1-contracts/src/core/sequencer_selection/ILeonidas.sol @@ -27,4 +27,7 @@ interface ILeonidas { function getCurrentEpochCommittee() external view returns (address[] memory); function getEpochCommittee(uint256 _epoch) external view returns (address[] memory); function getValidators() external view returns (address[] memory); + + function getEpochAt(uint256 _ts) external view returns (uint256); + function getSlotAt(uint256 _ts) external view returns (uint256); } diff --git a/l1-contracts/src/core/sequencer_selection/Leonidas.sol b/l1-contracts/src/core/sequencer_selection/Leonidas.sol index 57438f6860a..1b9484658c6 100644 --- a/l1-contracts/src/core/sequencer_selection/Leonidas.sol +++ b/l1-contracts/src/core/sequencer_selection/Leonidas.sol @@ -128,28 +128,6 @@ contract Leonidas is Ownable, ILeonidas { return epochs[_epoch].committee; } - function getCommitteeAt(uint256 _ts) internal view returns (address[] memory) { - uint256 epochNumber = getEpochAt(_ts); - Epoch storage epoch = epochs[epochNumber]; - - if (epoch.sampleSeed != 0) { - uint256 committeeSize = epoch.committee.length; - if (committeeSize == 0) { - return new address[](0); - } - return epoch.committee; - } - - // Allow anyone if there is no validator set - if (validatorSet.length() == 0) { - return new address[](0); - } - - // Emulate a sampling of the validators - uint256 sampleSeed = _getSampleSeed(epochNumber); - return _sampleValidators(sampleSeed); - } - /** * @notice Get the validator set for the current epoch * @return The validator set for the current epoch @@ -169,6 +147,28 @@ contract Leonidas is Ownable, ILeonidas { return validatorSet.values(); } + /** + * @notice Performs a setup of an epoch if needed. The setup will + * - Sample the validator set for the epoch + * - Set the seed for the epoch + * - Update the last seed + * + * @dev Since this is a reference optimising for simplicity, we store the actual validator set in the epoch structure. + * This is very heavy on gas, so start crying because the gas here will melt the poles + * https://i.giphy.com/U1aN4HTfJ2SmgB2BBK.webp + */ + function setupEpoch() public override(ILeonidas) { + uint256 epochNumber = getCurrentEpoch(); + Epoch storage epoch = epochs[epochNumber]; + + if (epoch.sampleSeed == 0) { + epoch.sampleSeed = _getSampleSeed(epochNumber); + epoch.nextSeed = lastSeed = _computeNextSeed(epochNumber); + + epoch.committee = _sampleValidators(epoch.sampleSeed); + } + } + /** * @notice Get the number of validators in the validator set * @@ -198,28 +198,6 @@ contract Leonidas is Ownable, ILeonidas { return validatorSet.contains(_validator); } - /** - * @notice Performs a setup of an epoch if needed. The setup will - * - Sample the validator set for the epoch - * - Set the seed for the epoch - * - Update the last seed - * - * @dev Since this is a reference optimising for simplicity, we store the actual validator set in the epoch structure. - * This is very heavy on gas, so start crying because the gas here will melt the poles - * https://i.giphy.com/U1aN4HTfJ2SmgB2BBK.webp - */ - function setupEpoch() public override(ILeonidas) { - uint256 epochNumber = getCurrentEpoch(); - Epoch storage epoch = epochs[epochNumber]; - - if (epoch.sampleSeed == 0) { - epoch.sampleSeed = _getSampleSeed(epochNumber); - epoch.nextSeed = lastSeed = _computeNextSeed(epochNumber); - - epoch.committee = _sampleValidators(epoch.sampleSeed); - } - } - /** * @notice Get the current epoch number * @@ -314,6 +292,28 @@ contract Leonidas is Ownable, ILeonidas { return committee[_computeProposerIndex(epochNumber, slot, sampleSeed, committee.length)]; } + /** + * @notice Computes the epoch at a specific time + * + * @param _ts - The timestamp to compute the epoch for + * + * @return The computed epoch + */ + function getEpochAt(uint256 _ts) public view override(ILeonidas) returns (uint256) { + return _ts < GENESIS_TIME ? 0 : (_ts - GENESIS_TIME) / (EPOCH_DURATION * SLOT_DURATION); + } + + /** + * @notice Computes the slot at a specific time + * + * @param _ts - The timestamp to compute the slot for + * + * @return The computed slot + */ + function getSlotAt(uint256 _ts) public view override(ILeonidas) returns (uint256) { + return (_ts - GENESIS_TIME) / SLOT_DURATION; + } + /** * @notice Adds a validator to the set WITHOUT setting up the epoch * @param _validator - The validator to add @@ -322,6 +322,28 @@ contract Leonidas is Ownable, ILeonidas { validatorSet.add(_validator); } + function getCommitteeAt(uint256 _ts) internal view returns (address[] memory) { + uint256 epochNumber = getEpochAt(_ts); + Epoch storage epoch = epochs[epochNumber]; + + if (epoch.sampleSeed != 0) { + uint256 committeeSize = epoch.committee.length; + if (committeeSize == 0) { + return new address[](0); + } + return epoch.committee; + } + + // Allow anyone if there is no validator set + if (validatorSet.length() == 0) { + return new address[](0); + } + + // Emulate a sampling of the validators + uint256 sampleSeed = _getSampleSeed(epochNumber); + return _sampleValidators(sampleSeed); + } + /** * @notice Propose a pending block from the point-of-view of sequencer selection. Will: * - Setup the epoch if needed (if epoch committee is empty skips the rest) @@ -392,6 +414,20 @@ contract Leonidas is Ownable, ILeonidas { } } + /** + * @notice Computes the nextSeed for an epoch + * + * @dev We include the `_epoch` instead of using the randao directly to avoid issues with foundry testing + * where randao == 0. + * + * @param _epoch - The epoch to compute the seed for + * + * @return The computed seed + */ + function _computeNextSeed(uint256 _epoch) private view returns (uint256) { + return uint256(keccak256(abi.encode(_epoch, block.prevrandao))); + } + /** * @notice Samples a validator set for a specific epoch * @@ -452,42 +488,6 @@ contract Leonidas is Ownable, ILeonidas { return lastSeed; } - /** - * @notice Computes the epoch at a specific time - * - * @param _ts - The timestamp to compute the epoch for - * - * @return The computed epoch - */ - function getEpochAt(uint256 _ts) public view returns (uint256) { - return (_ts - GENESIS_TIME) / (EPOCH_DURATION * SLOT_DURATION); - } - - /** - * @notice Computes the slot at a specific time - * - * @param _ts - The timestamp to compute the slot for - * - * @return The computed slot - */ - function getSlotAt(uint256 _ts) public view returns (uint256) { - return (_ts - GENESIS_TIME) / SLOT_DURATION; - } - - /** - * @notice Computes the nextSeed for an epoch - * - * @dev We include the `_epoch` instead of using the randao directly to avoid issues with foundry testing - * where randao == 0. - * - * @param _epoch - The epoch to compute the seed for - * - * @return The computed seed - */ - function _computeNextSeed(uint256 _epoch) private view returns (uint256) { - return uint256(keccak256(abi.encode(_epoch, block.prevrandao))); - } - /** * @notice Computes the index of the committee member that acts as proposer for a given slot * diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 084870f412d..6331b455212 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -23,6 +23,8 @@ import {PortalERC20} from "./portals/PortalERC20.sol"; import {TxsDecoderHelper} from "./decoders/helpers/TxsDecoderHelper.sol"; import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol"; +// solhint-disable comprehensive-interface + /** * Blocks are generated using the `integration_l1_publisher.test.ts` tests. * Main use of these test is shorter cycles when updating the decoder contract. @@ -113,13 +115,7 @@ contract RollupTest is DecoderBase { _testBlock("mixed_block_1", false); - uint256 currentSlot = rollup.getCurrentSlot(); - (,, uint128 slot) = rollup.blocks(1); - uint256 prunableAt = uint256(slot) + rollup.TIMELINESS_PROVING_IN_SLOTS(); - - vm.expectRevert( - abi.encodeWithSelector(Errors.Rollup__NotReadyToPrune.selector, currentSlot, prunableAt) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NothingToPrune.selector)); rollup.prune(); } diff --git a/l1-contracts/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index 9a8e84d143b..44700b1e4f5 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -21,6 +21,8 @@ import {TxsDecoderHelper} from "../decoders/helpers/TxsDecoderHelper.sol"; import {IFeeJuicePortal} from "../../src/core/interfaces/IFeeJuicePortal.sol"; import {MessageHashUtils} from "@oz/utils/cryptography/MessageHashUtils.sol"; +// solhint-disable comprehensive-interface + /** * We are using the same blocks as from Rollup.t.sol. * The tests in this file is testing the sequencer selection @@ -28,6 +30,12 @@ import {MessageHashUtils} from "@oz/utils/cryptography/MessageHashUtils.sol"; contract SpartaTest is DecoderBase { using MessageHashUtils for bytes32; + struct StructToAvoidDeepStacks { + uint256 needed; + address proposer; + bool shouldRevert; + } + Registry internal registry; Inbox internal inbox; Outbox internal outbox; @@ -36,9 +44,10 @@ contract SpartaTest is DecoderBase { TxsDecoderHelper internal txsHelper; PortalERC20 internal portalERC20; - mapping(address validator => uint256 privateKey) internal privateKeys; - SignatureLib.Signature internal emptySignature; + mapping(address validator => uint256 privateKey) internal privateKeys; + mapping(address => bool) internal _seenValidators; + mapping(address => bool) internal _seenCommittee; /** * @notice Set up the contracts needed for the tests with time aligned to the provided block name @@ -78,9 +87,6 @@ contract SpartaTest is DecoderBase { _; } - mapping(address => bool) internal _seenValidators; - mapping(address => bool) internal _seenCommittee; - function testInitialCommitteMatch() public setup(4) { address[] memory validators = rollup.getValidators(); address[] memory committee = rollup.getCurrentEpochCommittee(); @@ -145,12 +151,6 @@ contract SpartaTest is DecoderBase { _testBlock("mixed_block_1", true, 2, false); } - struct StructToAvoidDeepStacks { - uint256 needed; - address proposer; - bool shouldRevert; - } - function _testBlock( string memory _name, bool _expectRevert, From 4cdeb3bf3e8c04ff6797fd494371727f642b7612 Mon Sep 17 00:00:00 2001 From: Mitch Date: Tue, 17 Sep 2024 20:33:17 -0400 Subject: [PATCH 3/7] update getSlotAt check --- l1-contracts/src/core/sequencer_selection/Leonidas.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l1-contracts/src/core/sequencer_selection/Leonidas.sol b/l1-contracts/src/core/sequencer_selection/Leonidas.sol index 1b9484658c6..8a90052500f 100644 --- a/l1-contracts/src/core/sequencer_selection/Leonidas.sol +++ b/l1-contracts/src/core/sequencer_selection/Leonidas.sol @@ -311,7 +311,7 @@ contract Leonidas is Ownable, ILeonidas { * @return The computed slot */ function getSlotAt(uint256 _ts) public view override(ILeonidas) returns (uint256) { - return (_ts - GENESIS_TIME) / SLOT_DURATION; + return _ts < GENESIS_TIME ? 0 : (_ts - GENESIS_TIME) / SLOT_DURATION; } /** From 9d09b1d1e4a586d418e29c0b081e88b67f3a631d Mon Sep 17 00:00:00 2001 From: Mitch Date: Wed, 18 Sep 2024 14:44:56 -0400 Subject: [PATCH 4/7] Update test to hit code path --- l1-contracts/test/Rollup.t.sol | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 6331b455212..5a32fc4b905 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -119,7 +119,7 @@ contract RollupTest is DecoderBase { rollup.prune(); } - function testPrune() public setUpFor("mixed_block_1") { + function testPruneDuringPropose() public setUpFor("mixed_block_1") { _testBlock("mixed_block_1", false); assertEq(inbox.inProgress(), 3, "Invalid in progress"); @@ -129,7 +129,7 @@ contract RollupTest is DecoderBase { bytes32 inboxRoot2 = inbox.getRoot(2); (,, uint128 slot) = rollup.blocks(1); - uint256 prunableAt = uint256(slot) + rollup.TIMELINESS_PROVING_IN_SLOTS(); + uint256 prunableAt = uint256(slot) + Constants.AZTEC_EPOCH_DURATION * 2; uint256 timeOfPrune = rollup.getTimestampForSlot(prunableAt); vm.warp(timeOfPrune); @@ -148,16 +148,12 @@ contract RollupTest is DecoderBase { assertNotEq(rootMixed, bytes32(0), "Invalid root"); assertNotEq(minHeightMixed, 0, "Invalid min height"); - rollup.prune(); - assertEq(inbox.inProgress(), 3, "Invalid in progress"); - assertEq(rollup.getPendingBlockNumber(), 0, "Invalid pending block number"); - assertEq(rollup.getProvenBlockNumber(), 0, "Invalid proven block number"); - // @note We alter what slot is specified in the empty block! // This means that we keep the `empty_block_1` mostly as is, but replace the slot number // and timestamp as if it was created at a different point in time. This allow us to insert it // as if it was the first block, even after we had originally inserted the mixed block. - // An example where this could happen would be if no-one could proof the mixed block. + // An example where this could happen would be if no-one could prove the mixed block. + // @note We prune the pending chain as part of the propose call. _testBlock("empty_block_1", false, prunableAt); assertEq(inbox.inProgress(), 3, "Invalid in progress"); From 6b1a7ba3d27b01bb841daf8cec51950fcddda264 Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Thu, 19 Sep 2024 20:19:18 -0400 Subject: [PATCH 5/7] feat: proofClaim in Rollup (#8636) Fix #8608 Add the proofClaim to the rollup. Update the `canPrune` logic to account for it. --- l1-contracts/src/core/Rollup.sol | 93 +++++- l1-contracts/src/core/interfaces/IRollup.sol | 13 + .../src/core/libraries/DataStructures.sol | 8 + l1-contracts/src/core/libraries/Errors.sol | 22 +- l1-contracts/test/Rollup.t.sol | 279 ++++++++++++++++++ 5 files changed, 403 insertions(+), 12 deletions(-) diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 71a7f7f0f2b..7e8aec2f39b 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -53,6 +53,9 @@ contract Rollup is Leonidas, IRollup, ITestRollup { // @todo #8018 uint256 public constant TIMELINESS_PROVING_IN_SLOTS = 100; + uint256 public constant CLAIM_DURATION_IN_L2_SLOTS = 13; + uint256 public constant PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST = 1000; + uint256 public immutable L1_BLOCK_AT_GENESIS; IRegistry public immutable REGISTRY; IInbox public immutable INBOX; @@ -63,6 +66,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { IVerifier public verifier; ChainTips public tips; + DataStructures.EpochProofClaim public proofClaim; // @todo Validate assumption: // Currently we assume that the archive root following a block is specific to the block @@ -177,6 +181,60 @@ contract Rollup is Leonidas, IRollup, ITestRollup { vkTreeRoot = _vkTreeRoot; } + function claimEpochProofRight(DataStructures.EpochProofQuote calldata _quote) + external + override(IRollup) + { + uint256 currentSlot = getCurrentSlot(); + address currentProposer = getCurrentProposer(); + uint256 epochToProve = getEpochToProve(); + + if (currentProposer != address(0) && currentProposer != msg.sender) { + revert Errors.Leonidas__InvalidProposer(currentProposer, msg.sender); + } + + if (_quote.epochToProve != epochToProve) { + revert Errors.Rollup__NotClaimingCorrectEpoch(epochToProve, _quote.epochToProve); + } + + if (currentSlot % Constants.AZTEC_EPOCH_DURATION >= CLAIM_DURATION_IN_L2_SLOTS) { + revert Errors.Rollup__NotInClaimPhase( + currentSlot % Constants.AZTEC_EPOCH_DURATION, CLAIM_DURATION_IN_L2_SLOTS + ); + } + + // if the epoch to prove is not the one that has been claimed, + // then whatever is in the proofClaim is stale + if (proofClaim.epochToProve == epochToProve && proofClaim.proposerClaimant != address(0)) { + revert Errors.Rollup__ProofRightAlreadyClaimed(); + } + + if (_quote.bondAmount < PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST) { + revert Errors.Rollup__InsufficientBondAmount( + PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST, _quote.bondAmount + ); + } + + if (_quote.validUntilSlot < currentSlot) { + revert Errors.Rollup__QuoteExpired(currentSlot, _quote.validUntilSlot); + } + + // We don't currently unstake, + // but we will as part of https://github.com/AztecProtocol/aztec-packages/issues/8652. + // Blocked on submitting epoch proofs to this contract. + address bondProvider = PROOF_COMMITMENT_ESCROW.stakeBond(_quote); + + proofClaim = DataStructures.EpochProofClaim({ + epochToProve: epochToProve, + basisPointFee: _quote.basisPointFee, + bondAmount: _quote.bondAmount, + bondProvider: bondProvider, + proposerClaimant: msg.sender + }); + + emit ProofRightClaimed(epochToProve, bondProvider, msg.sender, _quote.bondAmount, currentSlot); + } + /** * @notice Publishes the body and propose the block * @dev `eth_log_handlers` rely on this function @@ -480,7 +538,26 @@ contract Rollup is Leonidas, IRollup, ITestRollup { return tips.pendingBlockNumber; } + /** + * @notice Get the epoch that should be proven + * + * @dev This is the epoch that should be proven. It does so by getting the epoch of the block + * following the last proven block. If there is no such block (i.e. the pending chain is + * the same as the proven chain), then revert. + * + * @return uint256 - The epoch to prove + */ + function getEpochToProve() public view override(IRollup) returns (uint256) { + if (tips.provenBlockNumber == tips.pendingBlockNumber) { + revert Errors.Rollup__NoEpochToProve(); + } else { + return getEpochAt(blocks[getProvenBlockNumber() + 1].slotNumber); + } + } + function _prune() internal { + delete proofClaim; + uint256 pending = tips.pendingBlockNumber; // @note We are not deleting the blocks, but we are "winding back" the pendingTip to the last block that was proven. @@ -501,12 +578,20 @@ contract Rollup is Leonidas, IRollup, ITestRollup { uint256 oldestPendingEpoch = getEpochAt(blocks[tips.provenBlockNumber + 1].slotNumber); uint256 startSlotOfPendingEpoch = oldestPendingEpoch * Constants.AZTEC_EPOCH_DURATION; - // TODO: #8608 adds a proof claim, which will allow us to prune the chain more aggressively. - // That is what will add a `CLAIM_DURATION` to the pruning logic. - if (currentSlot < startSlotOfPendingEpoch + 2 * Constants.AZTEC_EPOCH_DURATION) { + // suppose epoch 1 is proven, epoch 2 is pending, epoch 3 is the current epoch. + // we prune the pending chain back to the end of epoch 1 if: + // - the proof claim phase of epoch 3 has ended without a claim to prove epoch 2 (or proof of epoch 2) + // - we reach epoch 4 without a proof of epoch 2 (regardless of whether a proof claim was submitted) + bool inClaimPhase = currentSlot + < startSlotOfPendingEpoch + Constants.AZTEC_EPOCH_DURATION + CLAIM_DURATION_IN_L2_SLOTS; + + bool claimExists = currentSlot < startSlotOfPendingEpoch + 2 * Constants.AZTEC_EPOCH_DURATION + && proofClaim.epochToProve == oldestPendingEpoch && proofClaim.proposerClaimant != address(0); + + if (inClaimPhase || claimExists) { + // If we are in the claim phase, do not prune return false; } - return true; } diff --git a/l1-contracts/src/core/interfaces/IRollup.sol b/l1-contracts/src/core/interfaces/IRollup.sol index 4fe5e30dab2..464f4c93a96 100644 --- a/l1-contracts/src/core/interfaces/IRollup.sol +++ b/l1-contracts/src/core/interfaces/IRollup.sol @@ -18,9 +18,18 @@ interface IRollup { event L2BlockProposed(uint256 indexed blockNumber, bytes32 indexed archive); event L2ProofVerified(uint256 indexed blockNumber, bytes32 indexed proverId); event PrunedPending(uint256 provenBlockNumber, uint256 pendingBlockNumber); + event ProofRightClaimed( + uint256 indexed epoch, + address indexed bondProvider, + address indexed proposer, + uint256 bondAmount, + uint256 currentSlot + ); function prune() external; + function claimEpochProofRight(DataStructures.EpochProofQuote calldata _quote) external; + function propose( bytes calldata _header, bytes32 _archive, @@ -48,10 +57,13 @@ interface IRollup { DataStructures.ExecutionFlags memory _flags ) external view; + // solhint-disable-next-line func-name-mixedcase function INBOX() external view returns (IInbox); + // solhint-disable-next-line func-name-mixedcase function OUTBOX() external view returns (IOutbox); + // solhint-disable-next-line func-name-mixedcase function L1_BLOCK_AT_GENESIS() external view returns (uint256); function status(uint256 myHeaderBlockNumber) @@ -81,5 +93,6 @@ interface IRollup { function archiveAt(uint256 _blockNumber) external view returns (bytes32); function getProvenBlockNumber() external view returns (uint256); function getPendingBlockNumber() external view returns (uint256); + function getEpochToProve() external view returns (uint256); function computeTxsEffectsHash(bytes calldata _body) external pure returns (bytes32); } diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index 2b6438c3702..dcfa1b75888 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -90,4 +90,12 @@ library DataStructures { address rollup; uint32 basisPointFee; } + + struct EpochProofClaim { + uint256 epochToProve; // the epoch that the bond provider is claiming to prove + uint256 basisPointFee; // the fee that the bond provider will receive as a percentage of the block rewards + uint256 bondAmount; // the amount of escrowed funds that the bond provider will stake. Must be at least PROOF_COMMITMENT_BOND_AMOUNT + address bondProvider; // the address that has deposited funds in the escrow contract + address proposerClaimant; // the address of the proposer that submitted the claim + } } diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index fab6b2bac33..b5086474992 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -44,23 +44,29 @@ library Errors { error Outbox__BlockNotProven(uint256 l2BlockNumber); // 0x0e194a6d // Rollup + error Rollup__InsufficientBondAmount(uint256 minimum, uint256 provided); // 0xa165f276 error Rollup__InvalidArchive(bytes32 expected, bytes32 actual); // 0xb682a40e - error Rollup__InvalidProposedArchive(bytes32 expected, bytes32 actual); // 0x32532e73 error Rollup__InvalidBlockNumber(uint256 expected, uint256 actual); // 0xe5edf847 - error Rollup__SlotValueTooLarge(uint256 slot); // 0x7234f4fe - error Rollup__SlotAlreadyInChain(uint256 lastSlot, uint256 proposedSlot); // 0x83510bd0 + error Rollup__InvalidChainId(uint256 expected, uint256 actual); // 0x37b5bc12 error Rollup__InvalidEpoch(uint256 expected, uint256 actual); // 0x3c6d65e6 - error Rollup__TryingToProveNonExistingBlock(); // 0x34ef4954 error Rollup__InvalidInHash(bytes32 expected, bytes32 actual); // 0xcd6f4233 error Rollup__InvalidProof(); // 0xa5b2ba17 - error Rollup__InvalidChainId(uint256 expected, uint256 actual); // 0x37b5bc12 - error Rollup__InvalidVersion(uint256 expected, uint256 actual); // 0x9ef30794 + error Rollup__InvalidProposedArchive(bytes32 expected, bytes32 actual); // 0x32532e73 error Rollup__InvalidTimestamp(uint256 expected, uint256 actual); // 0x3132e895 + error Rollup__InvalidVersion(uint256 expected, uint256 actual); // 0x9ef30794 + error Rollup__NoEpochToProve(); // 0xcbaa3951 + error Rollup__NonSequentialProving(); // 0x1e5be132 + error Rollup__NotClaimingCorrectEpoch(uint256 expected, uint256 actual); // 0xf0e0744d + error Rollup__NothingToPrune(); // 0x850defd3 + error Rollup__NotInClaimPhase(uint256 currentSlotInEpoch, uint256 claimDuration); // 0xe6969f11 + error Rollup__ProofRightAlreadyClaimed(); // 0x2cac5f0a + error Rollup__QuoteExpired(uint256 currentSlot, uint256 quoteSlot); // 0x20a001eb + error Rollup__SlotAlreadyInChain(uint256 lastSlot, uint256 proposedSlot); // 0x83510bd0 + error Rollup__SlotValueTooLarge(uint256 slot); // 0x7234f4fe error Rollup__TimestampInFuture(uint256 max, uint256 actual); // 0x89f30690 error Rollup__TimestampTooOld(); // 0x72ed9c81 + error Rollup__TryingToProveNonExistingBlock(); // 0x34ef4954 error Rollup__UnavailableTxs(bytes32 txsHash); // 0x414906c3 - error Rollup__NothingToPrune(); // 0x850defd3 - error Rollup__NonSequentialProving(); // 0x1e5be132 // Registry error Registry__RollupNotRegistered(address rollup); // 0xa1fee4cf diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 5a32fc4b905..0a9eacf8bf4 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -14,6 +14,7 @@ import {Outbox} from "../src/core/messagebridge/Outbox.sol"; import {Errors} from "../src/core/libraries/Errors.sol"; import {Rollup} from "../src/core/Rollup.sol"; import {IFeeJuicePortal} from "../src/core/interfaces/IFeeJuicePortal.sol"; +import {IRollup} from "../src/core/interfaces/IRollup.sol"; import {FeeJuicePortal} from "../src/core/FeeJuicePortal.sol"; import {Leonidas} from "../src/core/sequencer_selection/Leonidas.sol"; import {NaiveMerkle} from "./merkle/Naive.sol"; @@ -78,6 +79,284 @@ contract RollupTest is DecoderBase { _; } + function warpToL2Slot(uint256 _slot) public { + vm.warp(rollup.getTimestampForSlot(_slot)); + } + + function testClaimWithNothingToProve() public setUpFor("mixed_block_1") { + assertEq(rollup.getCurrentSlot(), 0, "genesis slot should be zero"); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 1, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + // sanity check that proven/pending tip are at genesis + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NoEpochToProve.selector)); + rollup.claimEpochProofRight(quote); + + warpToL2Slot(1); + assertEq(rollup.getCurrentSlot(), 1, "warp to slot 1 failed"); + assertEq(rollup.getCurrentEpoch(), 0, "Invalid current epoch"); + + // empty slots do not move pending chain + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NoEpochToProve.selector)); + rollup.claimEpochProofRight(quote); + } + + function testClaimWithWrongEpoch() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 1, + validUntilSlot: 1, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + vm.expectRevert( + abi.encodeWithSelector(Errors.Rollup__NotClaimingCorrectEpoch.selector, 0, quote.epochToProve) + ); + rollup.claimEpochProofRight(quote); + } + + function testClaimWithInsufficientBond() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 1, + bondAmount: 0, + rollup: address(0), + basisPointFee: 0 + }); + + vm.expectRevert( + abi.encodeWithSelector( + Errors.Rollup__InsufficientBondAmount.selector, + rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + quote.bondAmount + ) + ); + rollup.claimEpochProofRight(quote); + } + + function testClaimPastValidUntil() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 0, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + warpToL2Slot(1); + + vm.expectRevert( + abi.encodeWithSelector(Errors.Rollup__QuoteExpired.selector, 1, quote.validUntilSlot) + ); + rollup.claimEpochProofRight(quote); + } + + function testClaimSimple() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 1, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + warpToL2Slot(1); + + vm.expectEmit(true, true, true, true); + emit IRollup.ProofRightClaimed( + quote.epochToProve, address(0), address(this), quote.bondAmount, 1 + ); + rollup.claimEpochProofRight(quote); + + ( + uint256 epochToProve, + uint256 basisPointFee, + uint256 bondAmount, + address bondProvider, + address proposerClaimant + ) = rollup.proofClaim(); + assertEq(epochToProve, quote.epochToProve, "Invalid epoch to prove"); + assertEq(basisPointFee, quote.basisPointFee, "Invalid basis point fee"); + assertEq(bondAmount, quote.bondAmount, "Invalid bond amount"); + // TODO #8573 + // This will be fixed with proper escrow + assertEq(bondProvider, address(0), "Invalid bond provider"); + assertEq(proposerClaimant, address(this), "Invalid proposer claimant"); + } + + function testClaimTwice() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 1, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + warpToL2Slot(1); + + rollup.claimEpochProofRight(quote); + + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__ProofRightAlreadyClaimed.selector)); + rollup.claimEpochProofRight(quote); + + warpToL2Slot(2); + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__ProofRightAlreadyClaimed.selector)); + rollup.claimEpochProofRight(quote); + + // warp to epoch 1 + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION); + assertEq(rollup.getCurrentEpoch(), 1, "Invalid current epoch"); + + // We should still be trying to prove epoch 0 in epoch 1 + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__ProofRightAlreadyClaimed.selector)); + rollup.claimEpochProofRight(quote); + + // still nothing to prune + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NothingToPrune.selector)); + rollup.prune(); + } + + function testClaimOutsideClaimPhase() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 1, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION + rollup.CLAIM_DURATION_IN_L2_SLOTS()); + + vm.expectRevert( + abi.encodeWithSelector( + Errors.Rollup__NotInClaimPhase.selector, + rollup.CLAIM_DURATION_IN_L2_SLOTS(), + rollup.CLAIM_DURATION_IN_L2_SLOTS() + ) + ); + rollup.claimEpochProofRight(quote); + } + + function testNoPruneWhenClaimExists() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION + rollup.CLAIM_DURATION_IN_L2_SLOTS() - 1); + + rollup.claimEpochProofRight(quote); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION + rollup.CLAIM_DURATION_IN_L2_SLOTS()); + + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NothingToPrune.selector)); + rollup.prune(); + } + + function testPruneWhenClaimExpires() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION + rollup.CLAIM_DURATION_IN_L2_SLOTS() - 1); + + rollup.claimEpochProofRight(quote); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION * 2); + + // We should still be trying to prove epoch 0 in epoch 2 + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__ProofRightAlreadyClaimed.selector)); + rollup.claimEpochProofRight(quote); + + rollup.prune(); + + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NoEpochToProve.selector)); + rollup.claimEpochProofRight(quote); + } + + function testClaimAfterPrune() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false, 0); + + DataStructures.EpochProofQuote memory quote = DataStructures.EpochProofQuote({ + signature: SignatureLib.Signature({isEmpty: false, v: 27, r: bytes32(0), s: bytes32(0)}), + epochToProve: 0, + validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, + bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + rollup: address(0), + basisPointFee: 0 + }); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION + rollup.CLAIM_DURATION_IN_L2_SLOTS() - 1); + + rollup.claimEpochProofRight(quote); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION * 2); + + rollup.prune(); + + _testBlock("mixed_block_1", false, Constants.AZTEC_EPOCH_DURATION * 2); + + vm.expectEmit(true, true, true, true); + emit IRollup.ProofRightClaimed( + quote.epochToProve, + address(0), + address(this), + quote.bondAmount, + Constants.AZTEC_EPOCH_DURATION * 2 + ); + rollup.claimEpochProofRight(quote); + } + + function testPruneWhenNoProofClaim() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false); + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION + rollup.CLAIM_DURATION_IN_L2_SLOTS() - 1); + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NothingToPrune.selector)); + rollup.prune(); + + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION + rollup.CLAIM_DURATION_IN_L2_SLOTS()); + rollup.prune(); + } + function testRevertProveTwice() public setUpFor("mixed_block_1") { DecoderBase.Data memory data = load("mixed_block_1").block; bytes memory header = data.header; From 09d306491ce8739237656866952755c8e4827915 Mon Sep 17 00:00:00 2001 From: Mitch Date: Thu, 19 Sep 2024 20:48:10 -0400 Subject: [PATCH 6/7] clean up escrow interface remove `TIMELINESS_PROVING_IN_SLOTS` update tests --- l1-contracts/src/core/Rollup.sol | 80 +++++++++---------- .../interfaces/IProofCommitmentEscrow.sol | 8 +- .../src/core/libraries/DataStructures.sol | 1 - .../src/mock/MockProofCommitmentEscrow.sol | 4 +- l1-contracts/test/Rollup.t.sol | 27 ++++--- .../end-to-end/src/e2e_synching.test.ts | 2 +- 6 files changed, 62 insertions(+), 60 deletions(-) diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 7e8aec2f39b..d9d26527873 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -48,11 +48,8 @@ contract Rollup is Leonidas, IRollup, ITestRollup { uint128 slotNumber; } - // @note The number of slots within which a block must be proven - // This number is currently pulled out of thin air and should be replaced when we are not blind - // @todo #8018 - uint256 public constant TIMELINESS_PROVING_IN_SLOTS = 100; - + // See https://github.com/AztecProtocol/engineering-designs/blob/main/in-progress/8401-proof-timeliness/proof-timeliness.ipynb + // for justification of CLAIM_DURATION_IN_L2_SLOTS. uint256 public constant CLAIM_DURATION_IN_L2_SLOTS = 13; uint256 public constant PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST = 1000; @@ -110,27 +107,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup { setupEpoch(); } - function status(uint256 myHeaderBlockNumber) - external - view - override(IRollup) - returns ( - uint256 provenBlockNumber, - bytes32 provenArchive, - uint256 pendingBlockNumber, - bytes32 pendingArchive, - bytes32 archiveOfMyBlock - ) - { - return ( - tips.provenBlockNumber, - blocks[tips.provenBlockNumber].archive, - tips.pendingBlockNumber, - blocks[tips.pendingBlockNumber].archive, - archiveAt(myHeaderBlockNumber) - ); - } - /** * @notice Prune the pending chain up to the last proven block * @@ -222,7 +198,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { // We don't currently unstake, // but we will as part of https://github.com/AztecProtocol/aztec-packages/issues/8652. // Blocked on submitting epoch proofs to this contract. - address bondProvider = PROOF_COMMITMENT_ESCROW.stakeBond(_quote); + address bondProvider = PROOF_COMMITMENT_ESCROW.stakeBond(_quote.signature, _quote.bondAmount); proofClaim = DataStructures.EpochProofClaim({ epochToProve: epochToProve, @@ -452,6 +428,27 @@ contract Rollup is Leonidas, IRollup, ITestRollup { emit L2ProofVerified(header.globalVariables.blockNumber, _proverId); } + function status(uint256 myHeaderBlockNumber) + external + view + override(IRollup) + returns ( + uint256 provenBlockNumber, + bytes32 provenArchive, + uint256 pendingBlockNumber, + bytes32 pendingArchive, + bytes32 archiveOfMyBlock + ) + { + return ( + tips.provenBlockNumber, + blocks[tips.provenBlockNumber].archive, + tips.pendingBlockNumber, + blocks[tips.pendingBlockNumber].archive, + archiveAt(myHeaderBlockNumber) + ); + } + /** * @notice Check if msg.sender can propose at a given time * @@ -555,7 +552,22 @@ contract Rollup is Leonidas, IRollup, ITestRollup { } } + /** + * @notice Get the archive root of a specific block + * + * @param _blockNumber - The block number to get the archive root of + * + * @return bytes32 - The archive root of the block + */ + function archiveAt(uint256 _blockNumber) public view override(IRollup) returns (bytes32) { + if (_blockNumber <= tips.pendingBlockNumber) { + return blocks[_blockNumber].archive; + } + return bytes32(0); + } + function _prune() internal { + // TODO #8656 delete proofClaim; uint256 pending = tips.pendingBlockNumber; @@ -595,20 +607,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup { return true; } - /** - * @notice Get the archive root of a specific block - * - * @param _blockNumber - The block number to get the archive root of - * - * @return bytes32 - The archive root of the block - */ - function archiveAt(uint256 _blockNumber) public view override(IRollup) returns (bytes32) { - if (_blockNumber <= tips.pendingBlockNumber) { - return blocks[_blockNumber].archive; - } - return bytes32(0); - } - /** * @notice Validates the header for submission * diff --git a/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol b/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol index 8ef52a2e670..77b3fba206c 100644 --- a/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol +++ b/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol @@ -2,12 +2,14 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; -import {DataStructures} from "../libraries/DataStructures.sol"; +import {SignatureLib} from "../libraries/SignatureLib.sol"; interface IProofCommitmentEscrow { function deposit(uint256 _amount) external; function withdraw(uint256 _amount) external; // returns the address of the bond provider - function stakeBond(DataStructures.EpochProofQuote calldata _quote) external returns (address); - function unstakeBond(uint256 _amount) external; + function stakeBond(SignatureLib.Signature calldata _signature, uint256 _bondAmount) + external + returns (address); + function unstakeBond(uint256 _bondAmount) external; } diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index dcfa1b75888..f22eb10cd0d 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -87,7 +87,6 @@ library DataStructures { uint256 epochToProve; uint256 validUntilSlot; uint256 bondAmount; - address rollup; uint32 basisPointFee; } diff --git a/l1-contracts/src/mock/MockProofCommitmentEscrow.sol b/l1-contracts/src/mock/MockProofCommitmentEscrow.sol index d7bc1d847e4..9f62f7b76c7 100644 --- a/l1-contracts/src/mock/MockProofCommitmentEscrow.sol +++ b/l1-contracts/src/mock/MockProofCommitmentEscrow.sol @@ -2,7 +2,7 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; -import {DataStructures} from "../core/libraries/DataStructures.sol"; +import {SignatureLib} from "../core/libraries/SignatureLib.sol"; import {IProofCommitmentEscrow} from "../core/interfaces/IProofCommitmentEscrow.sol"; contract MockProofCommitmentEscrow is IProofCommitmentEscrow { @@ -18,7 +18,7 @@ contract MockProofCommitmentEscrow is IProofCommitmentEscrow { // do nothing } - function stakeBond(DataStructures.EpochProofQuote calldata) + function stakeBond(SignatureLib.Signature calldata, uint256) external pure override diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 0a9eacf8bf4..5c318419316 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -91,7 +91,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -116,7 +115,6 @@ contract RollupTest is DecoderBase { epochToProve: 1, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -134,7 +132,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: 0, - rollup: address(0), basisPointFee: 0 }); @@ -156,7 +153,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 0, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -176,7 +172,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -212,7 +207,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -248,7 +242,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -272,7 +265,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -294,7 +286,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -322,7 +313,6 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), - rollup: address(0), basisPointFee: 0 }); @@ -398,7 +388,7 @@ contract RollupTest is DecoderBase { rollup.prune(); } - function testPruneDuringPropose() public setUpFor("mixed_block_1") { + function testPrune() public setUpFor("mixed_block_1") { _testBlock("mixed_block_1", false); assertEq(inbox.inProgress(), 3, "Invalid in progress"); @@ -427,12 +417,16 @@ contract RollupTest is DecoderBase { assertNotEq(rootMixed, bytes32(0), "Invalid root"); assertNotEq(minHeightMixed, 0, "Invalid min height"); + rollup.prune(); + assertEq(inbox.inProgress(), 3, "Invalid in progress"); + assertEq(rollup.getPendingBlockNumber(), 0, "Invalid pending block number"); + assertEq(rollup.getProvenBlockNumber(), 0, "Invalid proven block number"); + // @note We alter what slot is specified in the empty block! // This means that we keep the `empty_block_1` mostly as is, but replace the slot number // and timestamp as if it was created at a different point in time. This allow us to insert it // as if it was the first block, even after we had originally inserted the mixed block. // An example where this could happen would be if no-one could prove the mixed block. - // @note We prune the pending chain as part of the propose call. _testBlock("empty_block_1", false, prunableAt); assertEq(inbox.inProgress(), 3, "Invalid in progress"); @@ -451,6 +445,15 @@ contract RollupTest is DecoderBase { assertNotEq(minHeightEmpty, minHeightMixed, "Invalid min height"); } + function testPruneDuringPropose() public setUpFor("mixed_block_1") { + _testBlock("mixed_block_1", false); + warpToL2Slot(Constants.AZTEC_EPOCH_DURATION * 2); + _testBlock("mixed_block_1", false, Constants.AZTEC_EPOCH_DURATION * 2); + + assertEq(rollup.getPendingBlockNumber(), 1, "Invalid pending block number"); + assertEq(rollup.getProvenBlockNumber(), 0, "Invalid proven block number"); + } + function testBlockFee() public setUpFor("mixed_block_1") { uint256 feeAmount = 2e18; diff --git a/yarn-project/end-to-end/src/e2e_synching.test.ts b/yarn-project/end-to-end/src/e2e_synching.test.ts index 2cbb21530fa..a0f980bab34 100644 --- a/yarn-project/end-to-end/src/e2e_synching.test.ts +++ b/yarn-project/end-to-end/src/e2e_synching.test.ts @@ -451,7 +451,7 @@ describe('e2e_synching', () => { const pendingBlockNumber = await rollup.read.getPendingBlockNumber(); await rollup.write.setAssumeProvenThroughBlockNumber([pendingBlockNumber - BigInt(variant.blockCount) / 2n]); - const timeliness = await rollup.read.TIMELINESS_PROVING_IN_SLOTS(); + const timeliness = (await rollup.read.EPOCH_DURATION()) * 2n; const [, , slot] = await rollup.read.blocks([(await rollup.read.getProvenBlockNumber()) + 1n]); const timeJumpTo = await rollup.read.getTimestampForSlot([slot + timeliness]); From d83289eae6e0a4d5bd058778eac8a88da0f5754a Mon Sep 17 00:00:00 2001 From: Mitch Date: Tue, 24 Sep 2024 10:19:42 -0400 Subject: [PATCH 7/7] update escrow interface and quote structure --- l1-contracts/src/core/Rollup.sol | 6 +++--- .../src/core/interfaces/IProofCommitmentEscrow.sol | 7 ++----- l1-contracts/src/core/libraries/DataStructures.sol | 1 + l1-contracts/src/mock/MockProofCommitmentEscrow.sol | 11 +++-------- l1-contracts/test/Rollup.t.sol | 12 +++++++++++- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index d9d26527873..40dab5df5e9 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -198,17 +198,17 @@ contract Rollup is Leonidas, IRollup, ITestRollup { // We don't currently unstake, // but we will as part of https://github.com/AztecProtocol/aztec-packages/issues/8652. // Blocked on submitting epoch proofs to this contract. - address bondProvider = PROOF_COMMITMENT_ESCROW.stakeBond(_quote.signature, _quote.bondAmount); + PROOF_COMMITMENT_ESCROW.stakeBond(_quote.bondAmount, _quote.prover); proofClaim = DataStructures.EpochProofClaim({ epochToProve: epochToProve, basisPointFee: _quote.basisPointFee, bondAmount: _quote.bondAmount, - bondProvider: bondProvider, + bondProvider: _quote.prover, proposerClaimant: msg.sender }); - emit ProofRightClaimed(epochToProve, bondProvider, msg.sender, _quote.bondAmount, currentSlot); + emit ProofRightClaimed(epochToProve, _quote.prover, msg.sender, _quote.bondAmount, currentSlot); } /** diff --git a/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol b/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol index 77b3fba206c..5aa2be81ec8 100644 --- a/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol +++ b/l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol @@ -7,9 +7,6 @@ import {SignatureLib} from "../libraries/SignatureLib.sol"; interface IProofCommitmentEscrow { function deposit(uint256 _amount) external; function withdraw(uint256 _amount) external; - // returns the address of the bond provider - function stakeBond(SignatureLib.Signature calldata _signature, uint256 _bondAmount) - external - returns (address); - function unstakeBond(uint256 _bondAmount) external; + function stakeBond(uint256 _bondAmount, address _prover) external; + function unstakeBond(uint256 _bondAmount, address _prover) external; } diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index f22eb10cd0d..8a114ce55c0 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -87,6 +87,7 @@ library DataStructures { uint256 epochToProve; uint256 validUntilSlot; uint256 bondAmount; + address prover; uint32 basisPointFee; } diff --git a/l1-contracts/src/mock/MockProofCommitmentEscrow.sol b/l1-contracts/src/mock/MockProofCommitmentEscrow.sol index 9f62f7b76c7..89e61d3c241 100644 --- a/l1-contracts/src/mock/MockProofCommitmentEscrow.sol +++ b/l1-contracts/src/mock/MockProofCommitmentEscrow.sol @@ -14,16 +14,11 @@ contract MockProofCommitmentEscrow is IProofCommitmentEscrow { // do nothing } - function unstakeBond(uint256 _amount) external override { + function unstakeBond(uint256 _amount, address _prover) external override { // do nothing } - function stakeBond(SignatureLib.Signature calldata, uint256) - external - pure - override - returns (address) - { - return address(0); + function stakeBond(uint256 _amount, address _prover) external override { + // do nothing } } diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 5c318419316..27e20595c59 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -91,6 +91,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -115,6 +116,7 @@ contract RollupTest is DecoderBase { epochToProve: 1, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -132,6 +134,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: 0, + prover: address(this), basisPointFee: 0 }); @@ -153,6 +156,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 0, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -172,6 +176,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(0), basisPointFee: 0 }); @@ -207,6 +212,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -242,6 +248,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 1, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -265,6 +272,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -286,6 +294,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -313,6 +322,7 @@ contract RollupTest is DecoderBase { epochToProve: 0, validUntilSlot: 2 * Constants.AZTEC_EPOCH_DURATION, bondAmount: rollup.PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST(), + prover: address(this), basisPointFee: 0 }); @@ -329,7 +339,7 @@ contract RollupTest is DecoderBase { vm.expectEmit(true, true, true, true); emit IRollup.ProofRightClaimed( quote.epochToProve, - address(0), + address(this), address(this), quote.bondAmount, Constants.AZTEC_EPOCH_DURATION * 2