Skip to content

Commit

Permalink
Merge pull request #235 from SiaFoundation/siafund-pool
Browse files Browse the repository at this point in the history
consensus: Rename SiafundPool -> SiafundTaxRevenue
  • Loading branch information
n8maninger authored Dec 3, 2024
2 parents 02a4796 + f813cd9 commit 866a892
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 33 deletions.
37 changes: 16 additions & 21 deletions consensus/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ func (n *Network) GenesisState() State {
return State{
Network: n,

Index: types.ChainIndex{Height: ^uint64(0)},
PrevTimestamps: [11]time.Time{},
Depth: intToTarget(maxTarget),
ChildTarget: n.InitialTarget,
SiafundPool: types.ZeroCurrency,
Index: types.ChainIndex{Height: ^uint64(0)},
PrevTimestamps: [11]time.Time{},
Depth: intToTarget(maxTarget),
ChildTarget: n.InitialTarget,
SiafundTaxRevenue: types.ZeroCurrency,

OakTime: 0,
OakTarget: intToTarget(maxTarget),
Expand All @@ -111,11 +111,11 @@ func (n *Network) GenesisState() State {
type State struct {
Network *Network `json:"-"` // network parameters are not encoded

Index types.ChainIndex `json:"index"`
PrevTimestamps [11]time.Time `json:"prevTimestamps"` // newest -> oldest
Depth types.BlockID `json:"depth"`
ChildTarget types.BlockID `json:"childTarget"`
SiafundPool types.Currency `json:"siafundPool"`
Index types.ChainIndex `json:"index"`
PrevTimestamps [11]time.Time `json:"prevTimestamps"` // newest -> oldest
Depth types.BlockID `json:"depth"`
ChildTarget types.BlockID `json:"childTarget"`
SiafundTaxRevenue types.Currency `json:"siafundTaxRevenue"`

// Oak hardfork state
OakTime time.Duration `json:"oakTime"`
Expand All @@ -139,7 +139,7 @@ func (s State) EncodeTo(e *types.Encoder) {
}
s.Depth.EncodeTo(e)
s.ChildTarget.EncodeTo(e)
types.V2Currency(s.SiafundPool).EncodeTo(e)
types.V2Currency(s.SiafundTaxRevenue).EncodeTo(e)

e.WriteUint64(uint64(s.OakTime))
s.OakTarget.EncodeTo(e)
Expand All @@ -160,7 +160,7 @@ func (s *State) DecodeFrom(d *types.Decoder) {
}
s.Depth.DecodeFrom(d)
s.ChildTarget.DecodeFrom(d)
(*types.V2Currency)(&s.SiafundPool).DecodeFrom(d)
(*types.V2Currency)(&s.SiafundTaxRevenue).DecodeFrom(d)

s.OakTime = time.Duration(d.ReadUint64())
s.OakTarget.DecodeFrom(d)
Expand Down Expand Up @@ -374,12 +374,7 @@ func (s State) FileContractTax(fc types.FileContract) types.Currency {

// V2FileContractTax computes the tax levied on a given v2 contract.
func (s State) V2FileContractTax(fc types.V2FileContract) types.Currency {
sum := fc.RenterOutput.Value.Add(fc.HostOutput.Value)
tax := sum.Div64(25) // 4%
// round down to nearest multiple of SiafundCount
_, r := bits.Div64(0, tax.Hi, s.SiafundCount())
_, r = bits.Div64(r, tax.Lo, s.SiafundCount())
return tax.Sub(types.NewCurrency64(r))
return fc.RenterOutput.Value.Add(fc.HostOutput.Value).Div64(25) // 4%
}

// StorageProofLeafIndex returns the leaf index used when computing or
Expand Down Expand Up @@ -537,7 +532,7 @@ func (s State) PartialSigHash(txn types.Transaction, cf types.CoveredFields) typ

// TransactionsCommitment returns the commitment hash covering the transactions
// that comprise a child block.
func (s *State) TransactionsCommitment(txns []types.Transaction, v2txns []types.V2Transaction) types.Hash256 {
func (s State) TransactionsCommitment(txns []types.Transaction, v2txns []types.V2Transaction) types.Hash256 {
var acc blake2b.Accumulator
for _, txn := range txns {
acc.AddLeaf(txn.FullHash())
Expand Down Expand Up @@ -598,7 +593,7 @@ type MidState struct {
res map[types.FileContractID]bool
v2revs map[types.FileContractID]*types.V2FileContractElement
v2res map[types.FileContractID]types.V2FileContractResolutionType
siafundPool types.Currency
siafundTaxRevenue types.Currency
foundationSubsidy types.Address
foundationManagement types.Address

Expand Down Expand Up @@ -660,7 +655,7 @@ func NewMidState(s State) *MidState {
res: make(map[types.FileContractID]bool),
v2revs: make(map[types.FileContractID]*types.V2FileContractElement),
v2res: make(map[types.FileContractID]types.V2FileContractResolutionType),
siafundPool: s.SiafundPool,
siafundTaxRevenue: s.SiafundTaxRevenue,
foundationSubsidy: s.FoundationSubsidyAddress,
foundationManagement: s.FoundationManagementAddress,
}
Expand Down
12 changes: 6 additions & 6 deletions consensus/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ func (ms *MidState) addSiafundElement(id types.SiafundOutputID, sfo types.Siafun
StateElement: types.StateElement{LeafIndex: types.UnassignedLeafIndex},
ID: id,
SiafundOutput: sfo,
ClaimStart: ms.siafundPool,
ClaimStart: ms.siafundTaxRevenue,
}
ms.sfes = append(ms.sfes, sfe)
ms.created[ms.sfes[len(ms.sfes)-1].ID] = len(ms.sfes) - 1
Expand All @@ -389,7 +389,7 @@ func (ms *MidState) addFileContractElement(id types.FileContractID, fc types.Fil
}
ms.fces = append(ms.fces, fce)
ms.created[ms.fces[len(ms.fces)-1].ID] = len(ms.fces) - 1
ms.siafundPool = ms.siafundPool.Add(ms.base.FileContractTax(fce.FileContract))
ms.siafundTaxRevenue = ms.siafundTaxRevenue.Add(ms.base.FileContractTax(fce.FileContract))
}

func (ms *MidState) reviseFileContractElement(fce types.FileContractElement, rev types.FileContract) {
Expand Down Expand Up @@ -426,7 +426,7 @@ func (ms *MidState) addV2FileContractElement(id types.FileContractID, fc types.V
}
ms.v2fces = append(ms.v2fces, fce)
ms.created[ms.v2fces[len(ms.v2fces)-1].ID] = len(ms.v2fces) - 1
ms.siafundPool = ms.siafundPool.Add(ms.base.V2FileContractTax(fce.V2FileContract))
ms.siafundTaxRevenue = ms.siafundTaxRevenue.Add(ms.base.V2FileContractTax(fce.V2FileContract))
}

func (ms *MidState) reviseV2FileContractElement(fce types.V2FileContractElement, rev types.V2FileContract) {
Expand Down Expand Up @@ -477,7 +477,7 @@ func (ms *MidState) ApplyTransaction(txn types.Transaction, ts V1TransactionSupp
if !ok {
panic("missing SiafundElement")
}
claimPortion := ms.siafundPool.Sub(sfe.ClaimStart).Div64(ms.base.SiafundCount()).Mul64(sfe.SiafundOutput.Value)
claimPortion := ms.siafundTaxRevenue.Sub(sfe.ClaimStart).Div64(ms.base.SiafundCount()).Mul64(sfe.SiafundOutput.Value)
ms.spendSiafundElement(sfe, txid)
ms.addImmatureSiacoinElement(sfi.ParentID.ClaimOutputID(), types.SiacoinOutput{Value: claimPortion, Address: sfi.ClaimAddress})
}
Expand Down Expand Up @@ -528,7 +528,7 @@ func (ms *MidState) ApplyV2Transaction(txn types.V2Transaction) {
}
for _, sfi := range txn.SiafundInputs {
ms.spendSiafundElement(sfi.Parent, txid)
claimPortion := ms.siafundPool.Sub(sfi.Parent.ClaimStart).Div64(ms.base.SiafundCount()).Mul64(sfi.Parent.SiafundOutput.Value)
claimPortion := ms.siafundTaxRevenue.Sub(sfi.Parent.ClaimStart).Div64(ms.base.SiafundCount()).Mul64(sfi.Parent.SiafundOutput.Value)
ms.addImmatureSiacoinElement(sfi.Parent.ID.V2ClaimOutputID(), types.SiacoinOutput{Value: claimPortion, Address: sfi.ClaimAddress})
}
for i, sfo := range txn.SiafundOutputs {
Expand Down Expand Up @@ -739,7 +739,7 @@ func ApplyBlock(s State, b types.Block, bs V1BlockSupplement, targetTimestamp ti

ms := NewMidState(s)
ms.ApplyBlock(b, bs)
s.SiafundPool = ms.siafundPool
s.SiafundTaxRevenue = ms.siafundTaxRevenue
s.Attestations += uint64(len(ms.aes))
s.FoundationSubsidyAddress = ms.foundationSubsidy
s.FoundationManagementAddress = ms.foundationManagement
Expand Down
134 changes: 129 additions & 5 deletions consensus/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1089,11 +1089,6 @@ func TestApplyRevertBlockV2(t *testing.T) {
checkUpdateElements(au, addedSCEs, spentSCEs, addedSFEs, spentSFEs)
}

_ = renterPublicKey
_ = hostPublicKey
_ = checkRevertElements
_ = prev

// revert block spending sc and sf
ru := RevertBlock(prev, b2, V1BlockSupplement{})
cs = prev
Expand Down Expand Up @@ -1297,6 +1292,135 @@ func TestApplyRevertBlockV2(t *testing.T) {
}
}

func TestSiafunds(t *testing.T) {
n, genesisBlock := testnet()
n.HardforkV2.AllowHeight = 1
n.HardforkV2.RequireHeight = 2

key := types.GeneratePrivateKey()

giftAddress := types.StandardAddress(key.PublicKey())
giftAmountSC := types.Siacoins(100e3)
giftAmountSF := uint64(1000)
giftTxn := types.Transaction{
SiacoinOutputs: []types.SiacoinOutput{
{Address: giftAddress, Value: giftAmountSC},
},
SiafundOutputs: []types.SiafundOutput{
{Address: giftAddress, Value: giftAmountSF},
},
}
genesisBlock.Transactions = []types.Transaction{giftTxn}
db, cs := newConsensusDB(n, genesisBlock)

signTxn := func(cs State, txn *types.V2Transaction) {
for i := range txn.SiacoinInputs {
txn.SiacoinInputs[i].SatisfiedPolicy = types.SatisfiedPolicy{
Policy: types.PolicyPublicKey(key.PublicKey()),
Signatures: []types.Signature{key.SignHash(cs.InputSigHash(*txn))},
}
}
for i := range txn.SiafundInputs {
txn.SiafundInputs[i].SatisfiedPolicy = types.SatisfiedPolicy{
Policy: types.PolicyPublicKey(key.PublicKey()),
Signatures: []types.Signature{key.SignHash(cs.InputSigHash(*txn))},
}
}
for i := range txn.FileContracts {
txn.FileContracts[i].RenterSignature = key.SignHash(cs.ContractSigHash(txn.FileContracts[i]))
txn.FileContracts[i].HostSignature = key.SignHash(cs.ContractSigHash(txn.FileContracts[i]))
}
}
mineTxns := func(txns []types.Transaction, v2txns []types.V2Transaction) (au ApplyUpdate, err error) {
b := types.Block{
ParentID: cs.Index.ID,
Timestamp: types.CurrentTimestamp(),
MinerPayouts: []types.SiacoinOutput{{Address: types.VoidAddress, Value: cs.BlockReward()}},
Transactions: txns,
}
if len(v2txns) > 0 {
b.V2 = &types.V2BlockData{
Height: cs.Index.Height + 1,
Commitment: cs.Commitment(cs.TransactionsCommitment(txns, v2txns), b.MinerPayouts[0].Address),
Transactions: v2txns,
}
}
findBlockNonce(cs, &b)
if err = ValidateBlock(cs, b, V1BlockSupplement{}); err != nil {
return
}
cs, au = ApplyBlock(cs, b, V1BlockSupplement{}, db.ancestorTimestamp(b.ParentID))
db.applyBlock(au)
return
}

fc := types.V2FileContract{
ProofHeight: 20,
ExpirationHeight: 30,
RenterOutput: types.SiacoinOutput{Value: types.Siacoins(5000)},
HostOutput: types.SiacoinOutput{Value: types.Siacoins(5000)},
RenterPublicKey: key.PublicKey(),
HostPublicKey: key.PublicKey(),
}
fcValue := fc.RenterOutput.Value.Add(fc.HostOutput.Value).Add(cs.V2FileContractTax(fc))

txn := types.V2Transaction{
SiacoinInputs: []types.V2SiacoinInput{{
Parent: db.sces[giftTxn.SiacoinOutputID(0)],
}},
SiacoinOutputs: []types.SiacoinOutput{{
Address: giftAddress,
Value: giftAmountSC.Sub(fcValue),
}},
FileContracts: []types.V2FileContract{fc},
}
signTxn(cs, &txn)
prev := cs
if _, err := mineTxns(nil, []types.V2Transaction{txn}); err != nil {
t.Fatal(err)
}
// siafund revenue should have increased
if cs.SiafundTaxRevenue != prev.SiafundTaxRevenue.Add(cs.V2FileContractTax(fc)) {
t.Fatalf("expected %v siafund revenue, got %v", prev.SiafundTaxRevenue.Add(cs.V2FileContractTax(fc)), cs.SiafundTaxRevenue)
}

// make a siafund claim
txn = types.V2Transaction{
SiafundInputs: []types.V2SiafundInput{{
Parent: db.sfes[giftTxn.SiafundOutputID(0)],
ClaimAddress: giftAddress,
}},
SiafundOutputs: []types.SiafundOutput{{
Address: giftAddress,
Value: giftAmountSF,
}},
}
signTxn(cs, &txn)
prev = cs
if au, err := mineTxns(nil, []types.V2Transaction{txn}); err != nil {
t.Fatal(err)
} else {
// siafund revenue should be unchanged
if cs.SiafundTaxRevenue != prev.SiafundTaxRevenue {
t.Fatalf("expected %v siafund revenue, got %v", prev.SiafundTaxRevenue, cs.SiafundTaxRevenue)
}
// should have received a timelocked siafund claim output
var claimOutput *types.SiacoinElement
au.ForEachSiacoinElement(func(sce types.SiacoinElement, _, _ bool) {
if sce.ID == txn.SiafundInputs[0].Parent.ID.V2ClaimOutputID() {
claimOutput = &sce
}
})
if claimOutput == nil {
t.Fatal("expected siafund claim output")
} else if claimOutput.MaturityHeight != cs.MaturityHeight()-1 {
t.Fatalf("expected siafund claim output to mature at height %v, got %v", cs.MaturityHeight()-1, claimOutput.MaturityHeight)
} else if exp := cs.V2FileContractTax(fc).Div64(cs.SiafundCount() / giftAmountSF); claimOutput.SiacoinOutput.Value != exp {
t.Fatalf("expected siafund claim output value %v, got %v", exp, claimOutput.SiacoinOutput.Value)
}
}
}

func TestFoundationSubsidy(t *testing.T) {
key := types.GeneratePrivateKey()
addr := types.StandardAddress(key.PublicKey())
Expand Down
2 changes: 1 addition & 1 deletion types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ type SiafundElement struct {
ID SiafundOutputID `json:"id"`
StateElement StateElement `json:"stateElement"`
SiafundOutput SiafundOutput `json:"siafundOutput"`
ClaimStart Currency `json:"claimStart"` // value of SiafundPool when element was created
ClaimStart Currency `json:"claimStart"` // value of SiafundTaxRevenue when element was created
}

// A FileContractElement is a record of a FileContract within the state
Expand Down

0 comments on commit 866a892

Please sign in to comment.