@@ -14,15 +14,19 @@ contract WitnetBlocksDefault
1414 WitnetBlocksData ,
1515 WitnetUpgradableBase
1616{
17- IWitnetRequestBoardV2 override immutable public board;
17+ using WitnetV2 for WitnetV2.Beacon;
18+
19+ IWitnetRequestBoardV2 immutable public override board;
20+ uint256 immutable internal __genesisIndex;
1821
19- uint256 immutable internal __genesis_index ;
20- bytes32 immutable internal __genesis_root ;
22+ uint256 immutable public override ROLLUP_DEFAULT_PENALTY_WEI ;
23+ uint256 immutable public override ROLLUP_MAX_GAS ;
2124
2225 constructor (
23- uint256 _genesisIndex ,
24- bytes32 _genesisRoot ,
2526 address _counterFactualAddress ,
27+ WitnetV2.Beacon memory _genesis ,
28+ uint256 _rollupDefaultPenaltyWei ,
29+ uint256 _rollupMaxGas ,
2630 bool _upgradable ,
2731 bytes32 _versionTag
2832 )
@@ -32,17 +36,15 @@ contract WitnetBlocksDefault
3236 "io.witnet.proxiable.blocks "
3337 )
3438 {
39+ assert (_counterFactualAddress != address (0 ));
40+ assert (_rollupDefaultPenaltyWei > 0 );
41+ assert (_rollupMaxGas > 0 );
3542 board = IWitnetRequestBoardV2 (_counterFactualAddress);
36- __blocks ().lastBeacon = WitnetV2.Beacon ({
37- index: _genesisIndex,
38- root: _genesisRoot
39- });
40- __genesis_index = _genesisIndex;
41- __genesis_root = _genesisRoot;
42- }
43-
44- function class () virtual override (WitnetUpgradableBase, IWitnetBlocks) external pure returns (bytes4 ) {
45- return type (IWitnetBlocks).interfaceId;
43+ __genesisIndex = _genesis.index;
44+ __blocks ().beacons[__genesisIndex] = _genesis;
45+ __blocks ().lastBeaconIndex = _genesis.index;
46+ ROLLUP_DEFAULT_PENALTY_WEI = _rollupDefaultPenaltyWei;
47+ ROLLUP_MAX_GAS = _rollupMaxGas;
4648 }
4749
4850
@@ -70,17 +72,23 @@ contract WitnetBlocksDefault
7072 }
7173 require (
7274 __proxiable ().implementation != base (),
73- "WitnetBlocks : already initialized "
75+ "WitnetBlocksDefault : already initialized "
7476 );
7577 if (initdata.length > 0 ) {
7678 WitnetV2.Beacon memory _checkpoint = abi.decode (initdata, (WitnetV2.Beacon));
77- uint256 _lastBeaconIndex = __blocks ().lastBeacon.index;
79+ uint256 _lastBeaconIndex = __blocks ().lastBeaconIndex;
80+ uint256 _nextBeaconIndex = __blocks ().nextBeaconIndex;
7881 require (
7982 _checkpoint.index > _lastBeaconIndex,
80- "WitnetBlocksDefault: illegal rollback "
83+ "WitnetBlocksDefault: cannot rollback "
8184 );
82- __blocks ().lastBeacon = _checkpoint;
83- emit Rollup (msg .sender , _checkpoint.index, _lastBeaconIndex);
85+ require (
86+ _nextBeaconIndex == 0 || _checkpoint.index < _nextBeaconIndex,
87+ "WitnetBlocksDefault: pending rollups "
88+ );
89+ __blocks ().lastBeaconIndex = _checkpoint.index;
90+ __blocks ().beacons[_checkpoint.index] = _checkpoint;
91+ emit FastForward (msg .sender , _checkpoint.index, _lastBeaconIndex);
8492 }
8593 __proxiable ().implementation = base ();
8694 emit Upgraded (msg .sender , base (), codehash (), version ());
@@ -99,47 +107,190 @@ contract WitnetBlocksDefault
99107 // ================================================================================================================
100108 // --- Implementation of 'IWitnetBlocks' --------------------------------------------------------------------------
101109
110+ function class () virtual override (WitnetUpgradableBase, IWitnetBlocks) external pure returns (bytes4 ) {
111+ return type (IWitnetBlocks).interfaceId;
112+ }
113+
102114 function genesis ()
103115 virtual override
104116 external view
105117 returns (WitnetV2.Beacon memory )
106118 {
107- return WitnetV2.Beacon ({
108- index: __genesis_index,
109- root: __genesis_root
110- });
119+ return __blocks ().beacons[__genesisIndex];
120+ }
121+
122+ function getBeaconDisputedQueries (uint256 beaconIndex )
123+ virtual override
124+ external view
125+ returns (bytes32 [] memory )
126+ {
127+ return __tracks_ (beaconIndex).queries;
128+ }
129+
130+ function getCurrentBeaconIndex ()
131+ virtual override
132+ public view
133+ returns (uint256 )
134+ {
135+ // solhint-disable not-rely-on-time
136+ return WitnetV2.beaconIndexFromTimestamp (block .timestamp );
137+ }
138+
139+ function getCurrentEpoch ()
140+ virtual override
141+ public view
142+ returns (uint256 )
143+ {
144+ // solhint-disable not-rely-on-time
145+ return WitnetV2.epochFromTimestamp (block .timestamp );
111146 }
112147
113148 function getLastBeacon ()
114149 virtual override
115150 external view
116151 returns (WitnetV2.Beacon memory _beacon )
117152 {
118- return __blocks ().lastBeacon ;
153+ return __blocks ().beacons[ __blocks ().lastBeaconIndex] ;
119154 }
120155
121- function getLastBeaconIndex ()
156+ function getLastBeaconEpoch ()
122157 virtual override
123- external view
158+ external view
124159 returns (uint256 )
125160 {
126- return __blocks ().lastBeacon.index ;
161+ return getLastBeaconIndex () * 10 ;
127162 }
128163
129- function getCurrentBeaconIndex ()
164+ function getLastBeaconIndex ()
130165 virtual override
131- public view
166+ public view
132167 returns (uint256 )
133168 {
134- // solhint-disable not-rely-on-time
135- return WitnetV2.beaconIndexFromTimestamp (block .timestamp );
169+ return __blocks ().lastBeaconIndex;
136170 }
137171
138172 function getNextBeaconIndex ()
139173 virtual override
140- external view
141- returns (uint256 )
174+ external view
175+ returns (uint256 )
176+ {
177+ return __blocks ().nextBeaconIndex;
178+ }
179+
180+ function __insertBeaconSuccessor (uint nextBeaconIndex , uint tallyBeaconIndex )
181+ virtual internal
182+ returns (uint256 )
183+ {
184+ uint _currentSuccessor = __blocks ().beaconSuccessorOf[nextBeaconIndex];
185+ if (_currentSuccessor == 0 ) {
186+ __blocks ().beaconSuccessorOf[nextBeaconIndex] = tallyBeaconIndex;
187+ return tallyBeaconIndex;
188+ } else if (_currentSuccessor >= tallyBeaconIndex) {
189+ __blocks ().beaconSuccessorOf[tallyBeaconIndex] = _currentSuccessor;
190+ return tallyBeaconIndex;
191+ } else {
192+ return __insertBeaconSuccessor (_currentSuccessor, tallyBeaconIndex);
193+ }
194+ }
195+
196+ function disputeQuery (bytes32 queryHash , uint256 tallyBeaconIndex )
197+ virtual override
198+ external
199+ {
200+ require (
201+ msg .sender == address (board),
202+ "WitnetBlocksDefault: unauthorized "
203+ );
204+ if (tallyBeaconIndex > __blocks ().lastBeaconIndex) {
205+ if (__blocks ().nextBeaconIndex > __blocks ().lastBeaconIndex) {
206+ // pending rollup
207+ if (tallyBeaconIndex < __blocks ().nextBeaconIndex) {
208+ __blocks ().beaconSuccessorOf[tallyBeaconIndex] = __blocks ().nextBeaconIndex;
209+ __blocks ().nextBeaconIndex = tallyBeaconIndex;
210+ } else if (tallyBeaconIndex > __blocks ().nextBeaconIndex) {
211+ __blocks ().nextBeaconIndex = __insertBeaconSuccessor (__blocks ().nextBeaconIndex, tallyBeaconIndex);
212+ if (tallyBeaconIndex > __blocks ().latestBeaconIndex) {
213+ __blocks ().latestBeaconIndex = tallyBeaconIndex;
214+ }
215+ }
216+ } else {
217+ // settle next rollup
218+ __blocks ().nextBeaconIndex = tallyBeaconIndex;
219+ __blocks ().latestBeaconIndex = tallyBeaconIndex;
220+ }
221+ BeaconTracks storage __tracks = __tracks_ (tallyBeaconIndex);
222+ if (! __tracks.disputed[queryHash]) {
223+ __tracks.disputed[queryHash] = true ;
224+ __tracks.queries.push (queryHash);
225+ }
226+ } else {
227+ revert ("WitnetBlocksDefault: too late dispute " );
228+ }
229+ }
230+
231+ function rollupTallyHashes (
232+ WitnetV2.FastForward[] calldata ffs ,
233+ bytes32 [] calldata tallyHashes ,
234+ uint256 tallyOffset ,
235+ uint256 tallyLength
236+ )
237+ external
238+ // TODO: modifiers
239+ returns (uint256 weiReward )
142240 {
143- return getCurrentBeaconIndex () + 1 ;
241+ uint _nextBeaconIndex = __blocks ().nextBeaconIndex;
242+ uint _lastBeaconIndex = __blocks ().lastBeaconIndex;
243+ require (
244+ ffs.length >= 1
245+ && ffs[ffs.length - 1 ].next.index <= _nextBeaconIndex,
246+ "WitnetBlocksDefault: misleading rollup "
247+ );
248+ if (_nextBeaconIndex > _lastBeaconIndex) {
249+ WitnetV2.Beacon memory _lastBeacon = __blocks ().beacons[_lastBeaconIndex];
250+ for (uint _ix = 0 ; _ix < ffs.length ; _ix ++ ) {
251+ _lastBeacon = _lastBeacon.verifyFastForward (ffs[_ix ++ ]);
252+ }
253+ emit FastForward (
254+ msg .sender ,
255+ _lastBeacon.index,
256+ _lastBeaconIndex
257+ );
258+ {
259+ __blocks ().beaconSuccessorOf[_lastBeaconIndex] = _lastBeacon.index;
260+ _lastBeaconIndex = _lastBeacon.index;
261+ __blocks ().lastBeaconIndex = _lastBeaconIndex;
262+ __blocks ().beacons[_lastBeaconIndex] = _lastBeacon;
263+ }
264+ }
265+ if (_nextBeaconIndex == _lastBeaconIndex) {
266+ BeaconTracks storage __tracks = __tracks_ (_nextBeaconIndex);
267+ require (
268+ tallyOffset == __tracks.offset
269+ && tallyOffset + tallyLength == tallyHashes.length ,
270+ "WitnetBlocksDefault: out of range "
271+ );
272+ require (
273+ WitnetV2.merkle (tallyHashes) == __blocks ().beacons[_nextBeaconIndex].ddrTallyRoot,
274+ "WitnetBlocksDefault: invalid tallies "
275+ );
276+ uint _maxTallyOffset = tallyOffset + tallyLength;
277+ for (; tallyOffset < _maxTallyOffset; tallyOffset ++ ) {
278+ (bytes32 _queryHash , uint256 _queryStakes ) = board.determineQueryTallyHash (tallyHashes[tallyOffset]);
279+ require (
280+ __tracks.disputed[_queryHash],
281+ "WitnetBlocksDefault: already judged "
282+ );
283+ __tracks.disputed[_queryHash] = false ;
284+ weiReward += _queryStakes;
285+ }
286+ if (tallyOffset == tallyHashes.length ) {
287+ __blocks ().nextBeaconIndex = __blocks ().beaconSuccessorOf[_nextBeaconIndex];
288+ } else {
289+ __tracks.offset = tallyOffset;
290+ }
291+ emit Rollup (msg .sender , _nextBeaconIndex, tallyOffset, weiReward);
292+ } else {
293+ revert ("WitnetBlocksDefault: no pending rollup " );
294+ }
144295 }
145- }
296+ }
0 commit comments