sweep: create sweep parameters struct

Prepares for adding more input-specific sweep parameters.
This commit is contained in:
Joost Jager 2019-12-09 11:42:58 +01:00
parent e2bf6b49e9
commit 38adfd7ecc
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
8 changed files with 59 additions and 36 deletions

@ -206,7 +206,7 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
c.log.Infof("sweeping commit output")
feePref := sweep.FeePreference{ConfTarget: commitOutputConfTarget}
resultChan, err := c.Sweeper.SweepInput(inp, feePref)
resultChan, err := c.Sweeper.SweepInput(inp, sweep.Params{Fee: feePref})
if err != nil {
c.log.Errorf("unable to sweep input: %v", err)

@ -102,8 +102,8 @@ func newMockSweeper() *mockSweeper {
}
}
func (s *mockSweeper) SweepInput(input input.Input,
feePreference sweep.FeePreference) (chan sweep.Result, error) {
func (s *mockSweeper) SweepInput(input input.Input, params sweep.Params) (
chan sweep.Result, error) {
s.sweptInputs <- input

@ -43,8 +43,8 @@ type OnionProcessor interface {
// UtxoSweeper defines the sweep functions that contract court requires.
type UtxoSweeper interface {
// SweepInput sweeps inputs back into the wallet.
SweepInput(input input.Input,
feePreference sweep.FeePreference) (chan sweep.Result, error)
SweepInput(input input.Input, params sweep.Params) (chan sweep.Result,
error)
// CreateSweepTx accepts a list of inputs and signs and generates a txn
// that spends from them. This method also makes an accurate fee

@ -536,7 +536,7 @@ func (w *WalletKit) BumpFee(ctx context.Context,
}
input := input.NewBaseInput(op, witnessType, signDesc, uint32(currentHeight))
if _, err = w.cfg.Sweeper.SweepInput(input, feePreference); err != nil {
if _, err = w.cfg.Sweeper.SweepInput(input, sweep.Params{Fee: feePreference}); err != nil {
return nil, err
}

@ -61,6 +61,14 @@ var (
DefaultMaxSweepAttempts = 10
)
// Params contains the parameters that control the sweeping process.
type Params struct {
// Fee is the fee preference of the client who requested the input to be
// swept. If a confirmation target is specified, then we'll map it into
// a fee rate whenever we attempt to cluster inputs for a sweep.
Fee FeePreference
}
// pendingInput is created when an input reaches the main loop for the first
// time. It tracks all relevant state that is needed for sweeping.
type pendingInput struct {
@ -84,11 +92,8 @@ type pendingInput struct {
// made to sweep this tx.
publishAttempts int
// feePreference is the fee preference of the client who requested the
// input to be swept. If a confirmation target is specified, then we'll
// map it into a fee rate whenever we attempt to cluster inputs for a
// sweep.
feePreference FeePreference
// params contains the parameters that control the sweeping process.
params Params
// lastFeeRate is the most recent fee rate used for this input within a
// transaction broadcast to the network.
@ -267,7 +272,7 @@ type Result struct {
// SweepInput call and the sweeper main loop.
type sweepInputMessage struct {
input input.Input
feePreference FeePreference
params Params
resultChan chan Result
}
@ -368,25 +373,26 @@ func (s *UtxoSweeper) Stop() error {
// Because it is an interface and we don't know what is exactly behind it, we
// cannot make a local copy in sweeper.
func (s *UtxoSweeper) SweepInput(input input.Input,
feePreference FeePreference) (chan Result, error) {
params Params) (chan Result, error) {
if input == nil || input.OutPoint() == nil || input.SignDesc() == nil {
return nil, errors.New("nil input received")
}
// Ensure the client provided a sane fee preference.
if _, err := s.feeRateForPreference(feePreference); err != nil {
if _, err := s.feeRateForPreference(params.Fee); err != nil {
return nil, err
}
log.Infof("Sweep request received: out_point=%v, witness_type=%v, "+
"time_lock=%v, amount=%v, fee_preference=%v", input.OutPoint(),
input.WitnessType(), input.BlocksToMaturity(),
btcutil.Amount(input.SignDesc().Output.Value), feePreference)
btcutil.Amount(input.SignDesc().Output.Value),
params.Fee)
sweeperInput := &sweepInputMessage{
input: input,
feePreference: feePreference,
params: params,
resultChan: make(chan Result, 1),
}
@ -470,7 +476,7 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch) {
listeners: []chan Result{input.resultChan},
input: input.input,
minPublishHeight: bestHeight,
feePreference: input.feePreference,
params: input.params,
}
s.pendingInputs[outpoint] = pendInput
@ -653,7 +659,7 @@ func (s *UtxoSweeper) clusterBySweepFeeRate() []inputCluster {
// First, we'll group together all inputs with similar fee rates. This
// is done by determining the fee rate bucket they should belong in.
for op, input := range s.pendingInputs {
feeRate, err := s.feeRateForPreference(input.feePreference)
feeRate, err := s.feeRateForPreference(input.params.Fee)
if err != nil {
log.Warnf("Skipping input %v: %v", op, err)
continue
@ -1072,9 +1078,9 @@ func (s *UtxoSweeper) handleBumpFeeReq(req *bumpFeeReq,
}
log.Debugf("Updating fee preference for %v from %v to %v", req.input,
pendingInput.feePreference, req.feePreference)
pendingInput.params.Fee, req.feePreference)
pendingInput.feePreference = req.feePreference
pendingInput.params.Fee = req.feePreference
// We'll reset the input's publish height to the current so that a new
// transaction can be created that replaces the transaction currently

@ -25,7 +25,7 @@ var (
testMaxInputsPerTx = 3
defaultFeePref = FeePreference{ConfTarget: 1}
defaultFeePref = Params{Fee: FeePreference{ConfTarget: 1}}
)
type sweeperTestContext struct {
@ -354,7 +354,7 @@ func TestSuccess(t *testing.T) {
ctx := createSweeperTestContext(t)
// Sweeping an input without a fee preference should result in an error.
_, err := ctx.sweeper.SweepInput(spendableInputs[0], FeePreference{})
_, err := ctx.sweeper.SweepInput(spendableInputs[0], Params{})
if err != ErrNoFeePreference {
t.Fatalf("expected ErrNoFeePreference, got %v", err)
}
@ -1003,17 +1003,23 @@ func TestDifferentFeePreferences(t *testing.T) {
ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate
input1 := spendableInputs[0]
resultChan1, err := ctx.sweeper.SweepInput(input1, highFeePref)
resultChan1, err := ctx.sweeper.SweepInput(
input1, Params{Fee: highFeePref},
)
if err != nil {
t.Fatal(err)
}
input2 := spendableInputs[1]
resultChan2, err := ctx.sweeper.SweepInput(input2, highFeePref)
resultChan2, err := ctx.sweeper.SweepInput(
input2, Params{Fee: highFeePref},
)
if err != nil {
t.Fatal(err)
}
input3 := spendableInputs[2]
resultChan3, err := ctx.sweeper.SweepInput(input3, lowFeePref)
resultChan3, err := ctx.sweeper.SweepInput(
input3, Params{Fee: lowFeePref},
)
if err != nil {
t.Fatal(err)
}
@ -1067,16 +1073,23 @@ func TestPendingInputs(t *testing.T) {
ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate
input1 := spendableInputs[0]
resultChan1, err := ctx.sweeper.SweepInput(input1, highFeePref)
resultChan1, err := ctx.sweeper.SweepInput(
input1, Params{Fee: highFeePref},
)
if err != nil {
t.Fatal(err)
}
input2 := spendableInputs[1]
if _, err := ctx.sweeper.SweepInput(input2, highFeePref); err != nil {
_, err = ctx.sweeper.SweepInput(
input2, Params{Fee: highFeePref},
)
if err != nil {
t.Fatal(err)
}
input3 := spendableInputs[2]
resultChan3, err := ctx.sweeper.SweepInput(input3, lowFeePref)
resultChan3, err := ctx.sweeper.SweepInput(
input3, Params{Fee: lowFeePref},
)
if err != nil {
t.Fatal(err)
}
@ -1132,7 +1145,9 @@ func TestBumpFeeRBF(t *testing.T) {
input := createTestInput(
btcutil.SatoshiPerBitcoin, input.CommitmentTimeLock,
)
sweepResult, err := ctx.sweeper.SweepInput(&input, lowFeePref)
sweepResult, err := ctx.sweeper.SweepInput(
&input, Params{Fee: lowFeePref},
)
if err != nil {
t.Fatal(err)
}

@ -201,7 +201,7 @@ type NurseryConfig struct {
Store NurseryStore
// Sweep sweeps an input back to the wallet.
SweepInput func(input.Input, sweep.FeePreference) (chan sweep.Result, error)
SweepInput func(input.Input, sweep.Params) (chan sweep.Result, error)
}
// utxoNursery is a system dedicated to incubating time-locked outputs created
@ -778,7 +778,9 @@ func (u *utxoNursery) sweepMatureOutputs(classHeight uint32,
// passed in with disastrous consequences.
local := output
resultChan, err := u.cfg.SweepInput(&local, feePref)
resultChan, err := u.cfg.SweepInput(
&local, sweep.Params{Fee: feePref},
)
if err != nil {
return err
}

@ -983,7 +983,7 @@ func newMockSweeper(t *testing.T) *mockSweeper {
}
func (s *mockSweeper) sweepInput(input input.Input,
_ sweep.FeePreference) (chan sweep.Result, error) {
_ sweep.Params) (chan sweep.Result, error) {
utxnLog.Debugf("mockSweeper sweepInput called for %v", *input.OutPoint())