mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 20:56:42 +00:00
161 lines
5.1 KiB
Solidity
161 lines
5.1 KiB
Solidity
/// @title Swarm Distributed Preimage Archive
|
|
/// @author Daniel A. Nagy <daniel@ethdev.com>
|
|
contract Swarm
|
|
{
|
|
|
|
uint constant GRACE = 50; // grace period for lost information in blocks
|
|
uint constant REWARD_FRACTION = 10; // this fraction of a deposit is paid as reward
|
|
|
|
bytes32 constant MAGIC_NUMBER = "Swarm receipt";
|
|
|
|
struct Bee {
|
|
uint deposit; // amount deposited by this member
|
|
uint expiry; // expiration time of the deposit
|
|
bytes32 missing; // member accused of losing this swarm chunk
|
|
uint deadline; // block number before which chunk must be presented
|
|
address reporter; // receipt reported by this address
|
|
}
|
|
|
|
mapping (address => Bee) swarm;
|
|
|
|
// block number of transactions presenting chunks
|
|
mapping (bytes32 => uint) presentedChunks;
|
|
|
|
function max(uint a, uint b) private returns (uint c) {
|
|
if(a >= b) return a;
|
|
return b;
|
|
}
|
|
|
|
/// @notice Sign up as a Swarm node for `time` seconds.
|
|
/// No term extension for nodes with non-clean status.
|
|
///
|
|
/// @dev Guards against term overflow and unauthorized extension,
|
|
/// but all funds are added to deposite irrespective of status.
|
|
///
|
|
/// @param time term of Swarm membership in seconds from now.
|
|
function signup(uint time) {
|
|
Bee b = swarm[tx.origin];
|
|
if(isClean(msg.sender) && now + time > now) {
|
|
b.expiry = max(b.expiry, now + time);
|
|
}
|
|
b.deposit += msg.value;
|
|
}
|
|
|
|
/// @notice Withdraw from Swarm, refund deposit.
|
|
///
|
|
/// @dev Only allowed with clean status and expired term.
|
|
function withdraw() {
|
|
Bee b = swarm[tx.origin];
|
|
if(now > b.expiry && isClean(msg.sender)) {
|
|
msg.sender.send(b.deposit);
|
|
b.deposit = 0;
|
|
}
|
|
}
|
|
|
|
/// @notice Total deposit for address `addr`.
|
|
/// No change in state.
|
|
///
|
|
/// @dev Not meaningful for "Guilty" status.
|
|
///
|
|
/// @param addr queried address.
|
|
///
|
|
/// @return balance of queried address.
|
|
function balance(address addr) returns (uint d) {
|
|
Bee b = swarm[addr];
|
|
return b.deposit;
|
|
}
|
|
|
|
/// @notice Determine clean status of address `addr`.
|
|
/// Changes the state, but only as a matter of optimization.
|
|
/// Works as accessor.
|
|
///
|
|
/// @dev Defined as no signed receipt has been presented for missing chunk.
|
|
///
|
|
/// @param addr queried address.
|
|
///
|
|
/// @return true if status is "Clean".
|
|
function isClean(address addr) returns (bool s) {
|
|
Bee b = swarm[addr];
|
|
if(b.missing != 0 && presentedChunks[b.missing] != 0) b.missing = 0;
|
|
return b.missing == 0; // nothing they signed is missing
|
|
}
|
|
|
|
/// @param suspect address of reported Swarm node
|
|
event Report(address suspect);
|
|
|
|
/// @notice Find out what is missing in case of a Report event.
|
|
///
|
|
/// @return 0 if nothing is missing, swarm hash otherwise
|
|
function whatIsMissing() returns (bytes32 h) {
|
|
bytes32 missing = swarm[tx.origin].missing;
|
|
if(presentedChunks[missing] != 0) missing = 0;
|
|
return missing;
|
|
}
|
|
|
|
/// @notice Report chunk `swarmHash` as missing.
|
|
///
|
|
/// @param swarmHash sha3 hash of the missing chunk
|
|
/// @param expiry expiration time of receipt
|
|
/// @param sig_v signature parameter v
|
|
/// @param sig_r signature parameter r
|
|
/// @param sig_s signature parameter s
|
|
function reportMissingChunk(bytes32 swarmHash, uint expiry,
|
|
uint8 sig_v, bytes32 sig_r, bytes32 sig_s) {
|
|
if(expiry < now) return;
|
|
bytes32 recptHash = sha3(MAGIC_NUMBER, swarmHash, expiry);
|
|
address signer = ecrecover(recptHash, sig_v, sig_r, sig_s);
|
|
if(!isClean(signer) || !expiresAfter(signer, now)) return;
|
|
Bee b = swarm[signer];
|
|
b.missing = swarmHash;
|
|
b.deadline = block.number + GRACE;
|
|
b.reporter = msg.sender;
|
|
Report(signer);
|
|
}
|
|
|
|
/// @notice Present a chunk in order to avoid losing deposit.
|
|
///
|
|
/// @param chunk chunk data
|
|
function presentMissingChunk(bytes chunk) external {
|
|
bytes32 swarmHash = sha3(chunk);
|
|
presentedChunks[swarmHash] = block.number;
|
|
}
|
|
|
|
/// @notice Determine guilty status of address `addr`.
|
|
/// No change in state.
|
|
///
|
|
/// @dev Definition of guilty is failing to present missing chunk within grace period.
|
|
///
|
|
/// @param addr queried address.
|
|
///
|
|
/// @return true, if status is "Guilty".
|
|
function isGuilty(address addr) returns (bool g){
|
|
if(isClean(addr)) return false;
|
|
Bee b = swarm[addr];
|
|
return b.deadline < block.number;
|
|
}
|
|
|
|
/// @notice Collect rewards for successfully prosecuting `addr`.
|
|
///
|
|
/// @dev This implies burning 9/10 of the security deposit.
|
|
///
|
|
/// @param addr guilty defendant address
|
|
function claimReporterReward(address addr) {
|
|
if(!isGuilty(addr)) return;
|
|
Bee b = swarm[addr];
|
|
msg.sender.send(b.deposit / REWARD_FRACTION); // reporter rewarded
|
|
delete swarm[addr]; // rest of deposit burnt
|
|
}
|
|
|
|
/// @notice Determine if the deposit for `addr` is unaccessible until `time`.
|
|
/// No change in state.
|
|
///
|
|
/// @param addr queried address.
|
|
///
|
|
/// @param time queried time.
|
|
///
|
|
/// @return true if deposit expires after queried time.
|
|
function expiresAfter(address addr, uint time) returns (bool s) {
|
|
Bee b = swarm[addr];
|
|
return b.expiry > time;
|
|
}
|
|
}
|