Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

txrules: Consider DCP0012 in VSP fee calculations. #2281

Merged
merged 1 commit into from Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion wallet/chainntfns.go
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
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
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
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
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