diff --git a/contracts/StorageContract.sol b/contracts/StorageContract.sol index 8212c5d..fd77b98 100644 --- a/contracts/StorageContract.sol +++ b/contracts/StorageContract.sol @@ -21,6 +21,7 @@ contract StorageContract { uint _price, uint _proofPeriod, uint _proofTimeout, + uint _bidExpiry, address _host, bytes memory requestSignature, bytes memory bidSignature) @@ -32,10 +33,11 @@ contract StorageContract { _proofPeriod, _proofTimeout ); - bytes32 bidHash = hashBid(requestHash, _price); + bytes32 bidHash = hashBid(requestHash, _bidExpiry, _price); checkSignature(requestSignature, requestHash, msg.sender); checkSignature(bidSignature, bidHash, _host); checkProofTimeout(_proofTimeout); + checkBidExpiry(_bidExpiry); duration = _duration; size = _size; price = _price; @@ -68,13 +70,14 @@ contract StorageContract { } // Creates hash for a storage bid that can be used to check its signature. - function hashBid(bytes32 requestHash, uint _price) + function hashBid(bytes32 requestHash, uint _expiry, uint _price) internal pure returns (bytes32) { return keccak256(abi.encodePacked( "[dagger.bid.v1]", requestHash, + _expiry, _price )); } @@ -95,6 +98,10 @@ contract StorageContract { require(timeout <= 128, "Invalid proof timeout, needs to be <= 128"); } + function checkBidExpiry(uint expiry) internal view { + require(expiry > block.timestamp, "Bid expired"); + } + // Check whether a proof is required at the time of the block with the // specified block number. A proof has to be submitted within the proof // timeout for it to be valid. Whether a proof is required is determined diff --git a/test/StorageContract.test.js b/test/StorageContract.test.js index 18f84cb..7377ee5 100644 --- a/test/StorageContract.test.js +++ b/test/StorageContract.test.js @@ -13,6 +13,7 @@ describe("Storage Contract", function () { var StorageContract var client, host + var bidExpiry var requestHash, bidHash var contract @@ -26,7 +27,8 @@ describe("Storage Contract", function () { proofPeriod, proofTimeout ) - bidHash = hashBid(requestHash, price) + bidExpiry = Math.round(Date.now() / 1000) + 60 * 60 // 1 hour from now + bidHash = hashBid(requestHash, bidExpiry, price) }) describe("when properly instantiated", function () { @@ -39,6 +41,7 @@ describe("Storage Contract", function () { price, proofPeriod, proofTimeout, + bidExpiry, await host.getAddress(), await sign(client, requestHash), await sign(host, bidHash) @@ -90,6 +93,7 @@ describe("Storage Contract", function () { price, proofPeriod, proofTimeout, + bidExpiry, await host.getAddress(), invalidSignature, await sign(host, bidHash) @@ -97,7 +101,8 @@ describe("Storage Contract", function () { }) it("cannot be created when host signature is invalid", async function () { - let invalidSignature = await sign(host, hashBid(requestHash, price - 1)) + let invalidBid = hashBid(requestHash, bidExpiry, price - 1) + let invalidSignature = await sign(host, invalidBid) await expect(StorageContract.deploy( duration, size, @@ -105,6 +110,7 @@ describe("Storage Contract", function () { price, proofPeriod, proofTimeout, + bidExpiry, await host.getAddress(), await sign(client, requestHash), invalidSignature @@ -120,7 +126,7 @@ describe("Storage Contract", function () { proofPeriod, invalidTimeout ) - bidHash = hashBid(requestHash, price) + bidHash = hashBid(requestHash, bidExpiry, price) await expect(StorageContract.deploy( duration, size, @@ -128,12 +134,30 @@ describe("Storage Contract", function () { price, proofPeriod, invalidTimeout, + bidExpiry, await host.getAddress(), await sign(client, requestHash), await sign(host, bidHash), )).to.be.revertedWith("Invalid proof timeout") }) + it("cannot be created when bid has expired", async function () { + let expired = Math.round(Date.now() / 1000) - 1 // 1 second ago + let bidHash = hashBid(requestHash, expired, price) + await expect(StorageContract.deploy( + duration, + size, + contentHash, + price, + proofPeriod, + proofTimeout, + expired, + await host.getAddress(), + await sign(client, requestHash), + await sign(host, bidHash), + )).to.be.revertedWith("Bid expired") + }) + describe("proofs", function () { async function mineBlock() { @@ -158,6 +182,7 @@ describe("Storage Contract", function () { price, proofPeriod, proofTimeout, + bidExpiry, await host.getAddress(), await sign(client, requestHash), await sign(host, bidHash) @@ -239,6 +264,4 @@ describe("Storage Contract", function () { // TODO: only allow proofs after start of contract // TODO: payout // TODO: stake -// TODO: request expiration -// TODO: bid expiration // TODO: multiple hosts in single contract diff --git a/test/marketplace.js b/test/marketplace.js index 2aad7cc..1af8452 100644 --- a/test/marketplace.js +++ b/test/marketplace.js @@ -7,10 +7,10 @@ function hashRequest(duration, size, hash, proofPeriod, proofTimeout) { ) } -function hashBid(requestHash, price) { +function hashBid(requestHash, expiry, price) { return ethers.utils.solidityKeccak256( - ["string", "bytes32", "uint"], - ["[dagger.bid.v1]", requestHash, price] + ["string", "bytes32", "uint", "uint"], + ["[dagger.bid.v1]", requestHash, expiry, price] ) }