cnct: reuse sweep tx logic for success resolver

This commit is contained in:
Joost Jager 2018-09-26 11:00:10 -07:00
parent c1d845aa0d
commit 6977d59e35
No known key found for this signature in database
GPG Key ID: AE6B0D042C8E38D9
3 changed files with 98 additions and 77 deletions

@ -9,7 +9,6 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
@ -447,59 +446,19 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
"incoming+remote htlc confirmed", h, "incoming+remote htlc confirmed", h,
h.payHash[:]) h.payHash[:])
// In this case, we can sweep it directly from the input := sweep.MakeHtlcSucceedInput(
// commitment output. We'll first grab a fresh address &h.htlcResolution.ClaimOutpoint,
// from the wallet to sweep the output. &h.htlcResolution.SweepSignDesc,
addr, err := h.NewSweepAddr()
if err != nil {
return nil, err
}
// With our address obtained, we'll query for an
// estimate to be confirmed at ease.
//
// TODO(roasbeef): signal up if fee would be too large
// to sweep singly, need to batch
feePerKw, err := h.FeeEstimator.EstimateFeePerKW(6)
if err != nil {
return nil, err
}
log.Debugf("%T(%x): using %v sat/kw to sweep htlc"+
"incoming+remote htlc confirmed", h,
h.payHash[:], int64(feePerKw))
// Using a weight estimator, we'll compute the total
// fee required, and from that the value we'll end up
// with.
totalWeight := (&lnwallet.TxWeightEstimator{}).
AddWitnessInput(lnwallet.OfferedHtlcSuccessWitnessSize).
AddP2WKHOutput().Weight()
totalFees := feePerKw.FeeForWeight(int64(totalWeight))
sweepAmt := h.htlcResolution.SweepSignDesc.Output.Value -
int64(totalFees)
// With the fee computation finished, we'll now
// construct the sweep transaction.
htlcPoint := h.htlcResolution.ClaimOutpoint
h.sweepTx = wire.NewMsgTx(2)
h.sweepTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: htlcPoint,
})
h.sweepTx.AddTxOut(&wire.TxOut{
PkScript: addr,
Value: sweepAmt,
})
// With the transaction fully assembled, we can now
// generate a valid witness for the transaction.
h.htlcResolution.SweepSignDesc.SigHashes = txscript.NewTxSigHashes(
h.sweepTx,
)
h.sweepTx.TxIn[0].Witness, err = lnwallet.SenderHtlcSpendRedeem(
h.Signer, &h.htlcResolution.SweepSignDesc, h.sweepTx,
h.htlcResolution.Preimage[:], h.htlcResolution.Preimage[:],
) )
var err error
// TODO: Set tx lock time to current block height instead of
// zero. Will be taken care of once sweeper implementation is
// complete.
h.sweepTx, err = h.Sweeper.CreateSweepTx(
[]sweep.Input{&input}, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -35,13 +35,36 @@ type Input interface {
BlocksToMaturity() uint32 BlocksToMaturity() uint32
} }
// BaseInput contains all the information needed to sweep an output. type inputKit struct {
type BaseInput struct {
outpoint wire.OutPoint outpoint wire.OutPoint
witnessType lnwallet.WitnessType witnessType lnwallet.WitnessType
signDesc lnwallet.SignDescriptor signDesc lnwallet.SignDescriptor
} }
// OutPoint returns the breached output's identifier that is to be included as a
// transaction input.
func (i *inputKit) OutPoint() *wire.OutPoint {
return &i.outpoint
}
// WitnessType returns the type of witness that must be generated to spend the
// breached output.
func (i *inputKit) WitnessType() lnwallet.WitnessType {
return i.witnessType
}
// SignDesc returns the breached output's SignDescriptor, which is used during
// signing to compute the witness.
func (i *inputKit) SignDesc() *lnwallet.SignDescriptor {
return &i.signDesc
}
// BaseInput contains all the information needed to sweep a basic output
// (CSV/CLTV/no time lock)
type BaseInput struct {
inputKit
}
// MakeBaseInput assembles a new BaseInput that can be used to construct a // MakeBaseInput assembles a new BaseInput that can be used to construct a
// sweep transaction. // sweep transaction.
func MakeBaseInput(outpoint *wire.OutPoint, func MakeBaseInput(outpoint *wire.OutPoint,
@ -49,30 +72,14 @@ func MakeBaseInput(outpoint *wire.OutPoint,
signDescriptor *lnwallet.SignDescriptor) BaseInput { signDescriptor *lnwallet.SignDescriptor) BaseInput {
return BaseInput{ return BaseInput{
inputKit{
outpoint: *outpoint, outpoint: *outpoint,
witnessType: witnessType, witnessType: witnessType,
signDesc: *signDescriptor, signDesc: *signDescriptor,
},
} }
} }
// OutPoint returns the breached output's identifier that is to be included as a
// transaction input.
func (bi *BaseInput) OutPoint() *wire.OutPoint {
return &bi.outpoint
}
// WitnessType returns the type of witness that must be generated to spend the
// breached output.
func (bi *BaseInput) WitnessType() lnwallet.WitnessType {
return bi.witnessType
}
// SignDesc returns the breached output's SignDescriptor, which is used during
// signing to compute the witness.
func (bi *BaseInput) SignDesc() *lnwallet.SignDescriptor {
return &bi.signDesc
}
// BuildWitness computes a valid witness that allows us to spend from the // BuildWitness computes a valid witness that allows us to spend from the
// breached output. It does so by generating the witness generation function, // breached output. It does so by generating the witness generation function,
// which is parameterized primarily by the witness type and sign descriptor. The // which is parameterized primarily by the witness type and sign descriptor. The
@ -94,6 +101,54 @@ func (bi *BaseInput) BlocksToMaturity() uint32 {
return 0 return 0
} }
// Add compile-time constraint ensuring BaseInput implements // HtlcSucceedInput constitutes a sweep input that needs a pre-image. The input
// SpendableOutput. // is expected to reside on the commitment tx of the remote party and should not
// be a second level tx output.
type HtlcSucceedInput struct {
inputKit
preimage []byte
}
// MakeHtlcSucceedInput assembles a new redeem input that can be used to
// construct a sweep transaction.
func MakeHtlcSucceedInput(outpoint *wire.OutPoint,
signDescriptor *lnwallet.SignDescriptor,
preimage []byte) HtlcSucceedInput {
return HtlcSucceedInput{
inputKit: inputKit{
outpoint: *outpoint,
witnessType: lnwallet.HtlcAcceptedRemoteSuccess,
signDesc: *signDescriptor,
},
preimage: preimage,
}
}
// BuildWitness computes a valid witness that allows us to spend from the
// breached output. For HtlcSpendInput it will need to make the preimage part of
// the witness.
func (h *HtlcSucceedInput) BuildWitness(signer lnwallet.Signer, txn *wire.MsgTx,
hashCache *txscript.TxSigHashes, txinIdx int) ([][]byte, error) {
desc := h.signDesc
desc.SigHashes = hashCache
desc.InputIndex = txinIdx
return lnwallet.SenderHtlcSpendRedeem(
signer, &desc, txn,
h.preimage,
)
}
// BlocksToMaturity returns the relative timelock, as a number of blocks, that
// must be built on top of the confirmation height before the output can be
// spent.
func (h *HtlcSucceedInput) BlocksToMaturity() uint32 {
return 0
}
// Add compile-time constraint ensuring input structs implement Input interface.
var _ Input = (*BaseInput)(nil) var _ Input = (*BaseInput)(nil)
var _ Input = (*HtlcSucceedInput)(nil)

@ -118,6 +118,13 @@ func (s *UtxoSweeper) CreateSweepTx(inputs []Input,
) )
cltvCount++ cltvCount++
// An HTLC on the commitment transaction of the remote party,
// that can be swept with the preimage.
case lnwallet.HtlcAcceptedRemoteSuccess:
weightEstimate.AddWitnessInput(
lnwallet.OfferedHtlcSuccessWitnessSize,
)
default: default:
unknownCount++ unknownCount++
log.Warnf("kindergarten output in nursery store "+ log.Warnf("kindergarten output in nursery store "+