Skip to content

Commit 9433d4e

Browse files
committed
feat(poc): decentralized bridge approach witnet#2
1 parent a2240c0 commit 9433d4e

File tree

11 files changed

+690
-283
lines changed

11 files changed

+690
-283
lines changed

contracts/data/WitnetBlocksData.sol

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,18 @@ abstract contract WitnetBlocksData {
1313
0x28b1d7e478138a94698f82768889fd6edf6b777bb6815c200552870d3e78ffb5;
1414

1515
struct Storage {
16-
WitnetV2.Beacon lastBeacon;
16+
uint256 lastBeaconIndex;
17+
uint256 nextBeaconIndex;
18+
uint256 latestBeaconIndex;
19+
mapping (/* beacon index */ uint256 => WitnetV2.Beacon) beacons;
20+
mapping (/* beacon index */ uint256 => uint256) beaconSuccessorOf;
21+
mapping (/* beacon index */ uint256 => BeaconTracks) beaconTracks;
22+
}
23+
24+
struct BeaconTracks {
25+
mapping (bytes32 => bool) disputed;
26+
bytes32[] queries;
27+
uint256 offset;
1728
}
1829

1930
// ================================================================================================
@@ -29,4 +40,8 @@ abstract contract WitnetBlocksData {
2940
}
3041
}
3142

43+
function __tracks_(uint256 beaconIndex) internal view returns (BeaconTracks storage) {
44+
return __blocks().beaconTracks[beaconIndex];
45+
}
46+
3247
}

contracts/data/WitnetRequestBoardV2Data.sol

Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ abstract contract WitnetRequestBoardV2Data {
1414
0xfeed002ff8a708dcba69bac2a8e829fd61fee551b9e9fc0317707d989cb0fe53;
1515

1616
struct Storage {
17-
uint256 nonce;
1817
mapping (address => Escrow) escrows;
19-
mapping (bytes32 => WitnetV2.Query) queries;
18+
mapping (/* queryHash */ bytes32 => WitnetV2.Query) queries;
19+
mapping (/* tallyHash */ bytes32 => Suitor) suitors;
20+
}
21+
22+
struct Suitor {
23+
uint256 index;
24+
bytes32 queryHash;
2025
}
2126

2227
struct Escrow {
@@ -55,55 +60,4 @@ abstract contract WitnetRequestBoardV2Data {
5560
_ptr.slot := _WITNET_BOARD_DATA_SLOTHASH
5661
}
5762
}
58-
59-
/// Gets current status of given query.
60-
function _statusOf(bytes32 queryHash, IWitnetBlocks blocks)
61-
internal view
62-
returns (WitnetV2.QueryStatus)
63-
{
64-
WitnetV2.Query storage __query = __query_(queryHash);
65-
if (__query.reporter != address(0) || __query.disputes.length > 0) {
66-
if (blocks.getLastBeaconIndex() >= __query.epoch) {
67-
return WitnetV2.QueryStatus.Finalized;
68-
} else {
69-
if (__query.disputes.length > 0) {
70-
return WitnetV2.QueryStatus.Disputed;
71-
} else {
72-
return WitnetV2.QueryStatus.Reported;
73-
}
74-
}
75-
} else if (__query.from != address(0)) {
76-
return WitnetV2.checkQueryPostStatus(
77-
__query.epoch,
78-
blocks.getCurrentBeaconIndex()
79-
);
80-
} else {
81-
return WitnetV2.QueryStatus.Void;
82-
}
83-
}
84-
85-
function _statusOfRevertMessage(WitnetV2.QueryStatus queryStatus)
86-
internal pure
87-
returns (string memory)
88-
{
89-
string memory _reason;
90-
if (queryStatus == WitnetV2.QueryStatus.Posted) {
91-
_reason = "Posted";
92-
} else if (queryStatus == WitnetV2.QueryStatus.Reported) {
93-
_reason = "Reported";
94-
} else if (queryStatus == WitnetV2.QueryStatus.Disputed) {
95-
_reason = "Disputed";
96-
} else if (queryStatus == WitnetV2.QueryStatus.Expired) {
97-
_reason = "Expired";
98-
} else if (queryStatus == WitnetV2.QueryStatus.Finalized) {
99-
_reason = "Finalized";
100-
} else {
101-
_reason = "expected";
102-
}
103-
return string(abi.encodePacked(
104-
"WitnetRequestBoardV2Data: not in ",
105-
_reason,
106-
" status"
107-
));
108-
}
10963
}

contracts/impls/core/WitnetBlocksDefault.sol

Lines changed: 187 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)