forked from NebulousLabs/Sia
/
filecontracts.go
129 lines (118 loc) · 5.7 KB
/
filecontracts.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package types
// filecontracts.go contains the basic structs and helper functions for file
// contracts.
import (
"github.com/NebulousLabs/Sia/crypto"
)
var (
// ProofMissed indicates that a StorageProof was missed, which means that
// no valid proof was submitted within the proof window.
ProofMissed ProofStatus = false
// ProofValid indicates that a valid StorageProof was submitted within the
// proof window.
ProofValid ProofStatus = true
)
type (
// A FileContract is a public record of a storage agreement between a "host"
// and a "renter." It mandates that a host must submit a storage proof to the
// network, proving that they still possess the file they have agreed to
// store.
//
// The party must submit the storage proof in a block that is between
// 'WindowStart' and 'WindowEnd'. Upon submitting the proof, the outputs
// for 'ValidProofOutputs' are created. If the party does not submit a
// storage proof by 'WindowEnd', then the outputs for 'MissedProofOutputs'
// are created instead. The sum of 'MissedProofOutputs' and the sum of
// 'ValidProofOutputs' must equal 'Payout' minus the siafund fee. This fee
// is sent to the siafund pool, which is a set of siacoins only spendable
// by siafund owners.
//
// Under normal circumstances, the payout will be funded by both the host and
// the renter, which gives the host incentive not to lose the file. The
// 'ValidProofUnlockHash' will typically be spendable by host, and the
// 'MissedProofUnlockHash' will either by spendable by the renter or by
// nobody (the ZeroUnlockHash).
//
// A contract can be terminated early by submitting a FileContractTermination
// whose UnlockConditions hash to 'TerminationHash'.
FileContract struct {
FileSize uint64 `json:"filesize"`
FileMerkleRoot crypto.Hash `json:"filemerkleroot"`
WindowStart BlockHeight `json:"windowstart"`
WindowEnd BlockHeight `json:"windowend"`
Payout Currency `json:"payout"`
ValidProofOutputs []SiacoinOutput `json:"validproofoutputs"`
MissedProofOutputs []SiacoinOutput `json:"missedproofoutputs"`
UnlockHash UnlockHash `json:"unlockhash"`
RevisionNumber uint64 `json:"revisionnumber"`
}
// A FileContractRevision revises an existing file contract. The ParentID
// points to the file contract that is being revised. The UnlockConditions
// are the conditions under which the revision is valid, and must match the
// UnlockHash of the parent file contract. The Payout of the file contract
// cannot be changed, but all other fields are allowed to be changed. The
// sum of the outputs must match the original payout (taking into account
// the fee for the proof payouts.) A revision number is included. When
// getting accepted, the revision number of the revision must be higher
// than any previously seen revision number for that file contract.
//
// FileContractRevisions enable trust-free modifications to existing file
// contracts.
FileContractRevision struct {
ParentID FileContractID `json:"parentid"`
UnlockConditions UnlockConditions `json:"unlockconditions"`
NewRevisionNumber uint64 `json:"newrevisionnumber"`
NewFileSize uint64 `json:"newfilesize"`
NewFileMerkleRoot crypto.Hash `json:"newfilemerkleroot"`
NewWindowStart BlockHeight `json:"newwindowstart"`
NewWindowEnd BlockHeight `json:"newwindowend"`
NewValidProofOutputs []SiacoinOutput `json:"newvalidproofoutputs"`
NewMissedProofOutputs []SiacoinOutput `json:"newmissedproofoutputs"`
NewUnlockHash UnlockHash `json:"newunlockhash"`
}
// A StorageProof fulfills a FileContract. The proof contains a specific
// segment of the file, along with a set of hashes from the file's Merkle
// tree. In combination, these can be used to prove that the segment came
// from the file. To prevent abuse, the segment must be chosen randomly, so
// the ID of block 'WindowStart' - 1 is used as a seed value; see
// StorageProofSegment for the exact implementation.
//
// A transaction with a StorageProof cannot have any SiacoinOutputs,
// SiafundOutputs, or FileContracts. This is because a mundane reorg can
// invalidate the proof, and with it the rest of the transaction.
StorageProof struct {
ParentID FileContractID `json:"parentid"`
Segment [crypto.SegmentSize]byte `json:"segment"`
HashSet []crypto.Hash `json:"hashset"`
}
// ProofStatus indicates whether a StorageProof was valid (true) or missed (false).
ProofStatus bool
)
// StorageProofOutputID returns the ID of an output created by a file
// contract, given the status of the storage proof. The ID is calculating by
// hashing the concatenation of the StorageProofOutput Specifier, the ID of
// the file contract that the proof is for, a boolean indicating whether the
// proof was valid (true) or missed (false), and the index of the output
// within the file contract.
func (fcid FileContractID) StorageProofOutputID(proofStatus ProofStatus, i uint64) SiacoinOutputID {
return SiacoinOutputID(crypto.HashAll(
SpecifierStorageProofOutput,
fcid,
proofStatus,
i,
))
}
// PostTax returns the amount of currency remaining in a file contract payout
// after tax.
func PostTax(height BlockHeight, payout Currency) Currency {
return payout.Sub(Tax(height, payout))
}
// Tax returns the amount of Currency that will be taxed from fc.
func Tax(height BlockHeight, payout Currency) Currency {
// COMPATv0.4.0 - until the first 20,000 blocks have been archived, they
// will need to be handled in a special way.
if height < TaxHardforkHeight {
return payout.MulFloat(0.039).RoundDown(SiafundCount)
}
return payout.MulTax().RoundDown(SiafundCount)
}