Use bid hash as contract id

Adds nonce to storage request to ensure uniqueness.
This commit is contained in:
Mark Spanbroek 2021-10-20 14:28:05 +02:00
parent 08cedae4bf
commit c3e85c675a
3 changed files with 44 additions and 34 deletions

View File

@ -20,48 +20,48 @@ contract StorageContracts {
}
uint numberOfContracts;
mapping(uint => Contract) contracts;
mapping(bytes32 => Contract) contracts;
function duration(uint contractId) public view returns (uint) {
function duration(bytes32 contractId) public view returns (uint) {
return contracts[contractId].duration;
}
function size(uint contractId) public view returns (uint) {
function size(bytes32 contractId) public view returns (uint) {
return contracts[contractId].size;
}
function contentHash(uint contractId) public view returns (bytes32) {
function contentHash(bytes32 contractId) public view returns (bytes32) {
return contracts[contractId].contentHash;
}
function price(uint contractId) public view returns (uint) {
function price(bytes32 contractId) public view returns (uint) {
return contracts[contractId].price;
}
function host(uint contractId) public view returns (address) {
function host(bytes32 contractId) public view returns (address) {
return contracts[contractId].host;
}
function proofPeriod(uint contractId) public view returns (uint) {
function proofPeriod(bytes32 contractId) public view returns (uint) {
return contracts[contractId].proofPeriod;
}
function proofTimeout(uint contractId) public view returns (uint) {
function proofTimeout(bytes32 contractId) public view returns (uint) {
return contracts[contractId].proofTimeout;
}
function missingProofs(uint contractId) public view returns (uint) {
function missingProofs(bytes32 contractId) public view returns (uint) {
return contracts[contractId].missingProofs;
}
function newContract(
uint contractId,
uint _duration,
uint _size,
bytes32 _contentHash,
uint _price,
uint _proofPeriod,
uint _proofTimeout,
bytes32 _nonce,
uint _bidExpiry,
address _host,
bytes memory requestSignature,
@ -74,13 +74,15 @@ contract StorageContracts {
_size,
_contentHash,
_proofPeriod,
_proofTimeout
_proofTimeout,
_nonce
);
bytes32 bidHash = hashBid(requestHash, _bidExpiry, _price);
checkSignature(requestSignature, requestHash, msg.sender);
checkSignature(bidSignature, bidHash, _host);
checkProofTimeout(_proofTimeout);
checkBidExpiry(_bidExpiry);
bytes32 contractId = bidHash;
checkId(contractId);
Contract storage c = contracts[contractId];
c.initialized = true;
@ -100,7 +102,8 @@ contract StorageContracts {
uint _size,
bytes32 _hash,
uint _proofPeriod,
uint _proofTimeout
uint _proofTimeout,
bytes32 _nonce
)
internal pure
returns (bytes32)
@ -111,7 +114,8 @@ contract StorageContracts {
_size,
_hash,
_proofPeriod,
_proofTimeout
_proofTimeout,
_nonce
));
}
@ -148,7 +152,7 @@ contract StorageContracts {
require(expiry > block.timestamp, "Bid expired");
}
function checkId(uint contractId) internal view {
function checkId(bytes32 contractId) internal view {
require(
!contracts[contractId].initialized,
"A contract with this id already exists"
@ -160,7 +164,7 @@ contract StorageContracts {
// timeout for it to be valid. Whether a proof is required is determined
// randomly, but on average it is once every proof period.
function isProofRequired(
uint contractId,
bytes32 contractId,
uint blocknumber
)
public view
@ -172,7 +176,7 @@ contract StorageContracts {
}
function isProofTimedOut(
uint contractId,
bytes32 contractId,
uint blocknumber
)
internal view
@ -183,7 +187,7 @@ contract StorageContracts {
}
function submitProof(
uint contractId,
bytes32 contractId,
uint blocknumber,
bool proof
)
@ -203,7 +207,7 @@ contract StorageContracts {
c.proofReceived[blocknumber] = true;
}
function markProofAsMissing(uint contractId, uint blocknumber) public {
function markProofAsMissing(bytes32 contractId, uint blocknumber) public {
Contract storage c = contracts[contractId];
require(
isProofTimedOut(contractId, blocknumber),

View File

@ -10,6 +10,7 @@ describe("Storage Contracts", function () {
const proofPeriod = 8 // 8 blocks ≈ 2 minutes
const proofTimeout = 4 // 4 blocks ≈ 1 minute
const price = 42
const nonce = ethers.utils.randomBytes(32)
var contracts
var client, host
@ -26,24 +27,25 @@ describe("Storage Contracts", function () {
size,
contentHash,
proofPeriod,
proofTimeout
proofTimeout,
nonce
)
bidExpiry = Math.round(Date.now() / 1000) + 60 * 60 // 1 hour from now
bidHash = hashBid(requestHash, bidExpiry, price)
id = Math.round(Math.random() * 99999999) // randomly chosen contract id
id = bidHash
})
describe("when properly instantiated", function () {
beforeEach(async function () {
await contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
proofTimeout,
nonce,
bidExpiry,
await host.getAddress(),
await sign(client, requestHash),
@ -82,26 +84,26 @@ describe("Storage Contracts", function () {
it("cannot be created when contract id already used", async function () {
await contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
proofTimeout,
nonce,
bidExpiry,
await host.getAddress(),
await sign(client, requestHash),
await sign(host, bidHash)
)
await expect(contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
proofTimeout,
nonce,
bidExpiry,
await host.getAddress(),
await sign(client, requestHash),
@ -115,17 +117,18 @@ describe("Storage Contracts", function () {
size,
contentHash,
proofPeriod,
proofTimeout
proofTimeout,
nonce
)
let invalidSignature = await sign(client, invalidHash)
await expect(contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
proofTimeout,
nonce,
bidExpiry,
await host.getAddress(),
invalidSignature,
@ -137,13 +140,13 @@ describe("Storage Contracts", function () {
let invalidBid = hashBid(requestHash, bidExpiry, price - 1)
let invalidSignature = await sign(host, invalidBid)
await expect(contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
proofTimeout,
nonce,
bidExpiry,
await host.getAddress(),
await sign(client, requestHash),
@ -158,17 +161,18 @@ describe("Storage Contracts", function () {
size,
contentHash,
proofPeriod,
invalidTimeout
invalidTimeout,
nonce
)
bidHash = hashBid(requestHash, bidExpiry, price)
await expect(contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
invalidTimeout,
nonce,
bidExpiry,
await host.getAddress(),
await sign(client, requestHash),
@ -180,13 +184,13 @@ describe("Storage Contracts", function () {
let expired = Math.round(Date.now() / 1000) - 60 // 1 minute ago
let bidHash = hashBid(requestHash, expired, price)
await expect(contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
proofTimeout,
nonce,
expired,
await host.getAddress(),
await sign(client, requestHash),
@ -218,13 +222,13 @@ describe("Storage Contracts", function () {
beforeEach(async function () {
await contracts.newContract(
id,
duration,
size,
contentHash,
price,
proofPeriod,
proofTimeout,
nonce,
bidExpiry,
await host.getAddress(),
await sign(client, requestHash),

View File

@ -1,16 +1,18 @@
const { ethers } = require("hardhat")
function hashRequest(duration, size, hash, proofPeriod, proofTimeout) {
function hashRequest(duration, size, hash, proofPeriod, proofTimeout, nonce) {
const type = "[dagger.request.v1]"
return ethers.utils.solidityKeccak256(
["string", "uint", "uint", "bytes32", "uint", "uint"],
["[dagger.request.v1]", duration, size, hash, proofPeriod, proofTimeout]
["string", "uint", "uint", "bytes32", "uint", "uint", "bytes32"],
[type, duration, size, hash, proofPeriod, proofTimeout, nonce]
)
}
function hashBid(requestHash, expiry, price) {
const type = "[dagger.bid.v1]"
return ethers.utils.solidityKeccak256(
["string", "bytes32", "uint", "uint"],
["[dagger.bid.v1]", requestHash, expiry, price]
[type, requestHash, expiry, price]
)
}