Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
76 lines
3.1 KiB
JavaScript
76 lines
3.1 KiB
JavaScript
const { expect } = require("chai");
|
|
const { ethers } = require("hardhat");
|
|
|
|
describe("AereBlockSTMRegistry", () => {
|
|
let alice, bob, target;
|
|
let reg;
|
|
const SELECTOR = "0x12345678";
|
|
const SLOT_A = ethers.keccak256(ethers.toUtf8Bytes("slot-a"));
|
|
const SLOT_B = ethers.keccak256(ethers.toUtf8Bytes("slot-b"));
|
|
|
|
beforeEach(async () => {
|
|
[alice, bob, target] = await ethers.getSigners();
|
|
const F = await ethers.getContractFactory("AereBlockSTMRegistry");
|
|
reg = await F.deploy();
|
|
await reg.waitForDeployment();
|
|
});
|
|
|
|
it("first publisher claims (target, selector); only they can update", async () => {
|
|
// AUDIT FIX (HIGH #27): first publisher must be target itself OR target's owner.
|
|
// We have `target` as an EOA so we use it as msg.sender (== target.address).
|
|
await reg.connect(target).publish(target.address, SELECTOR, [
|
|
{ slotPrefix: SLOT_A, mode: 0 /*READ*/ },
|
|
{ slotPrefix: SLOT_B, mode: 1 /*WRITE*/ },
|
|
]);
|
|
expect(await reg.publisherOf(target.address, SELECTOR)).to.equal(target.address);
|
|
|
|
// Random alice cannot squat someone else's (target, selector).
|
|
await expect(
|
|
reg.connect(alice).publish(target.address, SELECTOR, [{ slotPrefix: SLOT_A, mode: 0 }])
|
|
).to.be.revertedWithCustomError(reg, "NotPublisher");
|
|
// Bob can't either.
|
|
await expect(
|
|
reg.connect(bob).publish(target.address, SELECTOR, [{ slotPrefix: SLOT_A, mode: 0 }])
|
|
).to.be.revertedWithCustomError(reg, "NotPublisher");
|
|
});
|
|
|
|
it("hintsFor returns the latest set + count is correct", async () => {
|
|
await reg.connect(target).publish(target.address, SELECTOR, [
|
|
{ slotPrefix: SLOT_A, mode: 2 /*READWRITE*/ },
|
|
]);
|
|
const out = await reg.hintsFor(target.address, SELECTOR);
|
|
expect(out.publisher).to.equal(target.address);
|
|
expect(out.hints.length).to.equal(1);
|
|
expect(out.hints[0].slotPrefix).to.equal(SLOT_A);
|
|
expect(out.hints[0].mode).to.equal(2);
|
|
});
|
|
|
|
it("publish replaces previous hints (not append)", async () => {
|
|
await reg.connect(target).publish(target.address, SELECTOR, [
|
|
{ slotPrefix: SLOT_A, mode: 0 }, { slotPrefix: SLOT_B, mode: 0 },
|
|
]);
|
|
await reg.connect(target).publish(target.address, SELECTOR, [
|
|
{ slotPrefix: SLOT_A, mode: 1 },
|
|
]);
|
|
const out = await reg.hintsFor(target.address, SELECTOR);
|
|
expect(out.hints.length).to.equal(1);
|
|
expect(out.hints[0].mode).to.equal(1);
|
|
});
|
|
|
|
it("rejects > 64 hints", async () => {
|
|
const hints = [];
|
|
for (let i = 0; i < 65; i++) hints.push({ slotPrefix: SLOT_A, mode: 0 });
|
|
await expect(
|
|
reg.connect(target).publish(target.address, SELECTOR, hints)
|
|
).to.be.revertedWithCustomError(reg, "TooManyHints");
|
|
});
|
|
|
|
it("clear only by publisher; emits", async () => {
|
|
await reg.connect(target).publish(target.address, SELECTOR, [{ slotPrefix: SLOT_A, mode: 0 }]);
|
|
await expect(reg.connect(bob).clear(target.address, SELECTOR)).to.be.revertedWithCustomError(reg, "NotPublisher");
|
|
await expect(reg.connect(target).clear(target.address, SELECTOR)).to.emit(reg, "HintsCleared");
|
|
const out = await reg.hintsFor(target.address, SELECTOR);
|
|
expect(out.hints.length).to.equal(0);
|
|
});
|
|
});
|