diff --git a/pool/chainstate.go b/pool/chainstate.go index 9c35cb60..4aa40327 100644 --- a/pool/chainstate.go +++ b/pool/chainstate.go @@ -190,6 +190,23 @@ func isTreasuryActive(tx *wire.MsgTx) bool { return true } +// coinbaseIndex returns the index of the coinbase output in the provided +// transaction. +func coinbaseIndex(tx *wire.MsgTx) uint32 { + treasuryActive := isTreasuryActive(tx) + + // The coinbase output prior to + // [DCP0006](https://github.com/decred/dcps/pull/17) + // activation is at the third index position and at + // the second index position once DCP0006 is activated. + coinbaseIndex := uint32(1) + if !treasuryActive { + coinbaseIndex = 2 + } + + return coinbaseIndex +} + // handleChainUpdates processes connected and disconnected block // notifications from the consensus daemon. // @@ -223,14 +240,14 @@ func (cs *ChainState) handleChainUpdates(ctx context.Context) error { } coinbaseTx := block.Transactions[0] - treasuryActive := isTreasuryActive(coinbaseTx) + coinbaseIndex := coinbaseIndex(coinbaseTx) soloPool := cs.cfg.SoloPool if !soloPool { go cs.cfg.ProcessPayments(ctx, &paymentMsg{ - CurrentHeight: header.Height, - TreasuryActive: treasuryActive, - Done: make(chan struct{}), + CurrentHeight: header.Height, + CoinbaseIndex: coinbaseIndex, + Done: make(chan struct{}), }) } @@ -359,14 +376,7 @@ func (cs *ChainState) handleChainUpdates(ctx context.Context) error { Coinbase: coinbaseTx.TxHash().String(), } - // The coinbase output prior to - // [DCP0006](https://github.com/decred/dcps/pull/17) - // activation is at the third index position and at - // the second index position once DCP0006 is activated. - amt := dcrutil.Amount(coinbaseTx.TxOut[1].Value) - if !treasuryActive { - amt = dcrutil.Amount(coinbaseTx.TxOut[2].Value) - } + amt := dcrutil.Amount(coinbaseTx.TxOut[coinbaseIndex].Value) err = cs.cfg.GeneratePayments(block.Header.Height, source, amt, work.CreatedOn) diff --git a/pool/paymentmgr.go b/pool/paymentmgr.go index 25451e82..535095f5 100644 --- a/pool/paymentmgr.go +++ b/pool/paymentmgr.go @@ -121,9 +121,9 @@ type PaymentMgrConfig struct { // paymentMsg represents a payment processing signal. type paymentMsg struct { - CurrentHeight uint32 - TreasuryActive bool - Done chan struct{} + CurrentHeight uint32 + CoinbaseIndex uint32 + Done chan struct{} } // PaymentMgr handles generating shares and paying out dividends to @@ -591,19 +591,10 @@ func (pm *PaymentMgr) monitorRescan(ctx context.Context, rescanSource walletrpc. // generatePayoutTxDetails creates the payout transaction inputs and outputs // from the provided payments -func (pm *PaymentMgr) generatePayoutTxDetails(ctx context.Context, txC TxCreator, feeAddr stdaddr.Address, payments map[string][]*Payment, treasuryActive bool) ([]chainjson.TransactionInput, +func (pm *PaymentMgr) generatePayoutTxDetails(ctx context.Context, txC TxCreator, feeAddr stdaddr.Address, payments map[string][]*Payment, coinbaseIndex uint32) ([]chainjson.TransactionInput, map[chainhash.Hash]uint32, map[string]dcrutil.Amount, dcrutil.Amount, error) { const funcName = "generatePayoutTxDetails" - // The coinbase output prior to - // [DCP0006](https://github.com/decred/dcps/pull/17) - // activation is at the third index position and at - // the second index position once DCP0006 is activated. - coinbaseIndex := uint32(1) - if !treasuryActive { - coinbaseIndex = 2 - } - var tIn, tOut dcrutil.Amount inputs := make([]chainjson.TransactionInput, 0) inputTxHashes := make(map[chainhash.Hash]uint32) @@ -701,7 +692,7 @@ func (pm *PaymentMgr) generatePayoutTxDetails(ctx context.Context, txC TxCreator } // PayDividends pays mature mining rewards to participating accounts. -func (pm *PaymentMgr) payDividends(ctx context.Context, height uint32, treasuryActive bool) error { +func (pm *PaymentMgr) payDividends(ctx context.Context, height uint32, coinbaseIndex uint32) error { const funcName = "payDividends" mPmts, err := pm.cfg.db.maturePendingPayments(height) if err != nil { @@ -805,7 +796,7 @@ func (pm *PaymentMgr) payDividends(ctx context.Context, height uint32, treasuryA feeAddr := pm.cfg.PoolFeeAddrs[pm.prng.Intn(len(pm.cfg.PoolFeeAddrs))] inputs, inputTxHashes, outputs, tOut, err := - pm.generatePayoutTxDetails(ctx, txC, feeAddr, pmts, treasuryActive) + pm.generatePayoutTxDetails(ctx, txC, feeAddr, pmts, coinbaseIndex) if err != nil { return err } @@ -947,7 +938,7 @@ func (pm *PaymentMgr) handlePayments(ctx context.Context) { case msg := <-pm.paymentCh: if !pm.cfg.SoloPool { - err := pm.payDividends(ctx, msg.CurrentHeight, msg.TreasuryActive) + err := pm.payDividends(ctx, msg.CurrentHeight, msg.CoinbaseIndex) if err != nil { log.Errorf("unable to process payments: %v", err) close(msg.Done) diff --git a/pool/paymentmgr_test.go b/pool/paymentmgr_test.go index 4f72a1ac..e33f2a34 100644 --- a/pool/paymentmgr_test.go +++ b/pool/paymentmgr_test.go @@ -718,7 +718,7 @@ func testPaymentMgrPayment(t *testing.T) { mPmts[zeroSource.Coinbase] = []*Payment{pmtA} pmtB = NewPayment(yID, randSource, amt, height, estMaturity) mPmts[randSource.Coinbase] = []*Payment{pmtB} - treasuryActive := true + coinbaseIndex := uint32(1) // Ensure generating payout tx details returns an error if fetching txOut // information fails. @@ -728,7 +728,7 @@ func testPaymentMgrPayment(t *testing.T) { }, } _, _, _, _, err = mgr.generatePayoutTxDetails(ctx, txC, poolFeeAddrs, - mPmts, treasuryActive) + mPmts, coinbaseIndex) if !errors.Is(err, errs.TxOut) { cancel() t.Fatalf("expected a fetch txOut error, got %v", err) @@ -748,7 +748,7 @@ func testPaymentMgrPayment(t *testing.T) { } _, _, _, _, err = mgr.generatePayoutTxDetails(ctx, txC, poolFeeAddrs, - mPmts, treasuryActive) + mPmts, coinbaseIndex) if !errors.Is(err, errs.Coinbase) { cancel() t.Fatalf("expected a spendable error") @@ -772,7 +772,7 @@ func testPaymentMgrPayment(t *testing.T) { } _, _, _, _, err = mgr.generatePayoutTxDetails(ctx, txC, poolFeeAddrs, - mPmts, treasuryActive) + mPmts, coinbaseIndex) if !errors.Is(err, errs.ValueNotFound) { cancel() t.Fatalf("expected an account not found error") @@ -793,7 +793,7 @@ func testPaymentMgrPayment(t *testing.T) { } _, _, _, _, err = mgr.generatePayoutTxDetails(ctx, txC, poolFeeAddrs, - mPmts, treasuryActive) + mPmts, coinbaseIndex) if !errors.Is(err, errs.CreateTx) { cancel() t.Fatalf("expected an input output mismatch error") @@ -814,7 +814,7 @@ func testPaymentMgrPayment(t *testing.T) { } _, _, _, _, err = mgr.generatePayoutTxDetails(ctx, txC, poolFeeAddrs, - mPmts, treasuryActive) + mPmts, coinbaseIndex) if !errors.Is(err, errs.CreateTx) { cancel() t.Fatalf("expected an unclaimed input value error, got %v", err) @@ -834,7 +834,7 @@ func testPaymentMgrPayment(t *testing.T) { inputs, inputTxHashes, outputs, _, err := mgr.generatePayoutTxDetails(ctx, txC, poolFeeAddrs, - mPmts, treasuryActive) + mPmts, coinbaseIndex) if err != nil { cancel() t.Fatalf("unexpected payout tx details error, got %v", err) @@ -905,7 +905,7 @@ func testPaymentMgrPayment(t *testing.T) { // Ensure dividend payments returns no error if there are no mature // payments to work with. - err = mgr.payDividends(ctx, estMaturity-1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity-1, coinbaseIndex) if err != nil { cancel() t.Fatal("expected no error since there are no mature payments") @@ -917,7 +917,7 @@ func testPaymentMgrPayment(t *testing.T) { return nil } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.Disconnected) { cancel() t.Fatalf("expected a nil tx creator error, got %v", err) @@ -932,7 +932,7 @@ func testPaymentMgrPayment(t *testing.T) { return -1, fmt.Errorf("unable to confirm blocks") } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if err == nil { cancel() t.Fatalf("expected a prune orphan payments error") @@ -961,7 +961,7 @@ func testPaymentMgrPayment(t *testing.T) { } } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.TxOut) { cancel() t.Fatalf("expected a generate payout tx details error, got %v", err) @@ -975,7 +975,7 @@ func testPaymentMgrPayment(t *testing.T) { return -1, nil } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.TxIn) { cancel() t.Fatalf("expected an apply tx fee error, got %v", err) @@ -998,7 +998,7 @@ func testPaymentMgrPayment(t *testing.T) { return int64(estMaturity) + 1, nil } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if err == nil { cancel() t.Fatalf("expected a coinbase confirmation error, got %v", err) @@ -1027,7 +1027,7 @@ func testPaymentMgrPayment(t *testing.T) { mgr.cfg.CoinbaseConfTimeout = time.Millisecond * 500 - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if err == nil { cancel() t.Fatal("expected a create transaction error") @@ -1058,7 +1058,7 @@ func testPaymentMgrPayment(t *testing.T) { } mgr.cfg.WalletPass = "123" - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.Disconnected) { cancel() t.Fatalf("expected a fetch tx broadcaster error, got %v", err) @@ -1095,7 +1095,7 @@ func testPaymentMgrPayment(t *testing.T) { } } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.SignTx) { cancel() t.Fatalf("expected a signing error, got %v", err) @@ -1130,7 +1130,7 @@ func testPaymentMgrPayment(t *testing.T) { } } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.PublishTx) { cancel() t.Fatalf("expected a publish error, got %v", err) @@ -1162,7 +1162,7 @@ func testPaymentMgrPayment(t *testing.T) { atomic.StoreUint32(&mgr.failedTxConfs, maxTxConfThreshold) - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.Rescan) { cancel() t.Fatalf("expected a rescan error, got %v", err) @@ -1193,7 +1193,7 @@ func testPaymentMgrPayment(t *testing.T) { } } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.Rescan) { cancel() t.Fatalf("expected a rescan error, got %v", err) @@ -1208,7 +1208,7 @@ func testPaymentMgrPayment(t *testing.T) { // Ensure dividend payment returns an error when there are no tx // confirmation hashes to rescan. - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.TxConf) { cancel() t.Fatalf("expected a no tx conf error, got %v", err) @@ -1246,7 +1246,7 @@ func testPaymentMgrPayment(t *testing.T) { } } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if !errors.Is(err, errs.PublishTx) { cancel() t.Fatalf("expected a publish error, got %v", err) @@ -1282,7 +1282,7 @@ func testPaymentMgrPayment(t *testing.T) { } } - err = mgr.payDividends(ctx, estMaturity+1, treasuryActive) + err = mgr.payDividends(ctx, estMaturity+1, coinbaseIndex) if err != nil { cancel() t.Fatalf("unexpected dividend payment error, got %v", err) @@ -1503,9 +1503,9 @@ func testPaymentMgrSignals(t *testing.T) { // Ensure the payment lifecycle process receives the payment signal and // processes mature payments. msgA := paymentMsg{ - CurrentHeight: estMaturity + 1, - TreasuryActive: false, - Done: make(chan struct{}), + CurrentHeight: estMaturity + 1, + CoinbaseIndex: 2, + Done: make(chan struct{}), } var wg sync.WaitGroup @@ -1537,9 +1537,9 @@ func testPaymentMgrSignals(t *testing.T) { } msgB := paymentMsg{ - CurrentHeight: estMaturity + 1, - TreasuryActive: false, - Done: make(chan struct{}), + CurrentHeight: estMaturity + 1, + CoinbaseIndex: 2, + Done: make(chan struct{}), } mgr.processPayments(ctx, &msgB) <-msgB.Done