sweep: broadcast sweep transactions in descending fee rate order

In this commit, we address another issue that arose with the
introduction of the fee rate buckets. We'll use an example to explain
the problem space:

Let's say we have inputs A, B, and C within the same fee rate bucket. If
A's fee rate is bumped to a higher bucket, then it's currently possible
for the lower fee rate bucket to be swept first, which would produce an
invalid RBF transaction since we're removing an input from the original
without providing a higher fee. By the time we get to the higher fee
rate bucket, we broadcast a valid RBF transaction _only_ sweeping input
A, which would evict the transaction sweeping inputs B and C from the
mempool.

To prevent this eviction, we can simply broadcast the higher fee rate
sweep transactions first, to ensure we have valid RBF transactions.
This commit is contained in:
Wilmer Paulino
2019-05-15 17:04:49 -07:00
parent 5172a5e255
commit 682aebdd53
2 changed files with 27 additions and 18 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt"
"math"
"math/rand"
"sort"
"sync"
"sync/atomic"
"time"
@ -488,8 +489,17 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch,
s.timer = nil
// We'll attempt to cluster all of our inputs with
// similar fee rates.
for _, cluster := range s.clusterBySweepFeeRate() {
// similar fee rates. Before attempting to sweep them,
// we'll sort them in descending fee rate order. We do
// this to ensure any inputs which have had their fee
// rate bumped are broadcast first in order enforce the
// RBF policy.
inputClusters := s.clusterBySweepFeeRate()
sort.Slice(inputClusters, func(i, j int) bool {
return inputClusters[i].sweepFeeRate >
inputClusters[j].sweepFeeRate
})
for _, cluster := range inputClusters {
// Examine pending inputs and try to construct
// lists of inputs.
inputLists, err := s.getInputLists(