You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
12 KiB
387 lines
12 KiB
package input |
|
|
|
import ( |
|
"github.com/btcsuite/btcd/txscript" |
|
"github.com/btcsuite/btcd/wire" |
|
"github.com/btcsuite/btcutil" |
|
"github.com/lightningnetwork/lnd/lntypes" |
|
) |
|
|
|
// Input represents an abstract UTXO which is to be spent using a sweeping |
|
// transaction. The method provided give the caller all information needed to |
|
// construct a valid input within a sweeping transaction to sweep this |
|
// lingering UTXO. |
|
type Input interface { |
|
// Outpoint returns the reference to the output being spent, used to |
|
// construct the corresponding transaction input. |
|
OutPoint() *wire.OutPoint |
|
|
|
// RequiredTxOut returns a non-nil TxOut if input commits to a certain |
|
// transaction output. This is used in the SINGLE|ANYONECANPAY case to |
|
// make sure any presigned input is still valid by including the |
|
// output. |
|
RequiredTxOut() *wire.TxOut |
|
|
|
// RequiredLockTime returns whether this input commits to a tx locktime |
|
// that must be used in the transaction including it. |
|
RequiredLockTime() (uint32, bool) |
|
|
|
// WitnessType returns an enum specifying the type of witness that must |
|
// be generated in order to spend this output. |
|
WitnessType() WitnessType |
|
|
|
// SignDesc returns a reference to a spendable output's sign |
|
// descriptor, which is used during signing to compute a valid witness |
|
// that spends this output. |
|
SignDesc() *SignDescriptor |
|
|
|
// CraftInputScript returns a valid set of input scripts allowing this |
|
// output to be spent. The returns input scripts should target the |
|
// input at location txIndex within the passed transaction. The input |
|
// scripts generated by this method support spending p2wkh, p2wsh, and |
|
// also nested p2sh outputs. |
|
CraftInputScript(signer Signer, txn *wire.MsgTx, |
|
hashCache *txscript.TxSigHashes, |
|
txinIdx int) (*Script, error) |
|
|
|
// 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. For non-CSV locked inputs this is always |
|
// zero. |
|
BlocksToMaturity() uint32 |
|
|
|
// HeightHint returns the minimum height at which a confirmed spending |
|
// tx can occur. |
|
HeightHint() uint32 |
|
|
|
// UnconfParent returns information about a possibly unconfirmed parent |
|
// tx. |
|
UnconfParent() *TxInfo |
|
} |
|
|
|
// TxInfo describes properties of a parent tx that are relevant for CPFP. |
|
type TxInfo struct { |
|
// Fee is the fee of the tx. |
|
Fee btcutil.Amount |
|
|
|
// Weight is the weight of the tx. |
|
Weight int64 |
|
} |
|
|
|
// SignDetails is a struct containing information needed to resign certain |
|
// inputs. It is used to re-sign 2nd level HTLC transactions that uses the |
|
// SINGLE|ANYONECANPAY sighash type, as we have a signature provided by our |
|
// peer, but we can aggregate multiple of these 2nd level transactions into a |
|
// new transaction, that needs to be signed by us. |
|
type SignDetails struct { |
|
// SignDesc is the sign descriptor needed for us to sign the input. |
|
SignDesc SignDescriptor |
|
|
|
// PeerSig is the peer's signature for this input. |
|
PeerSig Signature |
|
|
|
// SigHashType is the sighash signed by the peer. |
|
SigHashType txscript.SigHashType |
|
} |
|
|
|
type inputKit struct { |
|
outpoint wire.OutPoint |
|
witnessType WitnessType |
|
signDesc SignDescriptor |
|
heightHint uint32 |
|
blockToMaturity uint32 |
|
|
|
// unconfParent contains information about a potential unconfirmed |
|
// parent transaction. |
|
unconfParent *TxInfo |
|
} |
|
|
|
// 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 |
|
} |
|
|
|
// RequiredTxOut returns a nil for the base input type. |
|
func (i *inputKit) RequiredTxOut() *wire.TxOut { |
|
return nil |
|
} |
|
|
|
// RequiredLockTime returns whether this input commits to a tx locktime that |
|
// must be used in the transaction including it. This will be false for the |
|
// base input type since we can re-sign for any lock time. |
|
func (i *inputKit) RequiredLockTime() (uint32, bool) { |
|
return 0, false |
|
} |
|
|
|
// WitnessType returns the type of witness that must be generated to spend the |
|
// breached output. |
|
func (i *inputKit) WitnessType() WitnessType { |
|
return i.witnessType |
|
} |
|
|
|
// SignDesc returns the breached output's SignDescriptor, which is used during |
|
// signing to compute the witness. |
|
func (i *inputKit) SignDesc() *SignDescriptor { |
|
return &i.signDesc |
|
} |
|
|
|
// HeightHint returns the minimum height at which a confirmed spending |
|
// tx can occur. |
|
func (i *inputKit) HeightHint() uint32 { |
|
return i.heightHint |
|
} |
|
|
|
// 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. For non-CSV locked inputs this is always zero. |
|
func (i *inputKit) BlocksToMaturity() uint32 { |
|
return i.blockToMaturity |
|
} |
|
|
|
// Cpfp returns information about a possibly unconfirmed parent tx. |
|
func (i *inputKit) UnconfParent() *TxInfo { |
|
return i.unconfParent |
|
} |
|
|
|
// 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 |
|
// sweep transaction. |
|
func MakeBaseInput(outpoint *wire.OutPoint, witnessType WitnessType, |
|
signDescriptor *SignDescriptor, heightHint uint32, |
|
unconfParent *TxInfo) BaseInput { |
|
|
|
return BaseInput{ |
|
inputKit{ |
|
outpoint: *outpoint, |
|
witnessType: witnessType, |
|
signDesc: *signDescriptor, |
|
heightHint: heightHint, |
|
unconfParent: unconfParent, |
|
}, |
|
} |
|
} |
|
|
|
// NewBaseInput allocates and assembles a new *BaseInput that can be used to |
|
// construct a sweep transaction. |
|
func NewBaseInput(outpoint *wire.OutPoint, witnessType WitnessType, |
|
signDescriptor *SignDescriptor, heightHint uint32) *BaseInput { |
|
|
|
input := MakeBaseInput( |
|
outpoint, witnessType, signDescriptor, heightHint, nil, |
|
) |
|
|
|
return &input |
|
} |
|
|
|
// NewCsvInput assembles a new csv-locked input that can be used to |
|
// construct a sweep transaction. |
|
func NewCsvInput(outpoint *wire.OutPoint, witnessType WitnessType, |
|
signDescriptor *SignDescriptor, heightHint uint32, |
|
blockToMaturity uint32) *BaseInput { |
|
|
|
return &BaseInput{ |
|
inputKit{ |
|
outpoint: *outpoint, |
|
witnessType: witnessType, |
|
signDesc: *signDescriptor, |
|
heightHint: heightHint, |
|
blockToMaturity: blockToMaturity, |
|
}, |
|
} |
|
} |
|
|
|
// CraftInputScript returns a valid set of input scripts allowing this output |
|
// to be spent. The returned input scripts should target the input at location |
|
// txIndex within the passed transaction. The input scripts generated by this |
|
// method support spending p2wkh, p2wsh, and also nested p2sh outputs. |
|
func (bi *BaseInput) CraftInputScript(signer Signer, txn *wire.MsgTx, |
|
hashCache *txscript.TxSigHashes, txinIdx int) (*Script, error) { |
|
|
|
witnessFunc := bi.witnessType.WitnessGenerator(signer, bi.SignDesc()) |
|
|
|
return witnessFunc(txn, hashCache, txinIdx) |
|
} |
|
|
|
// HtlcSucceedInput constitutes a sweep input that needs a pre-image. The input |
|
// 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 *SignDescriptor, preimage []byte, heightHint, |
|
blocksToMaturity uint32) HtlcSucceedInput { |
|
|
|
return HtlcSucceedInput{ |
|
inputKit: inputKit{ |
|
outpoint: *outpoint, |
|
witnessType: HtlcAcceptedRemoteSuccess, |
|
signDesc: *signDescriptor, |
|
heightHint: heightHint, |
|
blockToMaturity: blocksToMaturity, |
|
}, |
|
preimage: preimage, |
|
} |
|
} |
|
|
|
// CraftInputScript returns a valid set of input scripts allowing this output |
|
// to be spent. The returns input scripts should target the input at location |
|
// txIndex within the passed transaction. The input scripts generated by this |
|
// method support spending p2wkh, p2wsh, and also nested p2sh outputs. |
|
func (h *HtlcSucceedInput) CraftInputScript(signer Signer, txn *wire.MsgTx, |
|
hashCache *txscript.TxSigHashes, txinIdx int) (*Script, error) { |
|
|
|
desc := h.signDesc |
|
desc.SigHashes = hashCache |
|
desc.InputIndex = txinIdx |
|
|
|
witness, err := SenderHtlcSpendRedeem( |
|
signer, &desc, txn, h.preimage, |
|
) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
} |
|
|
|
// HtlcsSecondLevelAnchorInput is an input type used to spend HTLC outputs |
|
// using a re-signed second level transaction, either via the timeout or success |
|
// paths. |
|
type HtlcSecondLevelAnchorInput struct { |
|
inputKit |
|
|
|
// SignedTx is the original second level transaction signed by the |
|
// channel peer. |
|
SignedTx *wire.MsgTx |
|
|
|
// createWitness creates a witness allowing the passed transaction to |
|
// spend the input. |
|
createWitness func(signer Signer, txn *wire.MsgTx, |
|
hashCache *txscript.TxSigHashes, txinIdx int) (wire.TxWitness, error) |
|
} |
|
|
|
// RequiredTxOut returns the tx out needed to be present on the sweep tx for |
|
// the spend of the input to be valid. |
|
func (i *HtlcSecondLevelAnchorInput) RequiredTxOut() *wire.TxOut { |
|
return i.SignedTx.TxOut[0] |
|
} |
|
|
|
// RequiredLockTime returns the locktime needed for the sweep tx for the spend |
|
// of the input to be valid. For a second level HTLC timeout this will be the |
|
// CLTV expiry, for HTLC success it will be zero. |
|
func (i *HtlcSecondLevelAnchorInput) RequiredLockTime() (uint32, bool) { |
|
return i.SignedTx.LockTime, true |
|
} |
|
|
|
// CraftInputScript returns a valid set of input scripts allowing this output |
|
// to be spent. The returns input scripts should target the input at location |
|
// txIndex within the passed transaction. The input scripts generated by this |
|
// method support spending p2wkh, p2wsh, and also nested p2sh outputs. |
|
func (i *HtlcSecondLevelAnchorInput) CraftInputScript(signer Signer, |
|
txn *wire.MsgTx, hashCache *txscript.TxSigHashes, |
|
txinIdx int) (*Script, error) { |
|
|
|
witness, err := i.createWitness(signer, txn, hashCache, txinIdx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
} |
|
|
|
// MakeHtlcSecondLevelTimeoutAnchorInput creates an input allowing the sweeper |
|
// to spend the HTLC output on our commit using the second level timeout |
|
// transaction. |
|
func MakeHtlcSecondLevelTimeoutAnchorInput(signedTx *wire.MsgTx, |
|
signDetails *SignDetails, heightHint uint32) HtlcSecondLevelAnchorInput { |
|
|
|
// Spend an HTLC output on our local commitment tx using the |
|
// 2nd timeout transaction. |
|
createWitness := func(signer Signer, txn *wire.MsgTx, |
|
hashCache *txscript.TxSigHashes, |
|
txinIdx int) (wire.TxWitness, error) { |
|
|
|
desc := signDetails.SignDesc |
|
desc.SigHashes = txscript.NewTxSigHashes(txn) |
|
desc.InputIndex = txinIdx |
|
|
|
return SenderHtlcSpendTimeout( |
|
signDetails.PeerSig, signDetails.SigHashType, signer, |
|
&desc, txn, |
|
) |
|
} |
|
|
|
return HtlcSecondLevelAnchorInput{ |
|
inputKit: inputKit{ |
|
outpoint: signedTx.TxIn[0].PreviousOutPoint, |
|
witnessType: HtlcOfferedTimeoutSecondLevelInputConfirmed, |
|
signDesc: signDetails.SignDesc, |
|
heightHint: heightHint, |
|
|
|
// CSV delay is always 1 for these inputs. |
|
blockToMaturity: 1, |
|
}, |
|
SignedTx: signedTx, |
|
createWitness: createWitness, |
|
} |
|
} |
|
|
|
// MakeHtlcSecondLevelSuccessAnchorInput creates an input allowing the sweeper |
|
// to spend the HTLC output on our commit using the second level success |
|
// transaction. |
|
func MakeHtlcSecondLevelSuccessAnchorInput(signedTx *wire.MsgTx, |
|
signDetails *SignDetails, preimage lntypes.Preimage, |
|
heightHint uint32) HtlcSecondLevelAnchorInput { |
|
|
|
// Spend an HTLC output on our local commitment tx using the 2nd |
|
// success transaction. |
|
createWitness := func(signer Signer, txn *wire.MsgTx, |
|
hashCache *txscript.TxSigHashes, |
|
txinIdx int) (wire.TxWitness, error) { |
|
|
|
desc := signDetails.SignDesc |
|
desc.SigHashes = hashCache |
|
desc.InputIndex = txinIdx |
|
|
|
return ReceiverHtlcSpendRedeem( |
|
signDetails.PeerSig, signDetails.SigHashType, |
|
preimage[:], signer, &desc, txn, |
|
) |
|
} |
|
|
|
return HtlcSecondLevelAnchorInput{ |
|
inputKit: inputKit{ |
|
outpoint: signedTx.TxIn[0].PreviousOutPoint, |
|
witnessType: HtlcAcceptedSuccessSecondLevelInputConfirmed, |
|
signDesc: signDetails.SignDesc, |
|
heightHint: heightHint, |
|
|
|
// CSV delay is always 1 for these inputs. |
|
blockToMaturity: 1, |
|
}, |
|
SignedTx: signedTx, |
|
createWitness: createWitness, |
|
} |
|
} |
|
|
|
// Compile-time constraints to ensure each input struct implement the Input |
|
// interface. |
|
var _ Input = (*BaseInput)(nil) |
|
var _ Input = (*HtlcSucceedInput)(nil) |
|
var _ Input = (*HtlcSecondLevelAnchorInput)(nil)
|
|
|