Spaces:
Sleeping
Sleeping
| // 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"); | |
| }); | |
| }); | |
| }); | |