Skip to content

Commit 7bb751f

Browse files
authored
feat: v3 codec (#4)
1 parent ca7f076 commit 7bb751f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+5092
-1127
lines changed

.env.example

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
### NOTE: DO NOT USE THIS FILE IF USING TESTNET'S .ENV
22
ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1
33

4+
MAINNET_FORK_RPC=
45
RINKEBY_RPC=https://eth-rinkeby.alchemyapi.io/v2/<YOUR ALCHEMY KEY>
56
SCROLL_L1_RPC=https://prealpha.scroll.io/l1
67
SCROLL_L2_RPC=https://prealpha.scroll.io/l2

hardhat-test/L1MessageQueue.spec.ts

+3-302
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,13 @@ import { expect } from "chai";
55
import { ethers } from "hardhat";
66

77
import { L1MessageQueue, L2GasPriceOracle } from "../typechain";
8-
import {
9-
MaxUint256,
10-
ZeroAddress,
11-
concat,
12-
encodeRlp,
13-
getAddress,
14-
hexlify,
15-
keccak256,
16-
randomBytes,
17-
toBeHex,
18-
toBigInt,
19-
} from "ethers";
8+
import { MaxUint256, ZeroAddress, concat, encodeRlp, hexlify, keccak256, randomBytes, toBeHex } from "ethers";
209

2110
describe("L1MessageQueue", async () => {
2211
let deployer: HardhatEthersSigner;
2312
let scrollChain: HardhatEthersSigner;
2413
let messenger: HardhatEthersSigner;
2514
let gateway: HardhatEthersSigner;
26-
let signer: HardhatEthersSigner;
2715

2816
let oracle: L2GasPriceOracle;
2917
let queue: L1MessageQueue;
@@ -37,7 +25,7 @@ describe("L1MessageQueue", async () => {
3725
};
3826

3927
beforeEach(async () => {
40-
[deployer, scrollChain, messenger, gateway, signer] = await ethers.getSigners();
28+
[deployer, scrollChain, messenger, gateway] = await ethers.getSigners();
4129

4230
const ProxyAdmin = await ethers.getContractFactory("ProxyAdmin", deployer);
4331
const admin = await ProxyAdmin.deploy();
@@ -62,51 +50,7 @@ describe("L1MessageQueue", async () => {
6250
await queue.initialize(messenger.address, scrollChain.address, ZeroAddress, oracle.getAddress(), 10000000);
6351
});
6452

65-
context("auth", async () => {
66-
it("should initialize correctly", async () => {
67-
expect(await queue.owner()).to.eq(deployer.address);
68-
expect(await queue.messenger()).to.eq(messenger.address);
69-
expect(await queue.scrollChain()).to.eq(scrollChain.address);
70-
expect(await queue.enforcedTxGateway()).to.eq(gateway.address);
71-
expect(await queue.gasOracle()).to.eq(await oracle.getAddress());
72-
expect(await queue.maxGasLimit()).to.eq(10000000);
73-
});
74-
75-
it("should revert, when initialize again", async () => {
76-
await expect(queue.initialize(ZeroAddress, ZeroAddress, ZeroAddress, ZeroAddress, 0)).to.revertedWith(
77-
"Initializable: contract is already initialized"
78-
);
79-
});
80-
81-
context("#updateGasOracle", async () => {
82-
it("should revert, when non-owner call", async () => {
83-
await expect(queue.connect(signer).updateGasOracle(ZeroAddress)).to.revertedWith(
84-
"Ownable: caller is not the owner"
85-
);
86-
});
87-
88-
it("should succeed", async () => {
89-
expect(await queue.gasOracle()).to.eq(await oracle.getAddress());
90-
await expect(queue.updateGasOracle(deployer.address))
91-
.to.emit(queue, "UpdateGasOracle")
92-
.withArgs(await oracle.getAddress(), deployer.address);
93-
expect(await queue.gasOracle()).to.eq(deployer.address);
94-
});
95-
});
96-
97-
context("#updateMaxGasLimit", async () => {
98-
it("should revert, when non-owner call", async () => {
99-
await expect(queue.connect(signer).updateMaxGasLimit(0)).to.revertedWith("Ownable: caller is not the owner");
100-
});
101-
102-
it("should succeed", async () => {
103-
expect(await queue.maxGasLimit()).to.eq(10000000);
104-
await expect(queue.updateMaxGasLimit(0)).to.emit(queue, "UpdateMaxGasLimit").withArgs(10000000, 0);
105-
expect(await queue.maxGasLimit()).to.eq(0);
106-
});
107-
});
108-
});
109-
53+
// other functions are tested in `src/test/L1MessageQueue.t.sol`
11054
context("#computeTransactionHash", async () => {
11155
it("should succeed", async () => {
11256
const sender = "0xb2a70fab1a45b1b9be443b6567849a1702bc1232";
@@ -147,247 +91,4 @@ describe("L1MessageQueue", async () => {
14791
}
14892
});
14993
});
150-
151-
context("#appendCrossDomainMessage", async () => {
152-
it("should revert, when non-messenger call", async () => {
153-
await expect(queue.connect(signer).appendCrossDomainMessage(ZeroAddress, 0, "0x")).to.revertedWith(
154-
"Only callable by the L1ScrollMessenger"
155-
);
156-
});
157-
158-
it("should revert, when exceed maxGasLimit", async () => {
159-
await expect(queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 10000001, "0x")).to.revertedWith(
160-
"Gas limit must not exceed maxGasLimit"
161-
);
162-
});
163-
164-
it("should revert, when below intrinsic gas", async () => {
165-
await expect(queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 0, "0x")).to.revertedWith(
166-
"Insufficient gas limit, must be above intrinsic gas"
167-
);
168-
});
169-
170-
it("should succeed", async () => {
171-
expect(await queue.nextCrossDomainMessageIndex()).to.eq(0n);
172-
const sender = getAddress(
173-
toBeHex((toBigInt(messenger.address) + toBigInt("0x1111000000000000000000000000000000001111")) % 2n ** 160n)
174-
.slice(2)
175-
.padStart(40, "0")
176-
);
177-
const hash = await queue.computeTransactionHash(sender, 0, 0, signer.address, 100000, "0x01");
178-
await expect(queue.connect(messenger).appendCrossDomainMessage(signer.address, 100000, "0x01"))
179-
.to.emit(queue, "QueueTransaction")
180-
.withArgs(sender, signer.address, 0, 0, 100000, "0x01");
181-
expect(await queue.nextCrossDomainMessageIndex()).to.eq(1n);
182-
expect(await queue.getCrossDomainMessage(0)).to.eq(hash);
183-
});
184-
});
185-
186-
context("#appendEnforcedTransaction", async () => {
187-
it("should revert, when non-gateway call", async () => {
188-
await expect(
189-
queue.connect(signer).appendEnforcedTransaction(signer.address, ZeroAddress, 0, 0, "0x")
190-
).to.revertedWith("Only callable by the EnforcedTxGateway");
191-
});
192-
193-
it("should revert, when sender is not EOA", async () => {
194-
await expect(
195-
queue.connect(gateway).appendEnforcedTransaction(queue.getAddress(), ZeroAddress, 0, 0, "0x")
196-
).to.revertedWith("only EOA");
197-
});
198-
199-
it("should revert, when exceed maxGasLimit", async () => {
200-
await expect(
201-
queue.connect(gateway).appendEnforcedTransaction(signer.address, ZeroAddress, 0, 10000001, "0x")
202-
).to.revertedWith("Gas limit must not exceed maxGasLimit");
203-
});
204-
205-
it("should revert, when below intrinsic gas", async () => {
206-
await expect(
207-
queue.connect(gateway).appendEnforcedTransaction(signer.address, ZeroAddress, 0, 0, "0x")
208-
).to.revertedWith("Insufficient gas limit, must be above intrinsic gas");
209-
});
210-
211-
it("should succeed", async () => {
212-
expect(await queue.nextCrossDomainMessageIndex()).to.eq(0n);
213-
const sender = signer.address;
214-
const hash = await queue.computeTransactionHash(sender, 0, 200, signer.address, 100000, "0x01");
215-
await expect(
216-
queue.connect(gateway).appendEnforcedTransaction(signer.address, signer.address, 200, 100000, "0x01")
217-
)
218-
.to.emit(queue, "QueueTransaction")
219-
.withArgs(sender, signer.address, 200, 0, 100000, "0x01");
220-
expect(await queue.nextCrossDomainMessageIndex()).to.eq(1n);
221-
expect(await queue.getCrossDomainMessage(0)).to.eq(hash);
222-
});
223-
});
224-
225-
context("#popCrossDomainMessage", async () => {
226-
it("should revert, when non-scrollChain call", async () => {
227-
await expect(queue.connect(signer).popCrossDomainMessage(0, 0, 0)).to.revertedWith(
228-
"Only callable by the ScrollChain"
229-
);
230-
});
231-
232-
it("should revert, when pop too many messages", async () => {
233-
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 257, 0)).to.revertedWith(
234-
"pop too many messages"
235-
);
236-
});
237-
238-
it("should revert, when start index mismatch", async () => {
239-
await expect(queue.connect(scrollChain).popCrossDomainMessage(1, 256, 0)).to.revertedWith("start index mismatch");
240-
});
241-
242-
it("should succeed", async () => {
243-
// append 512 messages
244-
for (let i = 0; i < 256 * 2; i++) {
245-
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
246-
}
247-
248-
// pop 50 messages with no skip
249-
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 50, 0))
250-
.to.emit(queue, "DequeueTransaction")
251-
.withArgs(0, 50, 0);
252-
for (let i = 0; i < 50; i++) {
253-
expect(await queue.isMessageSkipped(i)).to.eq(false);
254-
expect(await queue.isMessageDropped(i)).to.eq(false);
255-
}
256-
expect(await queue.pendingQueueIndex()).to.eq(50);
257-
258-
// pop 10 messages all skip
259-
await expect(queue.connect(scrollChain).popCrossDomainMessage(50, 10, 1023))
260-
.to.emit(queue, "DequeueTransaction")
261-
.withArgs(50, 10, 1023);
262-
expect(await queue.pendingQueueIndex()).to.eq(60);
263-
for (let i = 50; i < 60; i++) {
264-
expect(await queue.isMessageSkipped(i)).to.eq(true);
265-
expect(await queue.isMessageDropped(i)).to.eq(false);
266-
}
267-
268-
// pop 20 messages, skip first 5
269-
await expect(queue.connect(scrollChain).popCrossDomainMessage(60, 20, 31))
270-
.to.emit(queue, "DequeueTransaction")
271-
.withArgs(60, 20, 31);
272-
expect(await queue.pendingQueueIndex()).to.eq(80);
273-
for (let i = 60; i < 65; i++) {
274-
expect(await queue.isMessageSkipped(i)).to.eq(true);
275-
expect(await queue.isMessageDropped(i)).to.eq(false);
276-
}
277-
for (let i = 65; i < 80; i++) {
278-
expect(await queue.isMessageSkipped(i)).to.eq(false);
279-
expect(await queue.isMessageDropped(i)).to.eq(false);
280-
}
281-
282-
// pop 256 messages with random skip
283-
const bitmap = toBigInt("0x496525059c3f33758d17030403e45afe067b8a0ae1317cda0487fd2932cbea1a");
284-
const tx = await queue.connect(scrollChain).popCrossDomainMessage(80, 256, bitmap);
285-
await expect(tx).to.emit(queue, "DequeueTransaction").withArgs(80, 256, bitmap);
286-
console.log("gas used:", (await tx.wait())!.gasUsed.toString());
287-
for (let i = 80; i < 80 + 256; i++) {
288-
expect(await queue.isMessageSkipped(i)).to.eq(((bitmap >> toBigInt(i - 80)) & 1n) === 1n);
289-
expect(await queue.isMessageDropped(i)).to.eq(false);
290-
}
291-
});
292-
293-
// @note skip this random benchmark tests
294-
for (const count1 of [1, 2, 128, 129, 256]) {
295-
for (const count2 of [1, 2, 128, 129, 256]) {
296-
for (const count3 of [1, 2, 128, 129, 256]) {
297-
it.skip(`should succeed on random tests, pop three times each with ${count1} ${count2} ${count3} msgs`, async () => {
298-
// append count1 + count2 + count3 messages
299-
for (let i = 0; i < count1 + count2 + count3; i++) {
300-
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
301-
}
302-
303-
// first pop `count1` messages
304-
const bitmap1 = toBigInt(randomBytes(32));
305-
let tx = await queue.connect(scrollChain).popCrossDomainMessage(0, count1, bitmap1);
306-
await expect(tx)
307-
.to.emit(queue, "DequeueTransaction")
308-
.withArgs(0, count1, bitmap1 & ((1n << toBigInt(count1)) - 1n));
309-
for (let i = 0; i < count1; i++) {
310-
expect(await queue.isMessageSkipped(i)).to.eq(((bitmap1 >> toBigInt(i)) & 1n) === 1n);
311-
expect(await queue.isMessageDropped(i)).to.eq(false);
312-
}
313-
314-
// then pop `count2` messages
315-
const bitmap2 = toBigInt(randomBytes(32));
316-
tx = await queue.connect(scrollChain).popCrossDomainMessage(count1, count2, bitmap2);
317-
await expect(tx)
318-
.to.emit(queue, "DequeueTransaction")
319-
.withArgs(count1, count2, bitmap2 & ((1n << toBigInt(count2)) - 1n));
320-
for (let i = 0; i < count2; i++) {
321-
expect(await queue.isMessageSkipped(i + count1)).to.eq(((bitmap2 >> toBigInt(i)) & 1n) === 1n);
322-
expect(await queue.isMessageDropped(i + count1)).to.eq(false);
323-
}
324-
325-
// last pop `count3` messages
326-
const bitmap3 = toBigInt(randomBytes(32));
327-
tx = await queue.connect(scrollChain).popCrossDomainMessage(count1 + count2, count3, bitmap3);
328-
await expect(tx)
329-
.to.emit(queue, "DequeueTransaction")
330-
.withArgs(count1 + count2, count3, bitmap3 & ((1n << toBigInt(count3)) - 1n));
331-
for (let i = 0; i < count3; i++) {
332-
expect(await queue.isMessageSkipped(i + count1 + count2)).to.eq(((bitmap3 >> toBigInt(i)) & 1n) === 1n);
333-
expect(await queue.isMessageDropped(i + count1 + count2)).to.eq(false);
334-
}
335-
});
336-
}
337-
}
338-
}
339-
});
340-
341-
context("#dropCrossDomainMessage", async () => {
342-
it("should revert, when non-messenger call", async () => {
343-
await expect(queue.connect(signer).dropCrossDomainMessage(0)).to.revertedWith(
344-
"Only callable by the L1ScrollMessenger"
345-
);
346-
});
347-
348-
it("should revert, when drop non-skipped message", async () => {
349-
// append 10 messages
350-
for (let i = 0; i < 10; i++) {
351-
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
352-
}
353-
// pop 5 messages with no skip
354-
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 5, 0))
355-
.to.emit(queue, "DequeueTransaction")
356-
.withArgs(0, 5, 0);
357-
for (let i = 0; i < 5; i++) {
358-
expect(await queue.isMessageSkipped(i)).to.eq(false);
359-
expect(await queue.isMessageDropped(i)).to.eq(false);
360-
}
361-
expect(await queue.pendingQueueIndex()).to.eq(5);
362-
363-
for (let i = 0; i < 5; i++) {
364-
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("drop non-skipped message");
365-
}
366-
367-
// drop pending message
368-
for (let i = 6; i < 10; i++) {
369-
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("cannot drop pending message");
370-
}
371-
});
372-
373-
it("should succeed", async () => {
374-
// append 10 messages
375-
for (let i = 0; i < 10; i++) {
376-
await queue.connect(messenger).appendCrossDomainMessage(ZeroAddress, 1000000, "0x");
377-
}
378-
// pop 10 messages, all skipped
379-
await expect(queue.connect(scrollChain).popCrossDomainMessage(0, 10, 0x3ff))
380-
.to.emit(queue, "DequeueTransaction")
381-
.withArgs(0, 10, 0x3ff);
382-
383-
for (let i = 0; i < 10; i++) {
384-
expect(await queue.isMessageSkipped(i)).to.eq(true);
385-
expect(await queue.isMessageDropped(i)).to.eq(false);
386-
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.emit(queue, "DropTransaction").withArgs(i);
387-
await expect(queue.connect(messenger).dropCrossDomainMessage(i)).to.revertedWith("message already dropped");
388-
expect(await queue.isMessageSkipped(i)).to.eq(true);
389-
expect(await queue.isMessageDropped(i)).to.eq(true);
390-
}
391-
});
392-
});
39394
});

0 commit comments

Comments
 (0)