sweep: allow updating all sweep parameters

This is a preparation for adding additional parameters besides the fee
preference.
This commit is contained in:
Joost Jager 2020-01-09 14:41:28 +01:00
parent 280611ab6e
commit 16832cefa3
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
3 changed files with 52 additions and 39 deletions

@ -485,7 +485,11 @@ func (w *WalletKit) BumpFee(ctx context.Context,
// bump its fee, which will result in a replacement transaction (RBF) // bump its fee, which will result in a replacement transaction (RBF)
// being broadcast. If it is not aware of the input however, // being broadcast. If it is not aware of the input however,
// lnwallet.ErrNotMine is returned. // lnwallet.ErrNotMine is returned.
_, err = w.cfg.Sweeper.BumpFee(*op, feePreference) params := sweep.Params{
Fee: feePreference,
}
_, err = w.cfg.Sweeper.UpdateParams(*op, params)
switch err { switch err {
case nil: case nil:
return &BumpFeeResponse{}, nil return &BumpFeeResponse{}, nil

@ -69,6 +69,11 @@ type Params struct {
Fee FeePreference Fee FeePreference
} }
// String returns a human readable interpretation of the sweep parameters.
func (p Params) String() string {
return fmt.Sprintf("fee=%v", p.Fee)
}
// pendingInput is created when an input reaches the main loop for the first // pendingInput is created when an input reaches the main loop for the first
// time. It wraps the input and tracks all relevant state that is needed for // time. It wraps the input and tracks all relevant state that is needed for
// sweeping. // sweeping.
@ -151,17 +156,17 @@ type PendingInput struct {
Params Params Params Params
} }
// bumpFeeReq is an internal message we'll use to represent an external caller's // updateReq is an internal message we'll use to represent an external caller's
// intent to bump the fee rate of a given input. // intent to update the sweep parameters of a given input.
type bumpFeeReq struct { type updateReq struct {
input wire.OutPoint input wire.OutPoint
feePreference FeePreference params Params
responseChan chan *bumpFeeResp responseChan chan *updateResp
} }
// bumpFeeResp is an internal message we'll use to hand off the response of a // updateResp is an internal message we'll use to hand off the response of a
// bumpFeeReq from the UtxoSweeper's main event loop back to the caller. // updateReq from the UtxoSweeper's main event loop back to the caller.
type bumpFeeResp struct { type updateResp struct {
resultChan chan Result resultChan chan Result
err error err error
} }
@ -181,9 +186,9 @@ type UtxoSweeper struct {
// UtxoSweeper is attempting to sweep. // UtxoSweeper is attempting to sweep.
pendingSweepsReqs chan *pendingSweepsReq pendingSweepsReqs chan *pendingSweepsReq
// bumpFeeReqs is a channel that will be sent requests by external // updateReqs is a channel that will be sent requests by external
// callers who wish to bump the fee rate of a given input. // callers who wish to bump the fee rate of a given input.
bumpFeeReqs chan *bumpFeeReq updateReqs chan *updateReq
// pendingInputs is the total set of inputs the UtxoSweeper has been // pendingInputs is the total set of inputs the UtxoSweeper has been
// requested to sweep. // requested to sweep.
@ -290,7 +295,7 @@ func New(cfg *UtxoSweeperConfig) *UtxoSweeper {
cfg: cfg, cfg: cfg,
newInputs: make(chan *sweepInputMessage), newInputs: make(chan *sweepInputMessage),
spendChan: make(chan *chainntnfs.SpendDetail), spendChan: make(chan *chainntnfs.SpendDetail),
bumpFeeReqs: make(chan *bumpFeeReq), updateReqs: make(chan *updateReq),
pendingSweepsReqs: make(chan *pendingSweepsReq), pendingSweepsReqs: make(chan *pendingSweepsReq),
quit: make(chan struct{}), quit: make(chan struct{}),
pendingInputs: make(pendingInputs), pendingInputs: make(pendingInputs),
@ -575,9 +580,9 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch) {
// A new external request has been received to bump the fee rate // A new external request has been received to bump the fee rate
// of a given input. // of a given input.
case req := <-s.bumpFeeReqs: case req := <-s.updateReqs:
resultChan, err := s.handleBumpFeeReq(req, bestHeight) resultChan, err := s.handleUpdateReq(req, bestHeight)
req.responseChan <- &bumpFeeResp{ req.responseChan <- &updateResp{
resultChan: resultChan, resultChan: resultChan,
err: err, err: err,
} }
@ -1044,28 +1049,28 @@ func (s *UtxoSweeper) handlePendingSweepsReq(
return pendingInputs return pendingInputs
} }
// BumpFee allows bumping the fee of an input being swept by the UtxoSweeper // UpdateParams allows updating the sweep parameters of a pending input in the
// according to the provided fee preference. The new fee preference will be used // UtxoSweeper. This function can be used to provide an updated fee preference
// for a new sweep transaction of the input that will act as a replacement // that will be used for a new sweep transaction of the input that will act as a
// transaction (RBF) of the original sweeping transaction, if any. // replacement transaction (RBF) of the original sweeping transaction, if any.
// //
// NOTE: This currently doesn't do any fee rate validation to ensure that a bump // NOTE: This currently doesn't do any fee rate validation to ensure that a bump
// is actually successful. The responsibility of doing so should be handled by // is actually successful. The responsibility of doing so should be handled by
// the caller. // the caller.
func (s *UtxoSweeper) BumpFee(input wire.OutPoint, func (s *UtxoSweeper) UpdateParams(input wire.OutPoint,
feePreference FeePreference) (chan Result, error) { params Params) (chan Result, error) {
// Ensure the client provided a sane fee preference. // 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 return nil, err
} }
responseChan := make(chan *bumpFeeResp, 1) responseChan := make(chan *updateResp, 1)
select { select {
case s.bumpFeeReqs <- &bumpFeeReq{ case s.updateReqs <- &updateReq{
input: input, input: input,
feePreference: feePreference, params: params,
responseChan: responseChan, responseChan: responseChan,
}: }:
case <-s.quit: case <-s.quit:
return nil, ErrSweeperShuttingDown return nil, ErrSweeperShuttingDown
@ -1079,9 +1084,9 @@ func (s *UtxoSweeper) BumpFee(input wire.OutPoint,
} }
} }
// handleBumpFeeReq handles a bump fee request by simply updating the inputs fee // handleUpdateReq handles an update request by simply updating the sweep
// preference. Currently, no validation is done on the new fee preference to // parameters of the pending input. Currently, no validation is done on the new
// ensure it will properly create a replacement transaction. // fee preference to ensure it will properly create a replacement transaction.
// //
// TODO(wilmer): // TODO(wilmer):
// * Validate fee preference to ensure we'll create a valid replacement // * Validate fee preference to ensure we'll create a valid replacement
@ -1090,8 +1095,8 @@ func (s *UtxoSweeper) BumpFee(input wire.OutPoint,
// * Ensure we don't combine this input with any other unconfirmed inputs that // * Ensure we don't combine this input with any other unconfirmed inputs that
// did not exist in the original sweep transaction, resulting in an invalid // did not exist in the original sweep transaction, resulting in an invalid
// replacement transaction. // replacement transaction.
func (s *UtxoSweeper) handleBumpFeeReq(req *bumpFeeReq, func (s *UtxoSweeper) handleUpdateReq(req *updateReq, bestHeight int32) (
bestHeight int32) (chan Result, error) { chan Result, error) {
// If the UtxoSweeper is already trying to sweep this input, then we can // If the UtxoSweeper is already trying to sweep this input, then we can
// simply just increase its fee rate. This will allow the input to be // simply just increase its fee rate. This will allow the input to be
@ -1103,10 +1108,10 @@ func (s *UtxoSweeper) handleBumpFeeReq(req *bumpFeeReq,
return nil, lnwallet.ErrNotMine return nil, lnwallet.ErrNotMine
} }
log.Debugf("Updating fee preference for %v from %v to %v", req.input, log.Debugf("Updating sweep parameters for %v from %v to %v", req.input,
pendingInput.params.Fee, req.feePreference) pendingInput.params, req.params)
pendingInput.params.Fee = req.feePreference pendingInput.params = req.params
// We'll reset the input's publish height to the current so that a new // We'll reset the input's publish height to the current so that a new
// transaction can be created that replaces the transaction currently // transaction can be created that replaces the transaction currently

@ -1178,7 +1178,9 @@ func TestBumpFeeRBF(t *testing.T) {
// We'll first try to bump the fee of an output currently unknown to the // We'll first try to bump the fee of an output currently unknown to the
// UtxoSweeper. Doing so should result in a lnwallet.ErrNotMine error. // UtxoSweeper. Doing so should result in a lnwallet.ErrNotMine error.
bumpResult, err := ctx.sweeper.BumpFee(wire.OutPoint{}, lowFeePref) _, err := ctx.sweeper.UpdateParams(
wire.OutPoint{}, Params{Fee: lowFeePref},
)
if err != lnwallet.ErrNotMine { if err != lnwallet.ErrNotMine {
t.Fatalf("expected error lnwallet.ErrNotMine, got \"%v\"", err) t.Fatalf("expected error lnwallet.ErrNotMine, got \"%v\"", err)
} }
@ -1206,12 +1208,14 @@ func TestBumpFeeRBF(t *testing.T) {
ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate
// We should expect to see an error if a fee preference isn't provided. // We should expect to see an error if a fee preference isn't provided.
_, err = ctx.sweeper.BumpFee(*input.OutPoint(), FeePreference{}) _, err = ctx.sweeper.UpdateParams(*input.OutPoint(), Params{})
if err != ErrNoFeePreference { if err != ErrNoFeePreference {
t.Fatalf("expected ErrNoFeePreference, got %v", err) t.Fatalf("expected ErrNoFeePreference, got %v", err)
} }
bumpResult, err = ctx.sweeper.BumpFee(*input.OutPoint(), highFeePref) bumpResult, err := ctx.sweeper.UpdateParams(
*input.OutPoint(), Params{Fee: highFeePref},
)
if err != nil { if err != nil {
t.Fatalf("unable to bump input's fee: %v", err) t.Fatalf("unable to bump input's fee: %v", err)
} }