mirror of
https://github.com/status-im/dagger-contracts.git
synced 2025-01-28 23:35:04 +00:00
Extract logic around proofs into separate contract
This commit is contained in:
parent
c013a37229
commit
d1f5ce0786
92
contracts/Proofs.sol
Normal file
92
contracts/Proofs.sol
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract Proofs {
|
||||||
|
|
||||||
|
mapping(bytes32=>bool) private ids;
|
||||||
|
mapping(bytes32=>uint) private periods;
|
||||||
|
mapping(bytes32=>uint) private timeouts;
|
||||||
|
mapping(bytes32=>uint) private markers;
|
||||||
|
mapping(bytes32=>uint) private missed;
|
||||||
|
mapping(bytes32=>mapping(uint=>bool)) private received;
|
||||||
|
mapping(bytes32=>mapping(uint=>bool)) private missing;
|
||||||
|
|
||||||
|
function _period(bytes32 id) internal view returns (uint) {
|
||||||
|
return periods[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _timeout(bytes32 id) internal view returns (uint) {
|
||||||
|
return timeouts[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _missed(bytes32 id) internal view returns (uint) {
|
||||||
|
return missed[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _expectProofs(bytes32 id, uint period, uint timeout) internal {
|
||||||
|
require(!ids[id], "Proof id already in use");
|
||||||
|
ids[id] = true;
|
||||||
|
periods[id] = period;
|
||||||
|
timeouts[id] = timeout;
|
||||||
|
markers[id] = uint(blockhash(block.number - 1)) % period;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _isProofRequired(
|
||||||
|
bytes32 id,
|
||||||
|
uint blocknumber
|
||||||
|
)
|
||||||
|
internal view
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
bytes32 hash = blockhash(blocknumber);
|
||||||
|
return hash != 0 && uint(hash) % periods[id] == markers[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _isProofTimedOut(
|
||||||
|
bytes32 id,
|
||||||
|
uint blocknumber
|
||||||
|
)
|
||||||
|
internal view
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
return block.number >= blocknumber + timeouts[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _submitProof(
|
||||||
|
bytes32 id,
|
||||||
|
uint blocknumber,
|
||||||
|
bool proof
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
require(proof, "Invalid proof"); // TODO: replace bool by actual proof
|
||||||
|
require(
|
||||||
|
_isProofRequired(id, blocknumber),
|
||||||
|
"No proof required for this block"
|
||||||
|
);
|
||||||
|
require(
|
||||||
|
!_isProofTimedOut(id, blocknumber),
|
||||||
|
"Proof not allowed after timeout"
|
||||||
|
);
|
||||||
|
require(!received[id][blocknumber], "Proof already submitted");
|
||||||
|
received[id][blocknumber] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _markProofAsMissing(bytes32 id, uint blocknumber) internal {
|
||||||
|
require(
|
||||||
|
_isProofTimedOut(id, blocknumber),
|
||||||
|
"Proof has not timed out yet"
|
||||||
|
);
|
||||||
|
require(
|
||||||
|
!received[id][blocknumber],
|
||||||
|
"Proof was submitted, not missing"
|
||||||
|
);
|
||||||
|
require(
|
||||||
|
_isProofRequired(id, blocknumber),
|
||||||
|
"Proof was not required"
|
||||||
|
);
|
||||||
|
require(!missing[id][blocknumber], "Proof already marked as missing");
|
||||||
|
missing[id][blocknumber] = true;
|
||||||
|
missed[id] += 1;
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,9 @@
|
|||||||
pragma solidity ^0.8.0;
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
||||||
|
import "./Proofs.sol";
|
||||||
|
|
||||||
contract StorageContracts {
|
contract StorageContracts is Proofs {
|
||||||
|
|
||||||
struct Contract {
|
struct Contract {
|
||||||
bool initialized; // always true, except for empty contracts in mapping
|
bool initialized; // always true, except for empty contracts in mapping
|
||||||
@ -12,12 +13,6 @@ contract StorageContracts {
|
|||||||
bytes32 contentHash; // hash of data that is to be stored
|
bytes32 contentHash; // hash of data that is to be stored
|
||||||
uint price; // price in coins
|
uint price; // price in coins
|
||||||
address host; // host that provides storage
|
address host; // host that provides storage
|
||||||
uint proofPeriod; // average time between proofs (in blocks)
|
|
||||||
uint proofTimeout; // proof has to be submitted before this
|
|
||||||
uint proofMarker; // indicates when a proof is required
|
|
||||||
mapping(uint => bool) proofReceived; // whether proof for block was received
|
|
||||||
mapping(uint => bool) proofMissing; // whether proof for block was missing
|
|
||||||
uint missingProofs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint numberOfContracts;
|
uint numberOfContracts;
|
||||||
@ -44,15 +39,15 @@ contract StorageContracts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function proofPeriod(bytes32 contractId) public view returns (uint) {
|
function proofPeriod(bytes32 contractId) public view returns (uint) {
|
||||||
return contracts[contractId].proofPeriod;
|
return _period(contractId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function proofTimeout(bytes32 contractId) public view returns (uint) {
|
function proofTimeout(bytes32 contractId) public view returns (uint) {
|
||||||
return contracts[contractId].proofTimeout;
|
return _timeout(contractId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function missingProofs(bytes32 contractId) public view returns (uint) {
|
function missingProofs(bytes32 contractId) public view returns (uint) {
|
||||||
return contracts[contractId].missingProofs;
|
return _missed(contractId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newContract(
|
function newContract(
|
||||||
@ -92,9 +87,7 @@ contract StorageContracts {
|
|||||||
c.price = _price;
|
c.price = _price;
|
||||||
c.contentHash = _contentHash;
|
c.contentHash = _contentHash;
|
||||||
c.host = _host;
|
c.host = _host;
|
||||||
c.proofPeriod = _proofPeriod;
|
_expectProofs(contractId, _proofPeriod, _proofTimeout);
|
||||||
c.proofTimeout = _proofTimeout;
|
|
||||||
c.proofMarker = uint(blockhash(block.number - 1)) % _proofPeriod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates hash for a storage request that can be used to check its signature.
|
// Creates hash for a storage request that can be used to check its signature.
|
||||||
@ -171,20 +164,17 @@ contract StorageContracts {
|
|||||||
public view
|
public view
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
Contract storage c = contracts[contractId];
|
return _isProofRequired(contractId, blocknumber);
|
||||||
bytes32 hash = blockhash(blocknumber);
|
|
||||||
return hash != 0 && uint(hash) % c.proofPeriod == c.proofMarker;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isProofTimedOut(
|
function isProofTimedOut(
|
||||||
bytes32 contractId,
|
bytes32 contractId,
|
||||||
uint blocknumber
|
uint blocknumber
|
||||||
)
|
)
|
||||||
internal view
|
public view
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
Contract storage c = contracts[contractId];
|
return _isProofTimedOut(contractId, blocknumber);
|
||||||
return block.number >= blocknumber + c.proofTimeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitProof(
|
function submitProof(
|
||||||
@ -194,36 +184,10 @@ contract StorageContracts {
|
|||||||
)
|
)
|
||||||
public
|
public
|
||||||
{
|
{
|
||||||
Contract storage c = contracts[contractId];
|
_submitProof(contractId, blocknumber, proof);
|
||||||
require(proof, "Invalid proof"); // TODO: replace bool by actual proof
|
|
||||||
require(
|
|
||||||
isProofRequired(contractId, blocknumber),
|
|
||||||
"No proof required for this block"
|
|
||||||
);
|
|
||||||
require(
|
|
||||||
!isProofTimedOut(contractId, blocknumber),
|
|
||||||
"Proof not allowed after timeout"
|
|
||||||
);
|
|
||||||
require(!c.proofReceived[blocknumber], "Proof already submitted");
|
|
||||||
c.proofReceived[blocknumber] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function markProofAsMissing(bytes32 contractId, uint blocknumber) public {
|
function markProofAsMissing(bytes32 contractId, uint blocknumber) public {
|
||||||
Contract storage c = contracts[contractId];
|
_markProofAsMissing(contractId, blocknumber);
|
||||||
require(
|
|
||||||
isProofTimedOut(contractId, blocknumber),
|
|
||||||
"Proof has not timed out yet"
|
|
||||||
);
|
|
||||||
require(
|
|
||||||
!c.proofReceived[blocknumber],
|
|
||||||
"Proof was submitted, not missing"
|
|
||||||
);
|
|
||||||
require(
|
|
||||||
isProofRequired(contractId, blocknumber),
|
|
||||||
"Proof was not required"
|
|
||||||
);
|
|
||||||
require(!c.proofMissing[blocknumber], "Proof already marked as missing");
|
|
||||||
c.proofMissing[blocknumber] = true;
|
|
||||||
c.missingProofs += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
contracts/TestProofs.sol
Normal file
48
contracts/TestProofs.sol
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./Proofs.sol";
|
||||||
|
|
||||||
|
// exposes internal functions of Proofs for testing
|
||||||
|
contract TestProofs is Proofs {
|
||||||
|
|
||||||
|
function period(bytes32 id) public view returns (uint) {
|
||||||
|
return _period(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeout(bytes32 id) public view returns (uint) {
|
||||||
|
return _timeout(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function missed(bytes32 id) public view returns (uint) {
|
||||||
|
return _missed(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectProofs(bytes32 id, uint _period, uint _timeout) public {
|
||||||
|
_expectProofs(id, _period, _timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isProofRequired(
|
||||||
|
bytes32 id,
|
||||||
|
uint blocknumber
|
||||||
|
)
|
||||||
|
public view
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
return _isProofRequired(id, blocknumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitProof(
|
||||||
|
bytes32 id,
|
||||||
|
uint blocknumber,
|
||||||
|
bool proof
|
||||||
|
)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
_submitProof(id, blocknumber, proof);
|
||||||
|
}
|
||||||
|
|
||||||
|
function markProofAsMissing(bytes32 id, uint blocknumber) public {
|
||||||
|
_markProofAsMissing(id, blocknumber);
|
||||||
|
}
|
||||||
|
}
|
169
test/Proofs.test.js
Normal file
169
test/Proofs.test.js
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
const { expect } = require("chai")
|
||||||
|
const { ethers } = require("hardhat")
|
||||||
|
|
||||||
|
describe("Proofs", function () {
|
||||||
|
|
||||||
|
const id = ethers.utils.randomBytes(32)
|
||||||
|
const period = 10
|
||||||
|
const timeout = 5
|
||||||
|
|
||||||
|
let proofs
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
const Proofs = await ethers.getContractFactory("TestProofs")
|
||||||
|
proofs = await Proofs.deploy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("indicates that proofs are required", async function() {
|
||||||
|
await proofs.expectProofs(id, period, timeout)
|
||||||
|
expect(await proofs.period(id)).to.equal(period)
|
||||||
|
expect(await proofs.timeout(id)).to.equal(timeout)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("does not allow ids to be reused", async function() {
|
||||||
|
await proofs.expectProofs(id, period, timeout)
|
||||||
|
await expect(
|
||||||
|
proofs.expectProofs(id, period, timeout)
|
||||||
|
).to.be.revertedWith("Proof id already in use")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("when proofs are required", async function () {
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
await proofs.expectProofs(id, period, timeout)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function mineBlock() {
|
||||||
|
await ethers.provider.send("evm_mine")
|
||||||
|
}
|
||||||
|
|
||||||
|
async function minedBlockNumber() {
|
||||||
|
return await ethers.provider.getBlockNumber() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mineUntilProofIsRequired(id) {
|
||||||
|
while (!await proofs.isProofRequired(id, await minedBlockNumber())) {
|
||||||
|
mineBlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mineUntilProofTimeout() {
|
||||||
|
for (let i=0; i<timeout; i++) {
|
||||||
|
mineBlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it("requires on average a proof every period", async function () {
|
||||||
|
let blocks = 500
|
||||||
|
let amount = 0
|
||||||
|
for (i=0; i<blocks; i++) {
|
||||||
|
await mineBlock()
|
||||||
|
if (await proofs.isProofRequired(id, await minedBlockNumber())) {
|
||||||
|
amount += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let average = blocks / amount
|
||||||
|
expect(average).to.be.closeTo(period, period / 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("requires no proof for blocks that are unavailable", async function () {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
for (i=0; i<256; i++) { // only last 256 blocks are available in solidity
|
||||||
|
mineBlock()
|
||||||
|
}
|
||||||
|
expect(await proofs.isProofRequired(id, blocknumber)).to.be.false
|
||||||
|
})
|
||||||
|
|
||||||
|
it("submits a correct proof", async function () {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await proofs.submitProof(id, blocknumber, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails proof submission when proof is incorrect", async function () {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await expect(
|
||||||
|
proofs.submitProof(id, blocknumber, false)
|
||||||
|
).to.be.revertedWith("Invalid proof")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails proof submission when proof was not required", async function () {
|
||||||
|
while (await proofs.isProofRequired(id, await minedBlockNumber())) {
|
||||||
|
await mineBlock()
|
||||||
|
}
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await expect(
|
||||||
|
proofs.submitProof(id, blocknumber, true)
|
||||||
|
).to.be.revertedWith("No proof required")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails proof submission when proof is too late", async function () {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await mineUntilProofTimeout()
|
||||||
|
await expect(
|
||||||
|
proofs.submitProof(id, blocknumber, true)
|
||||||
|
).to.be.revertedWith("Proof not allowed after timeout")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails proof submission when already submitted", async function() {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await proofs.submitProof(id, blocknumber, true)
|
||||||
|
await expect(
|
||||||
|
proofs.submitProof(id, blocknumber, true)
|
||||||
|
).to.be.revertedWith("Proof already submitted")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("marks a proof as missing", async function () {
|
||||||
|
expect(await proofs.missed(id)).to.equal(0)
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await mineUntilProofTimeout()
|
||||||
|
await proofs.markProofAsMissing(id, blocknumber)
|
||||||
|
expect(await proofs.missed(id)).to.equal(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("does not mark a proof as missing before timeout", async function () {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await mineBlock()
|
||||||
|
await expect(
|
||||||
|
proofs.markProofAsMissing(id, blocknumber)
|
||||||
|
).to.be.revertedWith("Proof has not timed out yet")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("does not mark a submitted proof as missing", async function () {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await proofs.submitProof(id, blocknumber, true)
|
||||||
|
await mineUntilProofTimeout()
|
||||||
|
await expect(
|
||||||
|
proofs.markProofAsMissing(id, blocknumber)
|
||||||
|
).to.be.revertedWith("Proof was submitted, not missing")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("does not mark proof as missing when not required", async function () {
|
||||||
|
while (await proofs.isProofRequired(id, await minedBlockNumber())) {
|
||||||
|
mineBlock()
|
||||||
|
}
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await mineUntilProofTimeout()
|
||||||
|
await expect(
|
||||||
|
proofs.markProofAsMissing(id, blocknumber)
|
||||||
|
).to.be.revertedWith("Proof was not required")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("does not mark proof as missing twice", async function () {
|
||||||
|
await mineUntilProofIsRequired(id)
|
||||||
|
let blocknumber = await minedBlockNumber()
|
||||||
|
await mineUntilProofTimeout()
|
||||||
|
await proofs.markProofAsMissing(id, blocknumber)
|
||||||
|
await expect(
|
||||||
|
proofs.markProofAsMissing(id, blocknumber)
|
||||||
|
).to.be.revertedWith("Proof already marked as missing")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -197,158 +197,6 @@ describe("Storage Contracts", function () {
|
|||||||
await sign(host, bidHash),
|
await sign(host, bidHash),
|
||||||
)).to.be.revertedWith("Bid expired")
|
)).to.be.revertedWith("Bid expired")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("proofs", function () {
|
|
||||||
|
|
||||||
async function mineBlock() {
|
|
||||||
await ethers.provider.send("evm_mine")
|
|
||||||
}
|
|
||||||
|
|
||||||
async function minedBlockNumber() {
|
|
||||||
return await ethers.provider.getBlockNumber() - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
async function mineUntilProofIsRequired(id) {
|
|
||||||
while (!await contracts.isProofRequired(id, await minedBlockNumber())) {
|
|
||||||
mineBlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function mineUntilProofTimeout() {
|
|
||||||
for (let i=0; i<proofTimeout; i++) {
|
|
||||||
mineBlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(async function () {
|
|
||||||
await contracts.newContract(
|
|
||||||
duration,
|
|
||||||
size,
|
|
||||||
contentHash,
|
|
||||||
price,
|
|
||||||
proofPeriod,
|
|
||||||
proofTimeout,
|
|
||||||
nonce,
|
|
||||||
bidExpiry,
|
|
||||||
await host.getAddress(),
|
|
||||||
await sign(client, requestHash),
|
|
||||||
await sign(host, bidHash)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("requires on average a proof every period", async function () {
|
|
||||||
let blocks = 400
|
|
||||||
let proofs = 0
|
|
||||||
for (i=0; i<blocks; i++) {
|
|
||||||
await mineBlock()
|
|
||||||
if (await contracts.isProofRequired(id, await minedBlockNumber())) {
|
|
||||||
proofs += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let average = blocks / proofs
|
|
||||||
expect(average).to.be.closeTo(proofPeriod, proofPeriod / 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("requires no proof for blocks that are unavailable", async function () {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
for (i=0; i<256; i++) { // only last 256 blocks are available in solidity
|
|
||||||
mineBlock()
|
|
||||||
}
|
|
||||||
expect(await contracts.isProofRequired(id, blocknumber)).to.be.false
|
|
||||||
})
|
|
||||||
|
|
||||||
it("submits a correct proof", async function () {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await contracts.submitProof(id, blocknumber, true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("fails proof submission when proof is incorrect", async function () {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await expect(
|
|
||||||
contracts.submitProof(id, blocknumber, false)
|
|
||||||
).to.be.revertedWith("Invalid proof")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("fails proof submission when proof was not required", async function () {
|
|
||||||
while (await contracts.isProofRequired(id, await minedBlockNumber())) {
|
|
||||||
await mineBlock()
|
|
||||||
}
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await expect(
|
|
||||||
contracts.submitProof(id, blocknumber, true)
|
|
||||||
).to.be.revertedWith("No proof required")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("fails proof submission when proof is too late", async function () {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await mineUntilProofTimeout()
|
|
||||||
await expect(
|
|
||||||
contracts.submitProof(id, blocknumber, true)
|
|
||||||
).to.be.revertedWith("Proof not allowed after timeout")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("fails proof submission when already submitted", async function() {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await contracts.submitProof(id, blocknumber, true)
|
|
||||||
await expect(
|
|
||||||
contracts.submitProof(id, blocknumber, true)
|
|
||||||
).to.be.revertedWith("Proof already submitted")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("marks a proof as missing", async function () {
|
|
||||||
expect(await contracts.missingProofs(id)).to.equal(0)
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await mineUntilProofTimeout()
|
|
||||||
await contracts.markProofAsMissing(id, blocknumber)
|
|
||||||
expect(await contracts.missingProofs(id)).to.equal(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("does not mark a proof as missing before timeout", async function () {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await mineBlock()
|
|
||||||
await expect(
|
|
||||||
contracts.markProofAsMissing(id, blocknumber)
|
|
||||||
).to.be.revertedWith("Proof has not timed out yet")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("does not mark a submitted proof as missing", async function () {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await contracts.submitProof(id, blocknumber, true)
|
|
||||||
await mineUntilProofTimeout()
|
|
||||||
await expect(
|
|
||||||
contracts.markProofAsMissing(id, blocknumber)
|
|
||||||
).to.be.revertedWith("Proof was submitted, not missing")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("does not mark proof as missing when not required", async function () {
|
|
||||||
while (await contracts.isProofRequired(id, await minedBlockNumber())) {
|
|
||||||
mineBlock()
|
|
||||||
}
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await mineUntilProofTimeout()
|
|
||||||
await expect(
|
|
||||||
contracts.markProofAsMissing(id, blocknumber)
|
|
||||||
).to.be.revertedWith("Proof was not required")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("does not mark proof as missing twice", async function () {
|
|
||||||
await mineUntilProofIsRequired(id)
|
|
||||||
let blocknumber = await minedBlockNumber()
|
|
||||||
await mineUntilProofTimeout()
|
|
||||||
await contracts.markProofAsMissing(id, blocknumber)
|
|
||||||
await expect(
|
|
||||||
contracts.markProofAsMissing(id, blocknumber)
|
|
||||||
).to.be.revertedWith("Proof already marked as missing")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: implement checking of actual proofs of storage, instead of dummy bool
|
// TODO: implement checking of actual proofs of storage, instead of dummy bool
|
||||||
|
Loading…
x
Reference in New Issue
Block a user