@@ -27,28 +27,6 @@ import {Memory} from "step/src/Memory.sol";
2727
2828import {IDaveConsensus} from "./IDaveConsensus.sol " ;
2929
30- /// @notice Consensus contract with Dave tournaments.
31- ///
32- /// @notice This contract validates only one application,
33- /// which read inputs from the InputBox contract.
34- ///
35- /// @notice This contract also manages epoch boundaries, which
36- /// are defined in terms of block numbers. We represent them
37- /// as intervals of the form [a,b). They are also identified by
38- /// incremental numbers that start from 0.
39- ///
40- /// @notice Off-chain nodes can listen to `EpochSealed` events
41- /// to know where epochs start and end, and which epochs have been
42- /// settled already and which one is open for challenges still.
43- /// Anyone can settle an epoch by calling `settle`.
44- /// One can also check if it can be settled by calling `canSettle`.
45- ///
46- /// @notice At any given time, there is always one sealed epoch.
47- /// Prior to it, every epoch has been settled.
48- /// After it, the next epoch is accumulating inputs. Once this epoch is settled,
49- /// the accumlating epoch will be sealed, and a new
50- /// accumulating epoch will be created.
51- ///
5230contract DaveConsensus is IDaveConsensus , ERC165 , ApplicationChecker {
5331 using LibMath for uint256 ;
5432 using LibBinaryMerkleTree for bytes ;
@@ -63,6 +41,9 @@ contract DaveConsensus is IDaveConsensus, ERC165, ApplicationChecker {
6341 /// @notice The contract used to instantiate tournaments
6442 ITournamentFactory immutable _TOURNAMENT_FACTORY;
6543
44+ /// @notice The claim staging period
45+ uint256 immutable _CLAIM_STAGING_PERIOD;
46+
6647 /// @notice Deployment block number
6748 uint256 immutable _DEPLOYMENT_BLOCK_NUMBER = block .number ;
6849
@@ -78,6 +59,21 @@ contract DaveConsensus is IDaveConsensus, ERC165, ApplicationChecker {
7859 /// @notice Current sealed epoch tournament
7960 ITournament _tournament;
8061
62+ /// @notice Whether the result of the current sealed epoch tournament is staged
63+ bool _isTournamentResultStaged;
64+
65+ /// @notice The number of the block in which the tournament result was staged
66+ /// @dev Only meaningful if _isTournamentResultStaged is true.
67+ uint256 _stagingBlockNumber;
68+
69+ /// @notice The staged post-epoch machine state hash
70+ /// @dev Only meaningful if _isTournamentResultStaged is true.
71+ Machine.Hash _stagedPostEpochMachineStateHash;
72+
73+ /// @notice The staged post-epoch outputs Merkle root
74+ /// @dev Only meaningful if _isTournamentResultStaged is true.
75+ bytes32 _stagedPostEpochOutputsMerkleRoot;
76+
8177 /// @notice Settled output trees' merkle root hash
8278 mapping (bytes32 => bool ) _outputsMerkleRoots;
8379
@@ -88,13 +84,15 @@ contract DaveConsensus is IDaveConsensus, ERC165, ApplicationChecker {
8884 IInputBox inputBox ,
8985 address appContract ,
9086 ITournamentFactory tournamentFactory ,
91- Machine.Hash initialMachineStateHash
87+ Machine.Hash initialMachineStateHash ,
88+ uint256 claimStagingPeriod
9289 ) {
9390 // Initialize immutable variables
9491 _INPUT_BOX = inputBox;
9592 _APP_CONTRACT = appContract;
9693 _TOURNAMENT_FACTORY = tournamentFactory;
97- emit ConsensusCreation (inputBox, appContract, tournamentFactory);
94+ _CLAIM_STAGING_PERIOD = claimStagingPeriod;
95+ emit ConsensusCreation (inputBox, appContract, tournamentFactory, claimStagingPeriod);
9896
9997 // Initialize first sealed epoch
10098 uint256 inputIndexUpperBound = inputBox.getNumberOfInputs (appContract);
@@ -104,39 +102,102 @@ contract DaveConsensus is IDaveConsensus, ERC165, ApplicationChecker {
104102 emit EpochSealed (0 , 0 , inputIndexUpperBound, initialMachineStateHash, bytes32 (0 ), tournament);
105103 }
106104
107- function canSettle ()
105+ function canStageTournamentResult ()
108106 external
109107 view
110108 override
111- returns (bool isFinished , uint256 epochNumber , Tree.Node winnerCommitment )
109+ returns (
110+ bool isFinished ,
111+ bool isTournamentResultStaged ,
112+ uint256 epochNumber ,
113+ Tree.Node winnerCommitment ,
114+ Machine.Hash winnerPostEpochMachineStateHash
115+ )
112116 {
113- (isFinished, winnerCommitment,) = _tournament.arbitrationResult ();
114117 epochNumber = _epochNumber;
118+ isTournamentResultStaged = _isTournamentResultStaged;
119+ (isFinished, winnerCommitment, winnerPostEpochMachineStateHash) = _tournament.arbitrationResult ();
115120 }
116121
117- function settle (uint256 epochNumber , bytes32 outputsMerkleRoot , bytes32 [] calldata proof )
122+ function stageTournamentResult (uint256 epochNumber , bytes32 outputsMerkleRoot , bytes32 [] calldata proof )
118123 external
119124 override
120125 notForeclosed (_APP_CONTRACT)
121126 {
122127 // Check tournament settlement
123128 require (epochNumber == _epochNumber, IncorrectEpochNumber (epochNumber, _epochNumber));
124129
130+ // Check whether the tournament result is staged
131+ require (! _isTournamentResultStaged, TournamentResultAlreadyStaged ());
132+
125133 // Check tournament finished
126134 (bool isFinished ,, Machine.Hash finalMachineStateHash ) = _tournament.arbitrationResult ();
127135 require (isFinished, TournamentNotFinishedYet ());
128- ITournament oldTournament = _tournament;
129- _tournament = ITournament (address (0 ));
130136
131137 // Check outputs Merkle root
132138 _validateOutputTree (finalMachineStateHash, outputsMerkleRoot, proof);
133139
140+ // Stage tournament result, and store the current block number for
141+ // later checking whether the claim staging period has elapsed
142+ _stagingBlockNumber = block .number ;
143+ _stagedPostEpochMachineStateHash = finalMachineStateHash;
144+ _stagedPostEpochOutputsMerkleRoot = outputsMerkleRoot;
145+ _isTournamentResultStaged = true ;
146+
147+ // Try recovering bond for tournament winner
148+ try _tournament.tryRecoveringBond () {} catch {}
149+
150+ emit EpochStaged (epochNumber, finalMachineStateHash, outputsMerkleRoot);
151+ }
152+
153+ function canAcceptStagedTournamentResult ()
154+ external
155+ view
156+ override
157+ returns (
158+ bool isTournamentResultStaged ,
159+ bool isClaimStagingPeriodOver ,
160+ uint256 epochNumber ,
161+ Machine.Hash stagedPostEpochMachineStateHash ,
162+ bytes32 stagedPostEpochOutputsMerkleRoot
163+ )
164+ {
165+ epochNumber = _epochNumber;
166+ isTournamentResultStaged = _isTournamentResultStaged;
167+ if (_isTournamentResultStaged) {
168+ isClaimStagingPeriodOver = ((block .number - _stagingBlockNumber) >= _CLAIM_STAGING_PERIOD);
169+ stagedPostEpochMachineStateHash = _stagedPostEpochMachineStateHash;
170+ stagedPostEpochOutputsMerkleRoot = _stagedPostEpochOutputsMerkleRoot;
171+ }
172+ }
173+
174+ function acceptStagedTournamentResult (uint256 epochNumber ) external override notForeclosed (_APP_CONTRACT) {
175+ // Check tournament settlement
176+ require (epochNumber == _epochNumber, IncorrectEpochNumber (epochNumber, _epochNumber));
177+
178+ // Check whether the tournament result is staged
179+ require (_isTournamentResultStaged, TournamentResultNotStaged ());
180+
181+ // Check whether the claim staging period has elapsed
182+ {
183+ uint256 numberOfBlocksAfterStaging = block .number - _stagingBlockNumber;
184+ require (
185+ numberOfBlocksAfterStaging >= _CLAIM_STAGING_PERIOD,
186+ ClaimStagingPeriodNotOverYet (numberOfBlocksAfterStaging, _CLAIM_STAGING_PERIOD)
187+ );
188+ }
189+
190+ // Get staged tournament result
191+ Machine.Hash finalMachineStateHash = _stagedPostEpochMachineStateHash;
192+ bytes32 outputsMerkleRoot = _stagedPostEpochOutputsMerkleRoot;
193+
134194 // Seal current accumulating epoch, save settled output tree and machine state hash
135195 _epochNumber++ ;
136196 _inputIndexLowerBound = _inputIndexUpperBound;
137197 _inputIndexUpperBound = _INPUT_BOX.getNumberOfInputs (_APP_CONTRACT);
138198 _outputsMerkleRoots[outputsMerkleRoot] = true ;
139199 _lastFinalizedMachineStateHash = finalMachineStateHash;
200+ _isTournamentResultStaged = false ;
140201
141202 // Start new tournament
142203 _tournament = _TOURNAMENT_FACTORY.instantiate (finalMachineStateHash, this );
@@ -149,8 +210,6 @@ contract DaveConsensus is IDaveConsensus, ERC165, ApplicationChecker {
149210 outputsMerkleRoot,
150211 _tournament
151212 );
152-
153- oldTournament.tryRecoveringBond ();
154213 }
155214
156215 function getCurrentSealedEpoch ()
@@ -161,13 +220,23 @@ contract DaveConsensus is IDaveConsensus, ERC165, ApplicationChecker {
161220 uint256 epochNumber ,
162221 uint256 inputIndexLowerBound ,
163222 uint256 inputIndexUpperBound ,
164- ITournament tournament
223+ ITournament tournament ,
224+ bool isTournamentResultStaged ,
225+ uint256 stagingBlockNumber ,
226+ Machine.Hash stagedPostEpochMachineStateHash ,
227+ bytes32 stagedPostEpochOutputsMerkleRoot
165228 )
166229 {
167230 epochNumber = _epochNumber;
168231 inputIndexLowerBound = _inputIndexLowerBound;
169232 inputIndexUpperBound = _inputIndexUpperBound;
170233 tournament = _tournament;
234+ isTournamentResultStaged = _isTournamentResultStaged;
235+ if (_isTournamentResultStaged) {
236+ stagingBlockNumber = _stagingBlockNumber;
237+ stagedPostEpochMachineStateHash = _stagedPostEpochMachineStateHash;
238+ stagedPostEpochOutputsMerkleRoot = _stagedPostEpochOutputsMerkleRoot;
239+ }
171240 }
172241
173242 function getInputBox () external view override returns (IInputBox) {
@@ -182,6 +251,10 @@ contract DaveConsensus is IDaveConsensus, ERC165, ApplicationChecker {
182251 return _TOURNAMENT_FACTORY;
183252 }
184253
254+ function getClaimStagingPeriod () external view override returns (uint256 ) {
255+ return _CLAIM_STAGING_PERIOD;
256+ }
257+
185258 function provideMerkleRootOfInput (uint256 inputIndexWithinEpoch , bytes calldata input )
186259 external
187260 view
0 commit comments