Skip to content

Commit

Permalink
txrules: Consider DCP0012 in VSP fee calculations.
Browse files Browse the repository at this point in the history
Update StakePoolTicketFee so it considers whether DCP0012 is active.
This is acheived by swapping the deprecated CalcStakeVoteSubsidyV2 for
its replacement CalcStakeVoteSubsidyV3.

Extra test cases are added to validate that the dcp0010Active
and dcp0012Active flags work as expected.
  • Loading branch information
jholdstock authored and jrick committed Sep 14, 2023
1 parent 44cce5e commit 90232ed
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 20 deletions.
4 changes: 3 additions & 1 deletion wallet/chainntfns.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,11 @@ func (w *Wallet) evaluateStakePoolTicket(rec *udb.TxRecord, blockHeight int32, p

// Calculate the fee required based on the current
// height and the required amount from the pool.
const dcp0010Active = false
const dcp0012Active = false
feeNeeded := txrules.StakePoolTicketFee(dcrutil.Amount(
tx.TxOut[0].Value), fees, blockHeight, w.poolFees,
w.chainParams, false)
w.chainParams, dcp0010Active, dcp0012Active)
if commitAmt < feeNeeded {
log.Warnf("User %s submitted ticket %v which "+
"has less fees than are required to use this "+
Expand Down
16 changes: 11 additions & 5 deletions wallet/createtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -1355,8 +1355,9 @@ func (w *Wallet) purchaseTickets(ctx context.Context, op errors.Op,
if poolAddress != nil {
// poolAddress is only used with the legacy stakepool
const dcp0010Active = false
const dcp0012Active = false
vspFee = txrules.StakePoolTicketFee(ticketPrice, ticketFee,
tipHeight, poolFees, w.ChainParams(), dcp0010Active)
tipHeight, poolFees, w.ChainParams(), dcp0010Active, dcp0012Active)
}

// After tickets are created and published, watch for future
Expand Down Expand Up @@ -1398,22 +1399,27 @@ func (w *Wallet) purchaseTickets(ctx context.Context, op errors.Op,
if err != nil {
return nil, err
}
// In SPV mode, DCP0010 is assumed to have activated. This
// In SPV mode, DCP0010 and DCP0012 are assumed to have activated. This
// results in a larger fee calculation for the purposes of UTXO
// selection. In RPC mode the actual activation can be
// determined.
// selection. In RPC mode the actual activation can be determined.
dcp0010Active := true
dcp0012Active := true
switch n := n.(type) {
case *dcrd.RPC:
dcp0010Active, err = deployments.DCP0010Active(ctx,
tipHeight, w.chainParams, n)
if err != nil {
return nil, err
}
dcp0012Active, err = deployments.DCP0012Active(ctx,
tipHeight, w.chainParams, n)
if err != nil {
return nil, err
}
}
fee := txrules.StakePoolTicketFee(ticketPrice, ticketFee,
tipHeight, feePrice, w.chainParams,
dcp0010Active)
dcp0010Active, dcp0012Active)

// Reserve outputs for number of buys.
vspFeeCredits = make([][]Input, 0, req.Count)
Expand Down
13 changes: 10 additions & 3 deletions wallet/txrules/poolfees.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var initSubsidyCacheOnce sync.Once
// calculation of this fee.
func StakePoolTicketFee(stakeDiff dcrutil.Amount, relayFee dcrutil.Amount,
height int32, poolFee float64, params *chaincfg.Params,
dcp0010Active bool) dcrutil.Amount {
dcp0010Active bool, dcp0012Active bool) dcrutil.Amount {
// Shift the decimal two places, e.g. 1.00%
// to 100. This assumes that the proportion
// is already multiplied by 100 to give a
Expand All @@ -56,8 +56,15 @@ func StakePoolTicketFee(stakeDiff dcrutil.Amount, relayFee dcrutil.Amount,
initSubsidyCacheOnce.Do(func() {
subsidyCache = blockchain.NewSubsidyCache(params)
})
subsidy := subsidyCache.CalcStakeVoteSubsidyV2(int64(height),
dcp0010Active)

ssv := blockchain.SSVOriginal
switch {
case dcp0012Active:
ssv = blockchain.SSVDCP0012
case dcp0010Active:
ssv = blockchain.SSVDCP0010
}
subsidy := subsidyCache.CalcStakeVoteSubsidyV3(int64(height), ssv)
for i := 0; i < adjs; i++ {
subsidy *= 100
subsidy /= 101
Expand Down
81 changes: 71 additions & 10 deletions wallet/txrules/poolfees_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,81 @@ import (
func TestStakePoolTicketFee(t *testing.T) {
params := chaincfg.MainNetParams()
tests := []struct {
StakeDiff dcrutil.Amount
Fee dcrutil.Amount
Height int32
PoolFee float64
Expected dcrutil.Amount
StakeDiff dcrutil.Amount
Fee dcrutil.Amount
Height int32
PoolFee float64
Expected dcrutil.Amount
IsDCP0010Active bool
IsDCP0012Active bool
}{
0: {10 * 1e8, 0.01 * 1e8, 25000, 1.00, 0.01500463 * 1e8},
1: {20 * 1e8, 0.01 * 1e8, 25000, 1.00, 0.01621221 * 1e8},
2: {5 * 1e8, 0.05 * 1e8, 50000, 2.59, 0.03310616 * 1e8},
3: {15 * 1e8, 0.05 * 1e8, 50000, 2.59, 0.03956376 * 1e8},
0: {
StakeDiff: 10 * 1e8,
Fee: 0.01 * 1e8,
Height: 25000,
PoolFee: 1.00,
Expected: 0.01500463 * 1e8,
IsDCP0010Active: false,
IsDCP0012Active: false,
},
1: {
StakeDiff: 20 * 1e8,
Fee: 0.01 * 1e8,
Height: 25000,
PoolFee: 1.00,
Expected: 0.01621221 * 1e8,
IsDCP0010Active: false,
IsDCP0012Active: false,
},
2: {
StakeDiff: 5 * 1e8,
Fee: 0.05 * 1e8,
Height: 50000,
PoolFee: 2.59,
Expected: 0.03310616 * 1e8,
IsDCP0010Active: false,
IsDCP0012Active: false,
},
3: {
StakeDiff: 15 * 1e8,
Fee: 0.05 * 1e8,
Height: 50000,
PoolFee: 2.59,
Expected: 0.03956376 * 1e8,
IsDCP0010Active: false,
IsDCP0012Active: false,
},
4: {
StakeDiff: 15 * 1e8,
Fee: 0.05 * 1e8,
Height: 50000,
PoolFee: 2.59,
Expected: 0.09023823 * 1e8,
IsDCP0010Active: true,
IsDCP0012Active: false,
},
5: {
StakeDiff: 15 * 1e8,
Fee: 0.05 * 1e8,
Height: 50000,
PoolFee: 2.59,
Expected: 0.09784185 * 1e8,
IsDCP0010Active: false,
IsDCP0012Active: true,
},
6: {
StakeDiff: 15 * 1e8,
Fee: 0.05 * 1e8,
Height: 50000,
PoolFee: 2.59,
Expected: 0.09784185 * 1e8,
IsDCP0010Active: true,
IsDCP0012Active: true,
},
}
for i, test := range tests {
poolFeeAmt := StakePoolTicketFee(test.StakeDiff, test.Fee, test.Height,
test.PoolFee, params, false)
test.PoolFee, params, test.IsDCP0010Active, test.IsDCP0012Active)
if poolFeeAmt != test.Expected {
t.Errorf("Test %d: Got %v: Want %v", i, poolFeeAmt, test.Expected)
}
Expand Down
10 changes: 9 additions & 1 deletion wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -1666,18 +1666,26 @@ func (w *Wallet) PurchaseTickets(ctx context.Context, n NetworkBackend,
return nil, err
}
_, height := w.MainChainTip(ctx)
// In SPV mode, DCP0010 and DCP0012 are assumed to have activated. In RPC
// mode the actual activation can be determined.
dcp0010Active := true
dcp0012Active := true
switch n := n.(type) {
case *dcrd.RPC:
dcp0010Active, err = deployments.DCP0010Active(ctx,
height, w.chainParams, n)
if err != nil {
return nil, err
}
dcp0012Active, err = deployments.DCP0012Active(ctx,
height, w.chainParams, n)
if err != nil {
return nil, err
}
}
relayFee := w.RelayFee()
vspFee := txrules.StakePoolTicketFee(sdiff, relayFee, height,
feePercent, w.chainParams, dcp0010Active)
feePercent, w.chainParams, dcp0010Active, dcp0012Active)
a := &authorTx{
outputs: make([]*wire.TxOut, 0, 2),
account: req.SourceAccount,
Expand Down

0 comments on commit 90232ed

Please sign in to comment.