@arbitrum/nitro-contracts 1.0.0-beta.1 → 1.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/package.json +12 -8
- package/src/bridge/IInbox.sol +9 -0
- package/src/bridge/Inbox.sol +19 -39
- package/src/libraries/AdminFallbackProxy.sol +5 -5
- package/src/libraries/MessageTypes.sol +1 -0
- package/src/mocks/InboxStub.sol +4 -0
- package/src/mocks/Simple.sol +30 -0
- package/src/node-interface/NodeInterface.sol +18 -1
- package/src/node-interface/NodeInterfaceDebug.sol +30 -0
- package/src/osp/OneStepProver0.sol +14 -0
- package/src/osp/OneStepProverMath.sol +2 -2
- package/src/precompiles/ArbOwner.sol +3 -0
- package/src/rollup/IRollupCore.sol +26 -2
- package/src/rollup/IRollupEventBridge.sol +17 -0
- package/src/rollup/IRollupLogic.sol +34 -2
- package/src/rollup/RollupCore.sol +2 -2
- package/src/rollup/RollupCreator.sol +5 -15
- package/src/rollup/RollupEventBridge.sol +2 -3
- package/src/rollup/RollupLib.sol +2 -2
- package/src/rollup/RollupUserLogic.sol +7 -3
- package/src/rollup/ValidatorUtils.sol +0 -1
- package/src/rollup/ValidatorWallet.sol +0 -1
- package/src/state/Instructions.sol +2 -0
- package/.prettierrc +0 -5
- package/.solhint.json +0 -18
- package/deploy/BridgeStubCreator.js +0 -10
- package/deploy/HashProofHelper.js +0 -13
- package/deploy/InboxStubCreator.js +0 -17
- package/deploy/OneStepProofEntryCreator.js +0 -19
- package/deploy/OneStepProver0Creator.js +0 -14
- package/deploy/OneStepProverHostIoCreator.js +0 -14
- package/deploy/OneStepProverMathCreator.js +0 -14
- package/deploy/OneStepProverMemoryCreator.js +0 -14
- package/deploy/SequencerInboxStubCreator.js +0 -13
- package/deploy/ValueArrayTesterCreator.js +0 -13
- package/hardhat.config.ts +0 -47
- package/src/mocks/Counter.sol +0 -13
- package/test/contract/arbRollup.spec.ts +0 -869
- package/test/contract/common/challengeLib.ts +0 -43
- package/test/contract/common/globalStateLib.ts +0 -17
- package/test/contract/common/rolluplib.ts +0 -259
- package/test/contract/cryptographyPrimitives.spec.ts +0 -82
- package/test/contract/sequencerInboxForceInclude.spec.ts +0 -516
- package/test/contract/utils.ts +0 -40
- package/test/prover/hash-proofs.ts +0 -75
- package/test/prover/one-step-proof.ts +0 -93
- package/test/prover/proofs/.gitkeep +0 -0
- package/test/prover/value-arrays.ts +0 -11
- package/tsconfig.json +0 -13
@@ -1,869 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* Copyright 2019-2020, Offchain Labs, Inc.
|
3
|
-
*
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
* you may not use this file except in compliance with the License.
|
6
|
-
* You may obtain a copy of the License at
|
7
|
-
*
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
*
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
* See the License for the specific language governing permissions and
|
14
|
-
* limitations under the License.
|
15
|
-
*/
|
16
|
-
|
17
|
-
/* eslint-env node, mocha */
|
18
|
-
import { ethers, run } from "hardhat";
|
19
|
-
import { Signer } from "@ethersproject/abstract-signer";
|
20
|
-
import { BigNumberish, BigNumber } from "@ethersproject/bignumber";
|
21
|
-
import { BytesLike, hexConcat, zeroPad } from "@ethersproject/bytes";
|
22
|
-
import { ContractTransaction } from "@ethersproject/contracts";
|
23
|
-
import { assert, expect } from "chai";
|
24
|
-
import {
|
25
|
-
BridgeCreator__factory,
|
26
|
-
ChallengeManager,
|
27
|
-
ChallengeManager__factory,
|
28
|
-
OneStepProofEntry__factory,
|
29
|
-
OneStepProver0__factory,
|
30
|
-
OneStepProverHostIo__factory,
|
31
|
-
OneStepProverMath__factory,
|
32
|
-
OneStepProverMemory__factory,
|
33
|
-
RollupAdminLogic,
|
34
|
-
RollupAdminLogic__factory,
|
35
|
-
RollupCreator__factory,
|
36
|
-
RollupUserLogic,
|
37
|
-
RollupUserLogic__factory,
|
38
|
-
SequencerInbox,
|
39
|
-
SequencerInbox__factory,
|
40
|
-
} from "../../build/types";
|
41
|
-
import { initializeAccounts } from "./utils";
|
42
|
-
|
43
|
-
import { Node, RollupContract, forceCreateNode, assertionEquals } from "./common/rolluplib";
|
44
|
-
import { RollupLib } from "../../build/types/RollupUserLogic";
|
45
|
-
type AssertionStruct = RollupLib.AssertionStruct;
|
46
|
-
type ExecutionStateStruct = RollupLib.ExecutionStateStruct;
|
47
|
-
import { keccak256 } from "ethers/lib/utils";
|
48
|
-
import { ConfigStruct, RollupCreatedEvent } from "../../build/types/RollupCreator";
|
49
|
-
import { constants } from "ethers";
|
50
|
-
import { blockStateHash, MachineStatus } from "./common/challengeLib";
|
51
|
-
import * as globalStateLib from "./common/globalStateLib";
|
52
|
-
import { RollupChallengeStartedEvent } from "../../build/types/IRollupCore";
|
53
|
-
|
54
|
-
const zerobytes32 = ethers.constants.HashZero;
|
55
|
-
const stakeRequirement = 10;
|
56
|
-
const stakeToken = ethers.constants.AddressZero;
|
57
|
-
const confirmationPeriodBlocks = 100;
|
58
|
-
const minimumAssertionPeriod = 75;
|
59
|
-
const ZERO_ADDR = ethers.constants.AddressZero;
|
60
|
-
const extraChallengeTimeBlocks = 20;
|
61
|
-
const wasmModuleRoot = "0x9900000000000000000000000000000000000000000000000000000000000010";
|
62
|
-
|
63
|
-
// let rollup: RollupContract
|
64
|
-
let rollup: RollupContract;
|
65
|
-
let rollupUser: RollupUserLogic;
|
66
|
-
let rollupAdmin: RollupAdminLogic;
|
67
|
-
let accounts: Signer[];
|
68
|
-
let validators: Signer[];
|
69
|
-
let sequencerInbox: SequencerInbox;
|
70
|
-
let admin: Signer;
|
71
|
-
let sequencer: Signer;
|
72
|
-
let challengeManager: ChallengeManager;
|
73
|
-
|
74
|
-
async function getDefaultConfig(
|
75
|
-
_confirmPeriodBlocks = confirmationPeriodBlocks
|
76
|
-
): Promise<ConfigStruct> {
|
77
|
-
return {
|
78
|
-
baseStake: stakeRequirement,
|
79
|
-
chainId: stakeToken,
|
80
|
-
confirmPeriodBlocks: _confirmPeriodBlocks,
|
81
|
-
extraChallengeTimeBlocks: extraChallengeTimeBlocks,
|
82
|
-
owner: await accounts[0].getAddress(),
|
83
|
-
sequencerInboxMaxTimeVariation: {
|
84
|
-
delayBlocks: (60 * 60 * 24) / 15,
|
85
|
-
futureBlocks: 12,
|
86
|
-
delaySeconds: 60 * 60 * 24,
|
87
|
-
futureSeconds: 60 * 60,
|
88
|
-
},
|
89
|
-
stakeToken: stakeToken,
|
90
|
-
wasmModuleRoot: wasmModuleRoot,
|
91
|
-
loserStakeEscrow: ZERO_ADDR,
|
92
|
-
};
|
93
|
-
}
|
94
|
-
|
95
|
-
const setup = async () => {
|
96
|
-
const accounts = await initializeAccounts();
|
97
|
-
admin = accounts[0];
|
98
|
-
|
99
|
-
const user = accounts[1];
|
100
|
-
|
101
|
-
const val1 = accounts[2];
|
102
|
-
const val2 = accounts[3];
|
103
|
-
const val3 = accounts[4];
|
104
|
-
const val4 = accounts[5];
|
105
|
-
sequencer = accounts[6];
|
106
|
-
|
107
|
-
const oneStep0Fac = (await ethers.getContractFactory(
|
108
|
-
"OneStepProver0"
|
109
|
-
)) as OneStepProver0__factory;
|
110
|
-
const oneStep0 = await oneStep0Fac.deploy();
|
111
|
-
const oneStepMemoryFac = (await ethers.getContractFactory(
|
112
|
-
"OneStepProverMemory"
|
113
|
-
)) as OneStepProverMemory__factory;
|
114
|
-
const oneStepMemory = await oneStepMemoryFac.deploy();
|
115
|
-
const oneStepMathFac = (await ethers.getContractFactory(
|
116
|
-
"OneStepProverMath"
|
117
|
-
)) as OneStepProverMath__factory;
|
118
|
-
const oneStepMath = await oneStepMathFac.deploy();
|
119
|
-
const oneStepHostIoFac = (await ethers.getContractFactory(
|
120
|
-
"OneStepProverHostIo"
|
121
|
-
)) as OneStepProverHostIo__factory;
|
122
|
-
const oneStepHostIo = await oneStepHostIoFac.deploy();
|
123
|
-
|
124
|
-
const oneStepProofEntryFac = (await ethers.getContractFactory(
|
125
|
-
"OneStepProofEntry"
|
126
|
-
)) as OneStepProofEntry__factory;
|
127
|
-
const oneStepProofEntry = await oneStepProofEntryFac.deploy(
|
128
|
-
oneStep0.address,
|
129
|
-
oneStepMemory.address,
|
130
|
-
oneStepMath.address,
|
131
|
-
oneStepHostIo.address
|
132
|
-
);
|
133
|
-
|
134
|
-
const challengeManagerTemplateFac = (await ethers.getContractFactory(
|
135
|
-
"ChallengeManager"
|
136
|
-
)) as ChallengeManager__factory;
|
137
|
-
const challengeManagerTemplate = await challengeManagerTemplateFac.deploy();
|
138
|
-
|
139
|
-
const rollupAdminLogicFac = (await ethers.getContractFactory(
|
140
|
-
"RollupAdminLogic"
|
141
|
-
)) as RollupAdminLogic__factory;
|
142
|
-
const rollupAdminLogicTemplate = await rollupAdminLogicFac.deploy();
|
143
|
-
|
144
|
-
const rollupUserLogicFac = (await ethers.getContractFactory(
|
145
|
-
"RollupUserLogic"
|
146
|
-
)) as RollupUserLogic__factory;
|
147
|
-
const rollupUserLogicTemplate = await rollupUserLogicFac.deploy();
|
148
|
-
|
149
|
-
const bridgeCreatorFac = (await ethers.getContractFactory(
|
150
|
-
"BridgeCreator"
|
151
|
-
)) as BridgeCreator__factory;
|
152
|
-
const bridgeCreator = await bridgeCreatorFac.deploy();
|
153
|
-
|
154
|
-
const rollupCreatorFac = (await ethers.getContractFactory(
|
155
|
-
"RollupCreator"
|
156
|
-
)) as RollupCreator__factory;
|
157
|
-
const rollupCreator = await rollupCreatorFac.deploy();
|
158
|
-
|
159
|
-
await rollupCreator.setTemplates(
|
160
|
-
bridgeCreator.address,
|
161
|
-
oneStepProofEntry.address,
|
162
|
-
challengeManagerTemplate.address,
|
163
|
-
rollupAdminLogicTemplate.address,
|
164
|
-
rollupUserLogicTemplate.address
|
165
|
-
);
|
166
|
-
|
167
|
-
const nonce = await rollupCreator.signer.provider!.getTransactionCount(rollupCreator.address);
|
168
|
-
const expectedRollupAddress = ethers.utils.getContractAddress({
|
169
|
-
from: rollupCreator.address,
|
170
|
-
nonce: nonce + 2,
|
171
|
-
});
|
172
|
-
|
173
|
-
const response = await rollupCreator.createRollup(
|
174
|
-
await getDefaultConfig(),
|
175
|
-
expectedRollupAddress
|
176
|
-
);
|
177
|
-
const rec = await response.wait();
|
178
|
-
|
179
|
-
const rollupCreatedEvent = rollupCreator.interface.parseLog(rec.logs[rec.logs.length - 1])
|
180
|
-
.args as RollupCreatedEvent["args"];
|
181
|
-
|
182
|
-
const rollupAdmin = rollupAdminLogicFac
|
183
|
-
.attach(expectedRollupAddress)
|
184
|
-
.connect(rollupCreator.signer);
|
185
|
-
const rollupUser = rollupUserLogicFac.attach(expectedRollupAddress).connect(user);
|
186
|
-
|
187
|
-
await rollupAdmin.setValidator(
|
188
|
-
[await val1.getAddress(), await val2.getAddress(), await val3.getAddress()],
|
189
|
-
[true, true, true]
|
190
|
-
);
|
191
|
-
|
192
|
-
await rollupAdmin.setIsBatchPoster(await sequencer.getAddress(), true);
|
193
|
-
|
194
|
-
sequencerInbox = ((await ethers.getContractFactory(
|
195
|
-
"SequencerInbox"
|
196
|
-
)) as SequencerInbox__factory).attach(rollupCreatedEvent.sequencerInbox);
|
197
|
-
|
198
|
-
challengeManager = ((await ethers.getContractFactory(
|
199
|
-
"ChallengeManager"
|
200
|
-
)) as ChallengeManager__factory).attach(await rollupUser.challengeManager());
|
201
|
-
|
202
|
-
return {
|
203
|
-
admin,
|
204
|
-
user,
|
205
|
-
|
206
|
-
rollupAdmin,
|
207
|
-
rollupUser,
|
208
|
-
|
209
|
-
validators: [val1, val2, val3, val4],
|
210
|
-
|
211
|
-
rollupAdminLogicTemplate,
|
212
|
-
rollupUserLogicTemplate,
|
213
|
-
blockChallengeFactory: challengeManagerTemplateFac,
|
214
|
-
rollupEventBridge: await rollupAdmin.rollupEventBridge(),
|
215
|
-
outbox: await rollupAdmin.outbox(),
|
216
|
-
sequencerInbox: rollupCreatedEvent.sequencerInbox,
|
217
|
-
delayedBridge: rollupCreatedEvent.delayedBridge,
|
218
|
-
};
|
219
|
-
};
|
220
|
-
|
221
|
-
async function tryAdvanceChain(blocks: number): Promise<void> {
|
222
|
-
try {
|
223
|
-
for (let i = 0; i < blocks; i++) {
|
224
|
-
await ethers.provider.send("evm_mine", []);
|
225
|
-
}
|
226
|
-
} catch (e) {
|
227
|
-
// EVM mine failed. Try advancing the chain by sending txes if the node
|
228
|
-
// is in dev mode and mints blocks when txes are sent
|
229
|
-
for (let i = 0; i < blocks; i++) {
|
230
|
-
const tx = await accounts[0].sendTransaction({
|
231
|
-
value: 0,
|
232
|
-
to: await accounts[0].getAddress(),
|
233
|
-
});
|
234
|
-
await tx.wait();
|
235
|
-
}
|
236
|
-
}
|
237
|
-
}
|
238
|
-
|
239
|
-
async function advancePastAssertion(blockProposed: number): Promise<void> {
|
240
|
-
await tryAdvanceChain(blockProposed + confirmationPeriodBlocks);
|
241
|
-
}
|
242
|
-
|
243
|
-
function newRandomExecutionState() {
|
244
|
-
const blockHash = keccak256(ethers.utils.randomBytes(32));
|
245
|
-
const sendRoot = keccak256(ethers.utils.randomBytes(32));
|
246
|
-
const machineStatus = 1;
|
247
|
-
|
248
|
-
return newExecutionState(blockHash, sendRoot, 1, 0, machineStatus);
|
249
|
-
}
|
250
|
-
|
251
|
-
function newExecutionState(
|
252
|
-
blockHash: string,
|
253
|
-
sendRoot: string,
|
254
|
-
inboxPosition: BigNumberish,
|
255
|
-
positionInMessage: BigNumberish,
|
256
|
-
machineStatus: BigNumberish
|
257
|
-
): ExecutionStateStruct {
|
258
|
-
return {
|
259
|
-
globalState: {
|
260
|
-
bytes32Vals: [blockHash, sendRoot],
|
261
|
-
u64Vals: [inboxPosition, positionInMessage],
|
262
|
-
},
|
263
|
-
machineStatus,
|
264
|
-
};
|
265
|
-
}
|
266
|
-
|
267
|
-
function newRandomAssertion(prevExecutionState: ExecutionStateStruct): AssertionStruct {
|
268
|
-
return {
|
269
|
-
beforeState: prevExecutionState,
|
270
|
-
afterState: newRandomExecutionState(),
|
271
|
-
numBlocks: 10,
|
272
|
-
};
|
273
|
-
}
|
274
|
-
|
275
|
-
async function makeSimpleNode(
|
276
|
-
rollup: RollupContract,
|
277
|
-
sequencerInbox: SequencerInbox,
|
278
|
-
parentNode: {
|
279
|
-
assertion: { afterState: ExecutionStateStruct };
|
280
|
-
nodeNum: number;
|
281
|
-
nodeHash: BytesLike;
|
282
|
-
inboxMaxCount: BigNumber;
|
283
|
-
},
|
284
|
-
siblingNode?: Node,
|
285
|
-
prevNode?: Node,
|
286
|
-
stakeToAdd?: BigNumber
|
287
|
-
): Promise<{ tx: ContractTransaction; node: Node }> {
|
288
|
-
const staker = await rollup.rollup.getStaker(await rollup.rollup.signer.getAddress());
|
289
|
-
|
290
|
-
const assertion = newRandomAssertion(parentNode.assertion.afterState);
|
291
|
-
const { tx, node, expectedNewNodeHash } = await rollup.stakeOnNewNode(
|
292
|
-
sequencerInbox,
|
293
|
-
parentNode,
|
294
|
-
assertion,
|
295
|
-
siblingNode,
|
296
|
-
stakeToAdd
|
297
|
-
);
|
298
|
-
|
299
|
-
expect(assertionEquals(assertion, node.assertion), "unexpected assertion").to.be.true;
|
300
|
-
assert.equal(node.nodeNum, (prevNode || siblingNode || parentNode).nodeNum + 1);
|
301
|
-
assert.equal(node.nodeHash, expectedNewNodeHash);
|
302
|
-
|
303
|
-
if (stakeToAdd) {
|
304
|
-
const stakerAfter = await rollup.rollup.getStaker(await rollup.rollup.signer.getAddress());
|
305
|
-
expect(stakerAfter.latestStakedNode.toNumber()).to.eq(node.nodeNum);
|
306
|
-
expect(stakerAfter.amountStaked.toString()).to.eq(
|
307
|
-
staker.amountStaked.add(stakeToAdd).toString()
|
308
|
-
);
|
309
|
-
}
|
310
|
-
return { tx, node };
|
311
|
-
}
|
312
|
-
|
313
|
-
const makeSends = (count: number, batchStart = 0) => {
|
314
|
-
return [...Array(count)].map((_, i) =>
|
315
|
-
hexConcat([[0], zeroPad([i + batchStart], 32), zeroPad([0], 32), zeroPad([1], 32)])
|
316
|
-
);
|
317
|
-
};
|
318
|
-
|
319
|
-
let prevNode: Node;
|
320
|
-
const prevNodes: Node[] = [];
|
321
|
-
|
322
|
-
function updatePrevNode(node: Node) {
|
323
|
-
prevNode = node;
|
324
|
-
prevNodes.push(node);
|
325
|
-
}
|
326
|
-
|
327
|
-
describe("ArbRollup", () => {
|
328
|
-
it("should deploy contracts", async function () {
|
329
|
-
accounts = await initializeAccounts();
|
330
|
-
|
331
|
-
await run("deploy", { tags: "test" });
|
332
|
-
});
|
333
|
-
|
334
|
-
it("should initialize", async function () {
|
335
|
-
const {
|
336
|
-
rollupAdmin: rollupAdminContract,
|
337
|
-
rollupUser: rollupUserContract,
|
338
|
-
user: userI,
|
339
|
-
admin: adminI,
|
340
|
-
validators: validatorsI,
|
341
|
-
} = await setup();
|
342
|
-
rollupAdmin = rollupAdminContract;
|
343
|
-
rollupUser = rollupUserContract;
|
344
|
-
admin = adminI;
|
345
|
-
validators = validatorsI;
|
346
|
-
rollup = new RollupContract(rollupUser.connect(validators[0]));
|
347
|
-
});
|
348
|
-
|
349
|
-
it("should only initialize once", async function () {
|
350
|
-
await expect(
|
351
|
-
rollupAdmin.initialize(await getDefaultConfig(), {
|
352
|
-
challengeManager: constants.AddressZero,
|
353
|
-
delayedBridge: constants.AddressZero,
|
354
|
-
outbox: constants.AddressZero,
|
355
|
-
rollupAdminLogic: constants.AddressZero,
|
356
|
-
rollupEventBridge: constants.AddressZero,
|
357
|
-
rollupUserLogic: constants.AddressZero,
|
358
|
-
sequencerInbox: constants.AddressZero,
|
359
|
-
})
|
360
|
-
).to.be.revertedWith("Initializable: contract is already initialized");
|
361
|
-
});
|
362
|
-
|
363
|
-
it("should place stake on new node", async function () {
|
364
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
365
|
-
|
366
|
-
const initNode: {
|
367
|
-
assertion: { afterState: ExecutionStateStruct };
|
368
|
-
nodeNum: number;
|
369
|
-
nodeHash: BytesLike;
|
370
|
-
inboxMaxCount: BigNumber;
|
371
|
-
} = {
|
372
|
-
assertion: {
|
373
|
-
afterState: {
|
374
|
-
globalState: {
|
375
|
-
bytes32Vals: [zerobytes32, zerobytes32],
|
376
|
-
u64Vals: [0, 0],
|
377
|
-
},
|
378
|
-
machineStatus: MachineStatus.FINISHED,
|
379
|
-
},
|
380
|
-
},
|
381
|
-
inboxMaxCount: BigNumber.from(1),
|
382
|
-
nodeHash: zerobytes32,
|
383
|
-
nodeNum: 0,
|
384
|
-
};
|
385
|
-
|
386
|
-
const stake = await rollup.currentRequiredStake();
|
387
|
-
const { node } = await makeSimpleNode(
|
388
|
-
rollup,
|
389
|
-
sequencerInbox,
|
390
|
-
initNode,
|
391
|
-
undefined,
|
392
|
-
undefined,
|
393
|
-
stake
|
394
|
-
);
|
395
|
-
updatePrevNode(node);
|
396
|
-
});
|
397
|
-
|
398
|
-
it("should let a new staker place on existing node", async function () {
|
399
|
-
const stake = await rollup.currentRequiredStake();
|
400
|
-
await rollupUser
|
401
|
-
.connect(validators[2])
|
402
|
-
.newStakeOnExistingNode(1, prevNode.nodeHash, { value: stake });
|
403
|
-
});
|
404
|
-
|
405
|
-
it("should move stake to a new node", async function () {
|
406
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
407
|
-
const { node } = await makeSimpleNode(rollup, sequencerInbox, prevNode);
|
408
|
-
updatePrevNode(node);
|
409
|
-
});
|
410
|
-
|
411
|
-
it("should let the second staker place on the new node", async function () {
|
412
|
-
await rollup.connect(validators[2]).stakeOnExistingNode(2, prevNode.nodeHash);
|
413
|
-
});
|
414
|
-
|
415
|
-
it("should confirm node", async function () {
|
416
|
-
await tryAdvanceChain(confirmationPeriodBlocks * 2);
|
417
|
-
|
418
|
-
await rollup.confirmNextNode(prevNodes[0]);
|
419
|
-
});
|
420
|
-
|
421
|
-
it("should confirm next node", async function () {
|
422
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
423
|
-
await rollup.confirmNextNode(prevNodes[1]);
|
424
|
-
});
|
425
|
-
|
426
|
-
let challengedNode: Node;
|
427
|
-
let validNode: Node;
|
428
|
-
it("should let the first staker make another node", async function () {
|
429
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
430
|
-
const { node } = await makeSimpleNode(rollup, sequencerInbox, prevNode);
|
431
|
-
challengedNode = node;
|
432
|
-
validNode = node;
|
433
|
-
});
|
434
|
-
|
435
|
-
let challengerNode: Node;
|
436
|
-
it("should let the second staker make a conflicting node", async function () {
|
437
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
438
|
-
const { node } = await makeSimpleNode(
|
439
|
-
rollup.connect(validators[2]),
|
440
|
-
sequencerInbox,
|
441
|
-
prevNode,
|
442
|
-
validNode
|
443
|
-
);
|
444
|
-
challengerNode = node;
|
445
|
-
});
|
446
|
-
|
447
|
-
it("should fail to confirm first staker node", async function () {
|
448
|
-
await advancePastAssertion(challengedNode.proposedBlock);
|
449
|
-
await expect(rollup.confirmNextNode(validNode)).to.be.revertedWith("NOT_ALL_STAKED");
|
450
|
-
});
|
451
|
-
|
452
|
-
let challengeIndex: number;
|
453
|
-
it("should initiate a challenge", async function () {
|
454
|
-
const tx = rollup.createChallenge(
|
455
|
-
await validators[0].getAddress(),
|
456
|
-
await validators[2].getAddress(),
|
457
|
-
challengedNode,
|
458
|
-
challengerNode
|
459
|
-
);
|
460
|
-
const receipt = await (await tx).wait();
|
461
|
-
const ev = rollup.rollup.interface.parseLog(receipt.logs![receipt.logs!.length - 1]);
|
462
|
-
expect(ev.name).to.equal("RollupChallengeStarted");
|
463
|
-
|
464
|
-
const parsedEv = ev.args as RollupChallengeStartedEvent["args"];
|
465
|
-
challengeIndex = parsedEv.challengeIndex.toNumber();
|
466
|
-
});
|
467
|
-
|
468
|
-
it("should make a new node", async function () {
|
469
|
-
const { node } = await makeSimpleNode(
|
470
|
-
rollup,
|
471
|
-
sequencerInbox,
|
472
|
-
validNode,
|
473
|
-
undefined,
|
474
|
-
challengerNode
|
475
|
-
);
|
476
|
-
challengedNode = node;
|
477
|
-
});
|
478
|
-
|
479
|
-
it("new staker should make a conflicting node", async function () {
|
480
|
-
const stake = await rollup.currentRequiredStake();
|
481
|
-
await rollup.rollup
|
482
|
-
.connect(validators[1])
|
483
|
-
.newStakeOnExistingNode(3, validNode.nodeHash, { value: stake.add(50) });
|
484
|
-
|
485
|
-
const { node } = await makeSimpleNode(
|
486
|
-
rollup.connect(validators[1]),
|
487
|
-
sequencerInbox,
|
488
|
-
validNode,
|
489
|
-
challengedNode
|
490
|
-
);
|
491
|
-
challengerNode = node;
|
492
|
-
});
|
493
|
-
|
494
|
-
it("asserter should win via timeout", async function () {
|
495
|
-
await advancePastAssertion(challengedNode.proposedBlock);
|
496
|
-
await challengeManager.connect(validators[0]).timeout(challengeIndex);
|
497
|
-
});
|
498
|
-
|
499
|
-
it("confirm first staker node", async function () {
|
500
|
-
await rollup.confirmNextNode(validNode);
|
501
|
-
});
|
502
|
-
|
503
|
-
it("should reject out of order second node", async function () {
|
504
|
-
await rollup.rejectNextNode(stakeToken);
|
505
|
-
});
|
506
|
-
|
507
|
-
it("should initiate another challenge", async function () {
|
508
|
-
const tx = rollup.createChallenge(
|
509
|
-
await validators[0].getAddress(),
|
510
|
-
await validators[1].getAddress(),
|
511
|
-
challengedNode,
|
512
|
-
challengerNode
|
513
|
-
);
|
514
|
-
const receipt = await (await tx).wait();
|
515
|
-
const ev = rollup.rollup.interface.parseLog(receipt.logs![receipt.logs!.length - 1]);
|
516
|
-
expect(ev.name).to.equal("RollupChallengeStarted");
|
517
|
-
const parsedEv = ev.args as RollupChallengeStartedEvent["args"];
|
518
|
-
challengeIndex = parsedEv.challengeIndex.toNumber();
|
519
|
-
|
520
|
-
await expect(
|
521
|
-
rollup.rollup.completeChallenge(
|
522
|
-
challengeIndex,
|
523
|
-
await sequencer.getAddress(),
|
524
|
-
await validators[3].getAddress()
|
525
|
-
)
|
526
|
-
).to.be.revertedWith("WRONG_SENDER");
|
527
|
-
});
|
528
|
-
|
529
|
-
it("challenger should reply in challenge", async function () {
|
530
|
-
const seg0 = blockStateHash(
|
531
|
-
BigNumber.from(challengerNode.assertion.beforeState.machineStatus),
|
532
|
-
globalStateLib.hash(challengerNode.assertion.beforeState.globalState)
|
533
|
-
);
|
534
|
-
|
535
|
-
const seg1 = blockStateHash(
|
536
|
-
BigNumber.from(challengedNode.assertion.afterState.machineStatus),
|
537
|
-
globalStateLib.hash(challengedNode.assertion.afterState.globalState)
|
538
|
-
);
|
539
|
-
await challengeManager.connect(validators[1]).bisectExecution(
|
540
|
-
challengeIndex,
|
541
|
-
{
|
542
|
-
challengePosition: BigNumber.from(0),
|
543
|
-
oldSegments: [seg0, seg1],
|
544
|
-
oldSegmentsLength: BigNumber.from(challengedNode.assertion.numBlocks),
|
545
|
-
oldSegmentsStart: 0,
|
546
|
-
},
|
547
|
-
[
|
548
|
-
seg0,
|
549
|
-
zerobytes32,
|
550
|
-
zerobytes32,
|
551
|
-
zerobytes32,
|
552
|
-
zerobytes32,
|
553
|
-
zerobytes32,
|
554
|
-
zerobytes32,
|
555
|
-
zerobytes32,
|
556
|
-
zerobytes32,
|
557
|
-
zerobytes32,
|
558
|
-
zerobytes32,
|
559
|
-
]
|
560
|
-
);
|
561
|
-
});
|
562
|
-
|
563
|
-
it("challenger should win via timeout", async function () {
|
564
|
-
await advancePastAssertion(challengedNode.proposedBlock);
|
565
|
-
await challengeManager.timeout(challengeIndex);
|
566
|
-
});
|
567
|
-
|
568
|
-
it("should reject out of order second node", async function () {
|
569
|
-
await rollup.rejectNextNode(await validators[1].getAddress());
|
570
|
-
});
|
571
|
-
|
572
|
-
it("confirm next node", async function () {
|
573
|
-
await tryAdvanceChain(confirmationPeriodBlocks);
|
574
|
-
await rollup.confirmNextNode(challengerNode);
|
575
|
-
});
|
576
|
-
|
577
|
-
it("should add and remove stakes correctly", async function () {
|
578
|
-
/*
|
579
|
-
RollupUser functions that alter stake and their respective Core logic
|
580
|
-
|
581
|
-
user: newStake
|
582
|
-
core: createNewStake
|
583
|
-
|
584
|
-
user: addToDeposit
|
585
|
-
core: increaseStakeBy
|
586
|
-
|
587
|
-
user: reduceDeposit
|
588
|
-
core: reduceStakeTo
|
589
|
-
|
590
|
-
user: returnOldDeposit
|
591
|
-
core: withdrawStaker
|
592
|
-
|
593
|
-
user: withdrawStakerFunds
|
594
|
-
core: withdrawFunds
|
595
|
-
*/
|
596
|
-
|
597
|
-
const initialStake = await rollup.rollup.amountStaked(await validators[1].getAddress());
|
598
|
-
|
599
|
-
await rollup.connect(validators[1]).reduceDeposit(initialStake);
|
600
|
-
|
601
|
-
await expect(
|
602
|
-
rollup.connect(validators[1]).reduceDeposit(initialStake.add(1))
|
603
|
-
).to.be.revertedWith("TOO_LITTLE_STAKE");
|
604
|
-
|
605
|
-
await rollup
|
606
|
-
.connect(validators[1])
|
607
|
-
.addToDeposit(await validators[1].getAddress(), { value: 5 });
|
608
|
-
|
609
|
-
await rollup.connect(validators[1]).reduceDeposit(5);
|
610
|
-
|
611
|
-
const prevBalance = await validators[1].getBalance();
|
612
|
-
const prevWithdrawablefunds = await rollup.rollup.withdrawableFunds(
|
613
|
-
await validators[1].getAddress()
|
614
|
-
);
|
615
|
-
|
616
|
-
const tx = await rollup.rollup
|
617
|
-
.connect(validators[1])
|
618
|
-
.withdrawStakerFunds(await validators[1].getAddress());
|
619
|
-
const receipt = await tx.wait();
|
620
|
-
const gasPaid = receipt.gasUsed.mul(receipt.effectiveGasPrice);
|
621
|
-
|
622
|
-
const postBalance = await validators[1].getBalance();
|
623
|
-
const postWithdrawablefunds = await rollup.rollup.withdrawableFunds(
|
624
|
-
await validators[1].getAddress()
|
625
|
-
);
|
626
|
-
|
627
|
-
expect(postWithdrawablefunds).to.equal(0);
|
628
|
-
expect(postBalance.add(gasPaid)).to.equal(prevBalance.add(prevWithdrawablefunds));
|
629
|
-
|
630
|
-
// this gets deposit and removes staker
|
631
|
-
await rollup.rollup.connect(validators[1]).returnOldDeposit(await validators[1].getAddress());
|
632
|
-
// all stake is now removed
|
633
|
-
});
|
634
|
-
|
635
|
-
it("should allow removing zombies", async function () {
|
636
|
-
const zombieCount = (await rollup.rollup.connect(validators[2]).zombieCount()).toNumber();
|
637
|
-
for (let i = 0; i < zombieCount; i++) {
|
638
|
-
await rollup.rollup.connect(validators[2]).removeZombie(0, 1024);
|
639
|
-
}
|
640
|
-
});
|
641
|
-
|
642
|
-
it("should pause the contracts then resume", async function () {
|
643
|
-
const prevIsPaused = await rollup.rollup.paused();
|
644
|
-
expect(prevIsPaused).to.equal(false);
|
645
|
-
|
646
|
-
await rollupAdmin.pause();
|
647
|
-
|
648
|
-
const postIsPaused = await rollup.rollup.paused();
|
649
|
-
expect(postIsPaused).to.equal(true);
|
650
|
-
|
651
|
-
await expect(
|
652
|
-
rollup.connect(validators[1]).addToDeposit(await validators[1].getAddress(), { value: 5 })
|
653
|
-
).to.be.revertedWith("Pausable: paused");
|
654
|
-
|
655
|
-
await rollupAdmin.resume();
|
656
|
-
});
|
657
|
-
|
658
|
-
it("should allow admin to alter rollup while paused", async function () {
|
659
|
-
const prevLatestConfirmed = await rollup.rollup.latestConfirmed();
|
660
|
-
expect(prevLatestConfirmed.toNumber()).to.equal(6);
|
661
|
-
// prevNode is prevLatestConfirmed
|
662
|
-
prevNode = challengerNode;
|
663
|
-
|
664
|
-
const stake = await rollup.currentRequiredStake();
|
665
|
-
|
666
|
-
const { node: node1 } = await makeSimpleNode(
|
667
|
-
rollup,
|
668
|
-
sequencerInbox,
|
669
|
-
prevNode,
|
670
|
-
undefined,
|
671
|
-
undefined,
|
672
|
-
stake
|
673
|
-
);
|
674
|
-
const node1Num = await rollup.rollup.latestNodeCreated();
|
675
|
-
expect(node1Num.toNumber(), "node1num").to.eq(node1.nodeNum);
|
676
|
-
|
677
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
678
|
-
|
679
|
-
const { node: node2 } = await makeSimpleNode(
|
680
|
-
rollup.connect(validators[2]),
|
681
|
-
sequencerInbox,
|
682
|
-
prevNode,
|
683
|
-
node1,
|
684
|
-
undefined,
|
685
|
-
stake
|
686
|
-
);
|
687
|
-
const node2Num = await rollup.rollup.latestNodeCreated();
|
688
|
-
expect(node2Num.toNumber(), "node2num").to.eq(node2.nodeNum);
|
689
|
-
|
690
|
-
const tx = await rollup.createChallenge(
|
691
|
-
await validators[0].getAddress(),
|
692
|
-
await validators[2].getAddress(),
|
693
|
-
node1,
|
694
|
-
node2
|
695
|
-
);
|
696
|
-
const receipt = await tx.wait();
|
697
|
-
const ev = rollup.rollup.interface.parseLog(receipt.logs![receipt.logs!.length - 1]);
|
698
|
-
expect(ev.name).to.equal("RollupChallengeStarted");
|
699
|
-
const parsedEv = ev.args as RollupChallengeStartedEvent["args"];
|
700
|
-
challengeIndex = parsedEv.challengeIndex.toNumber();
|
701
|
-
|
702
|
-
expect(await challengeManager.currentResponder(challengeIndex), "turn challenger").to.eq(
|
703
|
-
await validators[2].getAddress()
|
704
|
-
);
|
705
|
-
|
706
|
-
await expect(
|
707
|
-
rollupAdmin.forceResolveChallenge(
|
708
|
-
[await validators[0].getAddress()],
|
709
|
-
[await validators[2].getAddress()]
|
710
|
-
),
|
711
|
-
"force resolve"
|
712
|
-
).to.be.revertedWith("Pausable: not paused");
|
713
|
-
|
714
|
-
await expect(
|
715
|
-
rollup.createChallenge(
|
716
|
-
await validators[0].getAddress(),
|
717
|
-
await validators[2].getAddress(),
|
718
|
-
node1,
|
719
|
-
node2
|
720
|
-
),
|
721
|
-
"create challenge"
|
722
|
-
).to.be.revertedWith("IN_CHAL");
|
723
|
-
|
724
|
-
await rollupAdmin.pause();
|
725
|
-
|
726
|
-
await rollupAdmin.forceResolveChallenge(
|
727
|
-
[await validators[0].getAddress()],
|
728
|
-
[await validators[2].getAddress()]
|
729
|
-
);
|
730
|
-
|
731
|
-
// challenge should have been destroyed
|
732
|
-
expect(await challengeManager.currentResponder(challengeIndex), "turn reset").to.equal(
|
733
|
-
constants.AddressZero
|
734
|
-
);
|
735
|
-
|
736
|
-
const challengeA = await rollupAdmin.currentChallenge(await validators[0].getAddress());
|
737
|
-
const challengeB = await rollupAdmin.currentChallenge(await validators[2].getAddress());
|
738
|
-
|
739
|
-
expect(challengeA).to.equal(ZERO_ADDR);
|
740
|
-
expect(challengeB).to.equal(ZERO_ADDR);
|
741
|
-
|
742
|
-
await rollupAdmin.forceRefundStaker([
|
743
|
-
await validators[0].getAddress(),
|
744
|
-
await validators[2].getAddress(),
|
745
|
-
]);
|
746
|
-
|
747
|
-
const adminAssertion = newRandomAssertion(prevNode.assertion.afterState);
|
748
|
-
const { node: forceCreatedNode1 } = await forceCreateNode(
|
749
|
-
rollupAdmin,
|
750
|
-
sequencerInbox,
|
751
|
-
prevNode,
|
752
|
-
adminAssertion,
|
753
|
-
node2
|
754
|
-
);
|
755
|
-
expect(assertionEquals(forceCreatedNode1.assertion, adminAssertion), "assertion error").to.be
|
756
|
-
.true;
|
757
|
-
|
758
|
-
const adminNodeNum = await rollup.rollup.latestNodeCreated();
|
759
|
-
const midLatestConfirmed = await rollup.rollup.latestConfirmed();
|
760
|
-
expect(midLatestConfirmed.toNumber()).to.equal(6);
|
761
|
-
|
762
|
-
expect(adminNodeNum.toNumber()).to.equal(node2Num.toNumber() + 1);
|
763
|
-
|
764
|
-
const adminAssertion2 = newRandomAssertion(prevNode.assertion.afterState);
|
765
|
-
const { node: forceCreatedNode2 } = await forceCreateNode(
|
766
|
-
rollupAdmin,
|
767
|
-
sequencerInbox,
|
768
|
-
prevNode,
|
769
|
-
adminAssertion2,
|
770
|
-
forceCreatedNode1
|
771
|
-
);
|
772
|
-
|
773
|
-
const postLatestCreated = await rollup.rollup.latestNodeCreated();
|
774
|
-
|
775
|
-
await rollupAdmin.forceConfirmNode(
|
776
|
-
adminNodeNum,
|
777
|
-
adminAssertion.afterState.globalState.bytes32Vals[0],
|
778
|
-
adminAssertion.afterState.globalState.bytes32Vals[1]
|
779
|
-
);
|
780
|
-
|
781
|
-
const postLatestConfirmed = await rollup.rollup.latestConfirmed();
|
782
|
-
expect(postLatestCreated).to.equal(adminNodeNum.add(1));
|
783
|
-
expect(postLatestConfirmed).to.equal(adminNodeNum);
|
784
|
-
|
785
|
-
await rollupAdmin.resume();
|
786
|
-
|
787
|
-
// should create node after resuming
|
788
|
-
|
789
|
-
prevNode = forceCreatedNode1;
|
790
|
-
|
791
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
792
|
-
|
793
|
-
await expect(
|
794
|
-
makeSimpleNode(
|
795
|
-
rollup.connect(validators[2]),
|
796
|
-
sequencerInbox,
|
797
|
-
prevNode,
|
798
|
-
undefined,
|
799
|
-
forceCreatedNode2,
|
800
|
-
stake
|
801
|
-
)
|
802
|
-
).to.be.revertedWith("STAKER_IS_ZOMBIE");
|
803
|
-
|
804
|
-
await expect(
|
805
|
-
makeSimpleNode(rollup.connect(validators[2]), sequencerInbox, prevNode)
|
806
|
-
).to.be.revertedWith("NOT_STAKED");
|
807
|
-
|
808
|
-
await rollup.rollup.connect(validators[2]).removeOldZombies(0);
|
809
|
-
|
810
|
-
await makeSimpleNode(
|
811
|
-
rollup.connect(validators[2]),
|
812
|
-
sequencerInbox,
|
813
|
-
prevNode,
|
814
|
-
undefined,
|
815
|
-
forceCreatedNode2,
|
816
|
-
stake
|
817
|
-
);
|
818
|
-
});
|
819
|
-
|
820
|
-
it("should initialize a fresh rollup", async function () {
|
821
|
-
const {
|
822
|
-
rollupAdmin: rollupAdminContract,
|
823
|
-
rollupUser: rollupUserContract,
|
824
|
-
user: userI,
|
825
|
-
admin: adminI,
|
826
|
-
validators: validatorsI,
|
827
|
-
} = await setup();
|
828
|
-
rollupAdmin = rollupAdminContract;
|
829
|
-
rollupUser = rollupUserContract;
|
830
|
-
admin = adminI;
|
831
|
-
validators = validatorsI;
|
832
|
-
rollup = new RollupContract(rollupUser.connect(validators[0]));
|
833
|
-
});
|
834
|
-
|
835
|
-
it("should stake on initial node again", async function () {
|
836
|
-
await tryAdvanceChain(minimumAssertionPeriod);
|
837
|
-
|
838
|
-
const initNode: {
|
839
|
-
assertion: { afterState: ExecutionStateStruct };
|
840
|
-
nodeNum: number;
|
841
|
-
nodeHash: BytesLike;
|
842
|
-
inboxMaxCount: BigNumber;
|
843
|
-
} = {
|
844
|
-
assertion: {
|
845
|
-
afterState: {
|
846
|
-
globalState: {
|
847
|
-
bytes32Vals: [zerobytes32, zerobytes32],
|
848
|
-
u64Vals: [0, 0],
|
849
|
-
},
|
850
|
-
machineStatus: MachineStatus.FINISHED,
|
851
|
-
},
|
852
|
-
},
|
853
|
-
inboxMaxCount: BigNumber.from(1),
|
854
|
-
nodeHash: zerobytes32,
|
855
|
-
nodeNum: 0,
|
856
|
-
};
|
857
|
-
|
858
|
-
const stake = await rollup.currentRequiredStake();
|
859
|
-
const { node } = await makeSimpleNode(
|
860
|
-
rollup,
|
861
|
-
sequencerInbox,
|
862
|
-
initNode,
|
863
|
-
undefined,
|
864
|
-
undefined,
|
865
|
-
stake
|
866
|
-
);
|
867
|
-
updatePrevNode(node);
|
868
|
-
});
|
869
|
-
});
|