2021-10-12 14:59:34 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.8.0;
|
|
|
|
|
|
|
|
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
|
|
|
|
|
|
contract StorageContract {
|
|
|
|
uint public immutable duration; // contract duration in seconds
|
|
|
|
uint public immutable size; // storage size in bytes
|
2021-10-14 12:49:29 +00:00
|
|
|
bytes32 public immutable contentHash; // hash of data that is to be stored
|
2021-10-12 14:59:34 +00:00
|
|
|
uint public immutable price; // price in coins
|
|
|
|
address public immutable host; // host that provides storage
|
2021-10-14 07:10:57 +00:00
|
|
|
uint public immutable proofPeriod; // average time between proofs (in blocks)
|
|
|
|
uint public immutable proofTimeout; // proof has to be submitted before this
|
2021-10-14 10:37:14 +00:00
|
|
|
uint public immutable proofMarker; // indicates when a proof is required
|
2021-10-12 14:59:34 +00:00
|
|
|
|
|
|
|
constructor(uint _duration,
|
|
|
|
uint _size,
|
2021-10-14 12:49:29 +00:00
|
|
|
bytes32 _contentHash,
|
2021-10-12 14:59:34 +00:00
|
|
|
uint _price,
|
2021-10-14 07:10:57 +00:00
|
|
|
uint _proofPeriod,
|
|
|
|
uint _proofTimeout,
|
2021-10-12 14:59:34 +00:00
|
|
|
address _host,
|
|
|
|
bytes memory requestSignature,
|
|
|
|
bytes memory bidSignature)
|
|
|
|
{
|
2021-10-14 12:49:29 +00:00
|
|
|
bytes32 requestHash = hashRequest(
|
|
|
|
_duration,
|
|
|
|
_size,
|
|
|
|
_contentHash,
|
|
|
|
_proofPeriod,
|
|
|
|
_proofTimeout
|
|
|
|
);
|
2021-10-12 14:59:34 +00:00
|
|
|
bytes32 bidHash = hashBid(requestHash, _price);
|
|
|
|
checkSignature(requestSignature, requestHash, msg.sender);
|
|
|
|
checkSignature(bidSignature, bidHash, _host);
|
2021-10-14 10:37:14 +00:00
|
|
|
checkProofTimeout(_proofTimeout);
|
2021-10-12 14:59:34 +00:00
|
|
|
duration = _duration;
|
|
|
|
size = _size;
|
|
|
|
price = _price;
|
2021-10-14 12:49:29 +00:00
|
|
|
contentHash = _contentHash;
|
2021-10-12 14:59:34 +00:00
|
|
|
host = _host;
|
2021-10-14 07:10:57 +00:00
|
|
|
proofPeriod = _proofPeriod;
|
|
|
|
proofTimeout = _proofTimeout;
|
2021-10-14 10:37:14 +00:00
|
|
|
proofMarker = uint(blockhash(block.number - 1)) % _proofPeriod;
|
2021-10-12 14:59:34 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 10:37:14 +00:00
|
|
|
// Creates hash for a storage request that can be used to check its signature.
|
2021-10-14 12:49:29 +00:00
|
|
|
function hashRequest(
|
|
|
|
uint _duration,
|
|
|
|
uint _size,
|
|
|
|
bytes32 _hash,
|
|
|
|
uint _proofPeriod,
|
|
|
|
uint _proofTimeout
|
|
|
|
)
|
2021-10-12 14:59:34 +00:00
|
|
|
internal pure
|
|
|
|
returns (bytes32)
|
|
|
|
{
|
|
|
|
return keccak256(abi.encodePacked(
|
|
|
|
"[dagger.request.v1]",
|
|
|
|
_duration,
|
2021-10-14 12:01:28 +00:00
|
|
|
_size,
|
2021-10-14 12:49:29 +00:00
|
|
|
_hash,
|
2021-10-14 12:01:28 +00:00
|
|
|
_proofPeriod,
|
|
|
|
_proofTimeout
|
2021-10-12 14:59:34 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2021-10-14 10:37:14 +00:00
|
|
|
// Creates hash for a storage bid that can be used to check its signature.
|
2021-10-12 14:59:34 +00:00
|
|
|
function hashBid(bytes32 requestHash, uint _price)
|
|
|
|
internal pure
|
|
|
|
returns (bytes32)
|
|
|
|
{
|
|
|
|
return keccak256(abi.encodePacked(
|
|
|
|
"[dagger.bid.v1]",
|
|
|
|
requestHash,
|
|
|
|
_price
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2021-10-14 10:37:14 +00:00
|
|
|
// Checks a signature for a storage request or bid, given its hash.
|
2021-10-12 14:59:34 +00:00
|
|
|
function checkSignature(bytes memory signature, bytes32 hash, address signer)
|
|
|
|
internal pure
|
|
|
|
{
|
|
|
|
bytes32 messageHash = ECDSA.toEthSignedMessageHash(hash);
|
|
|
|
address recovered = ECDSA.recover(messageHash, signature);
|
|
|
|
require(recovered == signer, "Invalid signature");
|
|
|
|
}
|
|
|
|
|
2021-10-14 10:37:14 +00:00
|
|
|
// Checks that proof timeout is <= 128. Only the latest 256 blocks can be
|
|
|
|
// checked in a smart contract, so that leaves a period of at least 128 blocks
|
|
|
|
// after timeout for a validator to signal the absence of a proof.
|
|
|
|
function checkProofTimeout(uint timeout) internal pure {
|
|
|
|
require(timeout <= 128, "Invalid proof timeout, needs to be <= 128");
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// randomly, but on average it is once every proof period.
|
|
|
|
function isProofRequired(uint blocknumber) public view returns (bool) {
|
|
|
|
bytes32 hash = blockhash(blocknumber);
|
|
|
|
return hash != 0 && uint(hash) % proofPeriod == proofMarker;
|
|
|
|
}
|
2021-10-12 14:59:34 +00:00
|
|
|
}
|