qcrypt-rng / quantum-oracle /contracts /test /QuantumRandomnessOracle.test.js
rocRevyAreGoals15's picture
Add quantum dashboard, VRF, PQC, data protection, and HF Spaces deployment
bab1185
// contracts/test/QuantumRandomnessOracle.test.js
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("QuantumRandomnessOracle", function () {
let quantumOracle;
let owner;
let user1;
let user2;
let oracleNode;
const REQUEST_FEE = ethers.utils.parseEther("0.01");
beforeEach(async function () {
[owner, user1, user2, oracleNode] = await ethers.getSigners();
const QuantumRandomnessOracle = await ethers.getContractFactory("QuantumRandomnessOracle");
quantumOracle = await QuantumRandomnessOracle.deploy(REQUEST_FEE, oracleNode.address);
await quantumOracle.deployed();
});
// Helper: mine N empty blocks so commit-reveal delay elapses
async function mineBlocks(n) {
for (let i = 0; i < n; i++) {
await ethers.provider.send("evm_mine", []);
}
}
// ---------------------------------------------------------------------------
// Deployment
// ---------------------------------------------------------------------------
describe("Deployment", function () {
it("Should set the right owner", async function () {
expect(await quantumOracle.owner()).to.equal(owner.address);
});
it("Should set the right oracle node", async function () {
expect(await quantumOracle.oracleNode()).to.equal(oracleNode.address);
});
it("Should set the right fee", async function () {
expect(await quantumOracle.fee()).to.equal(REQUEST_FEE);
});
});
// ---------------------------------------------------------------------------
// Request Randomness
// ---------------------------------------------------------------------------
describe("Request Randomness", function () {
it("Should allow users to request randomness", async function () {
await expect(
quantumOracle.connect(user1).requestRandomness({ value: REQUEST_FEE })
)
.to.emit(quantumOracle, "RandomnessRequested")
.withArgs(0, user1.address, REQUEST_FEE);
const request = await quantumOracle.getRequest(0);
expect(request.requester).to.equal(user1.address);
expect(request.fee).to.equal(REQUEST_FEE);
expect(request.fulfilled).to.be.false;
});
it("Should reject requests with insufficient fee", async function () {
await expect(
quantumOracle.connect(user1).requestRandomness({
value: ethers.utils.parseEther("0.001"),
})
).to.be.revertedWith("Insufficient fee paid");
});
it("Should increment request counter", async function () {
await quantumOracle.connect(user1).requestRandomness({ value: REQUEST_FEE });
await quantumOracle.connect(user2).requestRandomness({ value: REQUEST_FEE });
const request1 = await quantumOracle.getRequest(0);
const request2 = await quantumOracle.getRequest(1);
expect(request1.requester).to.equal(user1.address);
expect(request2.requester).to.equal(user2.address);
});
});
// ---------------------------------------------------------------------------
// Two-phase commit-reveal
// ---------------------------------------------------------------------------
describe("Commit-Reveal Flow", function () {
let requestId;
let randomnessValue;
let commitment;
beforeEach(async function () {
await quantumOracle.connect(user1).requestRandomness({ value: REQUEST_FEE });
requestId = 0;
// Generate a random value and its keccak256 commitment
randomnessValue = ethers.BigNumber.from(ethers.utils.randomBytes(32));
commitment = ethers.utils.keccak256(
ethers.utils.defaultAbiCoder.encode(["uint256"], [randomnessValue])
);
});
it("Should allow oracle node to submit a commitment", async function () {
await expect(
quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment)
)
.to.emit(quantumOracle, "CommitmentSubmitted")
.withArgs(requestId, commitment);
const request = await quantumOracle.getRequest(requestId);
expect(request.commitment).to.equal(commitment);
});
it("Should reject duplicate commitment", async function () {
await quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment);
await expect(
quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment)
).to.be.revertedWith("Commitment already submitted");
});
it("Should reject commitment from non-oracle node", async function () {
await expect(
quantumOracle.connect(user1).submitCommitment(requestId, commitment)
).to.be.revertedWith("Only oracle node can fulfill requests");
});
it("Should fulfill after commit-reveal delay", async function () {
await quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment);
// Mine enough blocks so the delay elapses
await mineBlocks(2);
await expect(
quantumOracle.connect(oracleNode).fulfillRandomness(requestId, randomnessValue)
)
.to.emit(quantumOracle, "RandomnessFulfilled")
.withArgs(requestId, randomnessValue, 256);
const request = await quantumOracle.getRequest(requestId);
expect(request.fulfilled).to.be.true;
expect(request.randomness).to.equal(randomnessValue);
});
it("Should reject reveal before delay elapses", async function () {
await quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment);
// Do NOT mine extra blocks
await expect(
quantumOracle.connect(oracleNode).fulfillRandomness(requestId, randomnessValue)
).to.be.revertedWith("Commit-reveal delay not elapsed");
});
it("Should reject reveal without a commitment", async function () {
await expect(
quantumOracle.connect(oracleNode).fulfillRandomness(requestId, randomnessValue)
).to.be.revertedWith("Commitment not yet submitted");
});
it("Should reject reveal with wrong preimage", async function () {
await quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment);
await mineBlocks(2);
const wrongRandomness = ethers.BigNumber.from(ethers.utils.randomBytes(32));
await expect(
quantumOracle.connect(oracleNode).fulfillRandomness(requestId, wrongRandomness)
).to.be.revertedWith("Commitment mismatch");
});
it("Should reject fulfillment by non-oracle node", async function () {
await quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment);
await mineBlocks(2);
await expect(
quantumOracle.connect(user1).fulfillRandomness(requestId, randomnessValue)
).to.be.revertedWith("Only oracle node can fulfill requests");
});
it("Should reject double fulfillment", async function () {
await quantumOracle.connect(oracleNode).submitCommitment(requestId, commitment);
await mineBlocks(2);
await quantumOracle.connect(oracleNode).fulfillRandomness(requestId, randomnessValue);
await expect(
quantumOracle.connect(oracleNode).fulfillRandomness(requestId, randomnessValue)
).to.be.revertedWith("Request already fulfilled");
});
});
// ---------------------------------------------------------------------------
// Access Control
// ---------------------------------------------------------------------------
describe("Access Control", function () {
it("Should allow owner to update oracle node", async function () {
const newOracleNode = user2.address;
await expect(quantumOracle.connect(owner).updateOracleNode(newOracleNode))
.to.emit(quantumOracle, "OracleNodeUpdated")
.withArgs(oracleNode.address, newOracleNode);
expect(await quantumOracle.oracleNode()).to.equal(newOracleNode);
});
it("Should reject oracle node update by non-owner", async function () {
await expect(
quantumOracle.connect(user1).updateOracleNode(user2.address)
).to.be.revertedWith("Only owner can call this function");
});
it("Should allow owner to update fee", async function () {
const newFee = ethers.utils.parseEther("0.02");
await expect(quantumOracle.connect(owner).updateFee(newFee))
.to.emit(quantumOracle, "FeeUpdated")
.withArgs(REQUEST_FEE, newFee);
expect(await quantumOracle.fee()).to.equal(newFee);
});
it("Should reject fee update by non-owner", async function () {
const newFee = ethers.utils.parseEther("0.02");
await expect(
quantumOracle.connect(user1).updateFee(newFee)
).to.be.revertedWith("Only owner can call this function");
});
});
});