diff --git a/contracts/Proofs.sol b/contracts/Proofs.sol index b1fb270..5627266 100644 --- a/contracts/Proofs.sol +++ b/contracts/Proofs.sol @@ -97,30 +97,45 @@ contract Proofs { return _getChallenge(id, currentPeriod()); } + function _getProofRequirement(bytes32 id, uint256 proofPeriod) + internal + view + returns (bool isRequired, uint8 pointer) + { + if (proofPeriod <= periodOf(starts[id])) { + return (false, 0); + } + if (proofPeriod >= periodOf(ends[id])) { + return (false, 0); + } + pointer = _getPointer(id, proofPeriod); + bytes32 challenge = _getChallenge(pointer); + uint256 probability = (probabilities[id] * (256 - downtime)) / 256; + isRequired = uint256(challenge) % probability == 0; + } + function _isProofRequired(bytes32 id, uint256 proofPeriod) internal view returns (bool) { - if (proofPeriod <= periodOf(starts[id])) { - return false; - } - if (proofPeriod >= periodOf(ends[id])) { - return false; - } - uint8 pointer = _getPointer(id, proofPeriod); - if (pointer < downtime) { - return false; - } - bytes32 challenge = _getChallenge(pointer); - uint256 probability = (probabilities[id] * (256 - downtime)) / 256; - return uint256(challenge) % probability == 0; + bool isRequired; + uint8 pointer; + (isRequired, pointer) = _getProofRequirement(id, proofPeriod); + return isRequired && pointer >= downtime; } function _isProofRequired(bytes32 id) internal view returns (bool) { return _isProofRequired(id, currentPeriod()); } + function _willProofBeRequired(bytes32 id) internal view returns (bool) { + bool isRequired; + uint8 pointer; + (isRequired, pointer) = _getProofRequirement(id, currentPeriod()); + return isRequired && pointer < downtime; + } + function _submitProof(bytes32 id, bool proof) internal { require(proof, "Invalid proof"); // TODO: replace bool by actual proof require(!received[id][currentPeriod()], "Proof already submitted"); diff --git a/contracts/Storage.sol b/contracts/Storage.sol index 2ae9cc4..ec23b22 100644 --- a/contracts/Storage.sol +++ b/contracts/Storage.sol @@ -66,6 +66,10 @@ contract Storage is Collateral, Marketplace, Proofs { return _isProofRequired(contractId); } + function willProofBeRequired(bytes32 contractId) public view returns (bool) { + return _willProofBeRequired(contractId); + } + function getChallenge(bytes32 contractId) public view returns (bytes32) { return _getChallenge(contractId); } diff --git a/contracts/TestProofs.sol b/contracts/TestProofs.sol index 3fac3aa..81aab4a 100644 --- a/contracts/TestProofs.sol +++ b/contracts/TestProofs.sol @@ -44,6 +44,10 @@ contract TestProofs is Proofs { return _isProofRequired(id); } + function willProofBeRequired(bytes32 id) public view returns (bool) { + return _willProofBeRequired(id); + } + function getChallenge(bytes32 id) public view returns (bytes32) { return _getChallenge(id); } diff --git a/test/Proofs.test.js b/test/Proofs.test.js index 0fbed44..48b539d 100644 --- a/test/Proofs.test.js +++ b/test/Proofs.test.js @@ -109,6 +109,36 @@ describe("Proofs", function () { } }) + describe("when proof requirement is upcoming", function () { + async function waitUntilProofWillBeRequired() { + while (!(await proofs.willProofBeRequired(id))) { + await mine() + } + } + + beforeEach(async function () { + await proofs.expectProofs(id, probability, duration) + await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await waitUntilProofWillBeRequired() + }) + + it("means the pointer is in downtime", async function () { + expect(await proofs.getPointer(id)).to.be.lt(downtime) + while ((await proofs.getPointer(id)) < downtime) { + expect(await proofs.willProofBeRequired(id)).to.be.true + await mine() + } + }) + + it("means that a proof is required after downtime", async function () { + while ((await proofs.getPointer(id)) < downtime) { + await mine() + } + expect(await proofs.willProofBeRequired(id)).to.be.false + expect(await proofs.isProofRequired(id)).to.be.true + }) + }) + describe("when proofs are required", async function () { beforeEach(async function () { await proofs.expectProofs(id, probability, duration)