Skip to content

Ahead of time auction for prover incentives #49

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

Merged
merged 98 commits into from
Mar 26, 2025
Merged
Show file tree
Hide file tree
Changes from 84 commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
bbdb33a
initial very rough implementation
ggonzalez94 Feb 24, 2025
d80af9f
add
ggonzalez94 Feb 24, 2025
b3931d9
improve the design and add necessary functions for evicting provers a…
ggonzalez94 Feb 25, 2025
f20a11b
use periods for the contract logic
ggonzalez94 Feb 25, 2025
24ebfc6
Merge branch 'main' into ahead-of-time-prover
ggonzalez94 Feb 25, 2025
4c040c4
add main proving function to the ProverManager and switch all logic t…
ggonzalez94 Feb 25, 2025
d7820a0
fmt
ggonzalez94 Feb 25, 2025
62b0391
add proveOtherPeriod and new interfaces
ggonzalez94 Feb 25, 2025
b76c422
expand IProverManager interface
ggonzalez94 Feb 25, 2025
a42f3cb
Fix typos
nikeshnazareth Feb 26, 2025
ffd8162
Fix spelling of inactiveExitDelay
nikeshnazareth Feb 26, 2025
8218e0f
Fix typo
nikeshnazareth Feb 26, 2025
46ef136
change exitAllowedAt for periodEnd
ggonzalez94 Feb 26, 2025
97ea128
Fix typo
nikeshnazareth Feb 26, 2025
08eb65d
Fix typos
nikeshnazareth Feb 26, 2025
a67c370
Merge branch 'ahead-of-time-prover' of https://github.com/OpenZeppeli…
ggonzalez94 Feb 26, 2025
2555e04
Merge branch 'ahead-of-time-prover' of https://github.com/OpenZeppeli…
ggonzalez94 Feb 26, 2025
daa3670
pass all parameters in the ctor. We might still merge some of these
ggonzalez94 Feb 26, 2025
5c3afc9
use bps for percentage, remove some unnecesary checks and storage var…
ggonzalez94 Feb 26, 2025
e32135b
typos
LeoPatOZ Feb 26, 2025
be4fd3d
add validateHeader function and fix issue with registerProver balance
ggonzalez94 Feb 27, 2025
291ee4d
Merge branch 'ahead-of-time-prover' of https://github.com/OpenZeppeli…
ggonzalez94 Feb 27, 2025
43b1dc6
fmt
ggonzalez94 Feb 27, 2025
6ca37e1
add tests
LeoPatOZ Feb 28, 2025
227afbb
Merge branch 'ahead-of-time-prover' of github.com:OpenZeppelin/minima…
LeoPatOZ Feb 28, 2025
1abea95
cleanup test
LeoPatOZ Feb 28, 2025
0360620
fix an issue with balance calculations and do some renamings
ggonzalez94 Feb 28, 2025
65f3f6c
debugging
LeoPatOZ Feb 28, 2025
a7a9307
Merge branch 'ahead-of-time-prover' of github.com:OpenZeppelin/minima…
LeoPatOZ Feb 28, 2025
e749ec2
remove console logs
LeoPatOZ Mar 3, 2025
bb780be
Change period livness bond to period stake
LeoPatOZ Mar 3, 2025
4e9b2ad
make ProverManager ctor payable, renames and validate start publicati…
ggonzalez94 Mar 7, 2025
3890985
refactor common logic into internal functions and improve documentation
ggonzalez94 Mar 7, 2025
3467088
add a lot of tests, fix some edge cases on ProverManager
ggonzalez94 Mar 10, 2025
c495dab
test revert strings
ggonzalez94 Mar 10, 2025
780cdd3
remove different pricing for delayed publications until we decide
ggonzalez94 Mar 10, 2025
c2efc01
fix checkpoint tracker tests
ggonzalez94 Mar 10, 2025
839894a
solve stack too deep error
ggonzalez94 Mar 10, 2025
7c66555
fmt and change ci
ggonzalez94 Mar 10, 2025
c5b4201
apply suggestions
ggonzalez94 Mar 12, 2025
9d8216b
+
ggonzalez94 Mar 12, 2025
3439cc9
add function to calculate the fees and use in Inbox
ggonzalez94 Mar 12, 2025
5c07994
add _isBidded()
ggonzalez94 Mar 12, 2025
c75931c
merge main
ggonzalez94 Mar 12, 2025
405f2cb
fmt
ggonzalez94 Mar 12, 2025
510658f
optimize withdraw by sending eth with assembly
ggonzalez94 Mar 12, 2025
de9d585
fmt
ggonzalez94 Mar 12, 2025
33367a0
abstract the distribution of stake and fees into a private function
ggonzalez94 Mar 13, 2025
89d74ab
Fix typo
nikeshnazareth Mar 17, 2025
0acdbc1
Revert if withdraw fails
nikeshnazareth Mar 17, 2025
d801ddd
Only evict active provers
nikeshnazareth Mar 17, 2025
3783ae2
Ensure evictProver is based on an unproven checkpoint
nikeshnazareth Mar 17, 2025
7d79ddb
Rename provingDeadling to provingWindow
nikeshnazareth Mar 17, 2025
650d604
Allow publications to fall exactly on period.end
nikeshnazareth Mar 17, 2025
69e54df
Use payPublicationFee transition logic in getCurrentFees
nikeshnazareth Mar 17, 2025
7126c7f
Create claimProvingVacany function
nikeshnazareth Mar 17, 2025
2706bfb
Fix: align IProverManager interface with ProverManager
nikeshnazareth Mar 17, 2025
582f95a
Create mechanism to finalise an old period
nikeshnazareth Mar 17, 2025
00788a7
abstract the logic to update the new period in a private function
ggonzalez94 Mar 17, 2025
a5ff441
make provenHash() and _isClosed view functions
ggonzalez94 Mar 17, 2025
8e8e626
merge if statements into a single require
ggonzalez94 Mar 17, 2025
25aa639
merge from main
ggonzalez94 Mar 17, 2025
e52736f
fix tests and format
ggonzalez94 Mar 17, 2025
c1fd5f2
add more tests
ggonzalez94 Mar 17, 2025
a09a875
Prove publication count (#77)
nikeshnazareth Mar 20, 2025
7023fd9
simplify natspect
ggonzalez94 Mar 21, 2025
3c919fb
more natspec
ggonzalez94 Mar 21, 2025
d6ae41c
refactor into _finalizePeriod
ggonzalez94 Mar 22, 2025
c49375f
store the entire CheckPoint in the CheckPointTracker
ggonzalez94 Mar 22, 2025
89363c8
set provenCheckpoint as private variable
ggonzalez94 Mar 22, 2025
e063209
Remove TransitionProven event from CheckpointTracker
nikeshnazareth Mar 24, 2025
3dc0d08
fmt
nikeshnazareth Mar 24, 2025
885ddbd
Fix typo
nikeshnazareth Mar 24, 2025
bc4ae0d
Fix comment to use maxBidPercentage instead of minUndercutPercentage
nikeshnazareth Mar 24, 2025
5e738ef
Move sufficient-underbid logic into its own function
nikeshnazareth Mar 24, 2025
51a4d46
Rename _finalizePeriod to _closePeriod
nikeshnazareth Mar 24, 2025
224c85a
Pass provingWindow instead of deadline to _closePeriod
nikeshnazareth Mar 24, 2025
485e955
Fix missing semicolon
nikeshnazareth Mar 24, 2025
01f7e9f
Change error message for invalid publication
nikeshnazareth Mar 24, 2025
ff301fd
Pass endDelay instead of endTimestamp to _closePeriod
nikeshnazareth Mar 24, 2025
dce75f7
Fix typo
nikeshnazareth Mar 24, 2025
098c086
Use "past period" to refer to periods that have already ended
nikeshnazareth Mar 24, 2025
e25f01e
Move stake burn logic to finalizePastPeriod
nikeshnazareth Mar 24, 2025
d56f920
Reuse claimProvingVacancy to initialise the contract
nikeshnazareth Mar 24, 2025
f22be22
Allow proofs for period 0
nikeshnazareth Mar 24, 2025
13a0cd1
Bug fix: incorrect variable name
nikeshnazareth Mar 24, 2025
7997304
Reuse named variable instead of magic number in test_withdraw
nikeshnazareth Mar 24, 2025
75c8732
Use getBlockTimestamp() instead of block.timestamp in tests
nikeshnazareth Mar 24, 2025
656e1bb
change isPast variable to isPastDeadline for clarity and avoid variab…
ggonzalez94 Mar 24, 2025
621bfac
Bug fix: calculate stake reward correctly on finalizePastPeriod
ggonzalez94 Mar 24, 2025
7e93ece
use rewardPercentage instead of burnedStakePercentage
ggonzalez94 Mar 24, 2025
3f4dab9
add tests for finalizePastPeriod
ggonzalez94 Mar 24, 2025
20f3172
fmt
ggonzalez94 Mar 24, 2025
29ee81e
add claimProvingVacancy tests
ggonzalez94 Mar 25, 2025
653afa6
reorder tests to match the contract layout
ggonzalez94 Mar 25, 2025
c09ef89
abstract deposit logic into _deposit function for testing
ggonzalez94 Mar 25, 2025
9ed2967
abstract logic to calculate fees and percentages
ggonzalez94 Mar 25, 2025
e846532
more test refactors
ggonzalez94 Mar 25, 2025
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
1 change: 1 addition & 0 deletions documentation/Overall Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ These properties seem like they should be useful for composability. However:

- we have not yet designed any features that rely on them.
- the shared feed undermines the ability to recognise when a publication is no longer required, so <span style="color: orange;">it prevents the use of a ring buffer</span>.
- we cannot compute the number of relevant publications between two publication ids, so we need to pass this as a separate parameter to the proof.

If we do not implement any composability features, we should restore the different publication feeds per rollup so the implementation can be optimised.

Expand Down
48 changes: 33 additions & 15 deletions src/protocol/CheckpointTracker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,67 @@ import {IPublicationFeed} from "./IPublicationFeed.sol";
import {IVerifier} from "./IVerifier.sol";

contract CheckpointTracker is ICheckpointTracker {
/// @notice The hash of the current proven checkpoint representing the latest verified state of the rollup
/// @notice The current proven checkpoint representing the latest verified state of the rollup
/// @dev Previous checkpoints are not stored here but are synchronized to the `SignalService`
/// @dev A checkpoint commitment is any value (typically a state root) that uniquely identifies
/// the state of the rollup at a specific point in time
bytes32 public provenHash;
/// @dev We store the actual checkpoint(not the hash) to avoid race conditions when closing a period or evicting a
/// prover(https://github.com/OpenZeppelin/minimal-rollup/pull/77#discussion_r2002192018)
Checkpoint private _provenCheckpoint;

IPublicationFeed public immutable publicationFeed;

// This would usually be retrieved dynamically as in the current Taiko implementation, but for simplicity we are
// just setting it in the constructor
IVerifier public immutable verifier;
address public proverManager;

/// @param _genesis the checkpoint commitment describing the initial state of the rollup
/// @param _publicationFeed the input data source that updates the state of this rollup
/// @param _verifier a contract that can verify the validity of a transition from one checkpoint to another
constructor(bytes32 _genesis, address _publicationFeed, address _verifier) {
/// @param _proverManager contract responsible for managing the prover auction
constructor(bytes32 _genesis, address _publicationFeed, address _verifier, address _proverManager) {
// set the genesis checkpoint commitment of the rollup - genesis is trusted to be correct
require(_genesis != 0, "genesis checkpoint commitment cannot be 0");

publicationFeed = IPublicationFeed(_publicationFeed);
verifier = IVerifier(_verifier);

proverManager = _proverManager;
Checkpoint memory genesisCheckpoint = Checkpoint({publicationId: 0, commitment: _genesis});
provenHash = keccak256(abi.encode(genesisCheckpoint));
emit CheckpointUpdated(provenHash);
_provenCheckpoint = genesisCheckpoint;
emit CheckpointUpdated(genesisCheckpoint);
}

/// @inheritdoc ICheckpointTracker
function proveTransition(Checkpoint calldata start, Checkpoint calldata end, bytes calldata proof) external {
function proveTransition(
Checkpoint calldata start,
Checkpoint calldata end,
uint256 numPublications,
bytes calldata proof
) external {
require(
proverManager == address(0) || msg.sender == proverManager, "Only the prover manager can call this function"
);

require(end.commitment != 0, "Checkpoint commitment cannot be 0");

bytes32 startCheckpointHash = keccak256(abi.encode(start));
require(startCheckpointHash == provenHash, "Start checkpoint must be the latest proven checkpoint");
require(
start.publicationId == _provenCheckpoint.publicationId && start.commitment == _provenCheckpoint.commitment,
"Start checkpoint must be the latest proven checkpoint"
);

require(start.publicationId < end.publicationId, "End publication must be after the last proven publication");

bytes32 startPublicationHash = publicationFeed.getPublicationHash(start.publicationId);
bytes32 endPublicationHash = publicationFeed.getPublicationHash(end.publicationId);
require(endPublicationHash != 0, "End publication does not exist");

verifier.verifyProof(startPublicationHash, endPublicationHash, start.commitment, end.commitment, proof);
verifier.verifyProof(
startPublicationHash, endPublicationHash, start.commitment, end.commitment, numPublications, proof
);

_provenCheckpoint = end;
emit CheckpointUpdated(end);
}

provenHash = keccak256(abi.encode(end));
emit TransitionProven(start, end);
function getProvenCheckpoint() external view returns (Checkpoint memory) {
return _provenCheckpoint;
}
}
20 changes: 13 additions & 7 deletions src/protocol/ICheckpointTracker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ interface ICheckpointTracker {
}

/// @notice Emitted when the proven checkpoint is updated
/// @param checkpointHash the hash of the last proven checkpoint
event CheckpointUpdated(bytes32 indexed checkpointHash);
/// @param latestCheckpoint the latest proven checkpoint
event CheckpointUpdated(Checkpoint latestCheckpoint);

/// @notice Emitted when a transition is proven
/// @param start the checkpoint before the transition
/// @param end the checkpoint after the transition
event TransitionProven(Checkpoint start, Checkpoint end);
/// @return _ The last proven checkpoint
function getProvenCheckpoint() external view returns (Checkpoint memory);

/// @notice Verifies a transition between two checkpoints. Update the latest `provenCheckpoint` if possible
/// @param start The initial checkpoint before the transition
/// @param end The final checkpoint after the transition
/// @param numPublications The number of publications that need to be processed between the two checkpoints.
/// Note that this is not necessarily (end.publicationId - start.publicationId) because there could be irrelevant
/// publications.
/// @param proof Arbitrary data passed to the `verifier` contract to confirm the transition validity
function proveTransition(Checkpoint calldata start, Checkpoint calldata end, bytes calldata proof) external;
function proveTransition(
Checkpoint calldata start,
Checkpoint calldata end,
uint256 numPublications,
bytes calldata proof
) external;
}
2 changes: 1 addition & 1 deletion src/protocol/IInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
pragma solidity ^0.8.28;

interface IInbox {
function publish(uint256 nBlobs, uint64 anchorBlockId) external;
function publish(uint256 nBlobs, uint64 anchorBlockId) external payable;
}
15 changes: 15 additions & 0 deletions src/protocol/IProposerFees.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IProposerFees {
/// @notice Proposers have to pay a fee for each publication they want to get proven. This should be called only by
/// the Inbox contract.
/// @param proposer The address of the proposer
/// @param isDelayed Whether the publication is a delayed publication
function payPublicationFee(address proposer, bool isDelayed) external payable;

/// @notice Returns the current fees for a period
/// @return fee The fee for a regular publication
/// @return delayedFee The fee for a delayed publication
function getCurrentFees() external view returns (uint256 fee, uint256 delayedFee);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getPublicationFees? or we'll later support getting previous/future fees?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we should support getting fees from other periods? Right now on-chain we don't have a use case that requires knowing the fees from a different period and off-chain actors can always get that from events.
The reason this function currently gets current fees instead of taking a period as an argument is that the Inboxis unaware of the concept of periods. Instead it would have to ask for the current period and then pass it as a parameter

}
61 changes: 61 additions & 0 deletions src/protocol/IProverManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {ICheckpointTracker} from "./ICheckpointTracker.sol";
import {IPublicationFeed} from "./IPublicationFeed.sol";

interface IProverManager {
/// @notice Bid to become the prover for the next period
/// @param offeredFee The fee you are willing to charge for proving each publication
function bid(uint256 offeredFee) external;

/// @notice The current prover can signal exit to eventually pull out their liveness bond.
function exit() external;

/// @notice If there is no active prover, start a new period and become the new prover in the next block
/// @param fee The per-publication fee for the new period
/// @dev Consider the scenario:
/// - a prover has exited or been evicted
/// - no prover has bid on the next period
/// - a publication is made, creating a new period with no prover and no fee
/// At this point it is impossible to outbid the prover because the fee is zero
/// This function allows anyone to start a new period with a new fee. Note that the new prover will still need to
// ensure the previous publications are proven before proving their own. Nevertheless, we start a new period so
// they cannot be evicted based on publications that occurred before they agreed to prove
function claimProvingVacancy(uint256 fee) external;

/// @notice Evicts a prover that has been inactive, marking the prover for slashing
/// @param publicationHeader The publication header that the caller is claiming is too old and hasn't been proven
function evictProver(IPublicationFeed.PublicationHeader calldata publicationHeader) external;

/// @notice Submits a proof.
/// @dev If called after the period is closed( the proof deadline has passed), the caller becomes the prover for the
/// period and some of the original prover's stake is burned
/// @dev In either case the (possibly new) prover gets the fee for all proven publications
/// @param start The initial checkpoint before the transition
/// @param end The final checkpoint after the transition
/// @param firstPub The first publication header in the transition. Note that since checkpoints refer to the
/// publication they follow, this should have an id `start.publicationId + 1`
/// @param lastPub The last publication header in the transition
/// @param numPublications The number of publications to process. This is not implied by the start/end publication
/// ids because the `PublicationFeed` is shared and may contain publications not relevant for this rollup
/// @param proof Arbitrary data passed to the `verifier` contract to confirm the transition validity
/// @param periodId The id of the period for which the proof is submitted
function prove(
ICheckpointTracker.Checkpoint calldata start,
ICheckpointTracker.Checkpoint calldata end,
IPublicationFeed.PublicationHeader calldata firstPub,
IPublicationFeed.PublicationHeader calldata lastPub,
uint256 numPublications,
bytes calldata proof,
uint256 periodId
) external;

/// @notice Returns the stake for a past period to the prover
/// @param periodId The id of the period to finalize
/// @param provenPublication A publication that the caller is claiming has been proven and is after the period end
/// @dev If there is a proven publication after the period, it implies the whole period has been proven.
/// @dev We assume there will always be a suitable proven publication.
function finalizePastPeriod(uint256 periodId, IPublicationFeed.PublicationHeader calldata provenPublication)
external;
}
5 changes: 5 additions & 0 deletions src/protocol/IPublicationFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ interface IPublicationFeed {
/// @notice Returns the next publication's ID.
/// @return _ The next publication ID.
function getNextPublicationId() external view returns (uint256);

/// @notice Validate a publication header against the hash stored in the feed
/// @param header The header to validate
/// @return _ True if the header is valid, false otherwise
function validateHeader(PublicationHeader calldata header) external view returns (bool);
}
1 change: 1 addition & 0 deletions src/protocol/IVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface IVerifier {
bytes32 endPublicationHash,
bytes32 startCheckPoint,
bytes32 endCheckPoint,
uint256 numPublications,
bytes calldata proof
) external;
}
5 changes: 5 additions & 0 deletions src/protocol/PublicationFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,9 @@ contract PublicationFeed is IPublicationFeed {
function getNextPublicationId() external view returns (uint256) {
return publicationHashes.length;
}

/// @inheritdoc IPublicationFeed
function validateHeader(PublicationHeader calldata header) external view returns (bool) {
return keccak256(abi.encode(header)) == publicationHashes[header.id];
}
}
Loading
Loading