mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
multi: use prev output fetcher where possible
This commit is contained in:
parent
72c9582b85
commit
f130eddb92
@ -1096,11 +1096,15 @@ func (bo *breachedOutput) SignDesc() *input.SignDescriptor {
|
||||
// sign descriptor. The method then returns the witness computed by invoking
|
||||
// this function on the first and subsequent calls.
|
||||
func (bo *breachedOutput) CraftInputScript(signer input.Signer, txn *wire.MsgTx,
|
||||
hashCache *txscript.TxSigHashes, txinIdx int) (*input.Script, error) {
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher,
|
||||
txinIdx int) (*input.Script, error) {
|
||||
|
||||
// First, we ensure that the witness generation function has been
|
||||
// initialized for this breached output.
|
||||
bo.witnessFunc = bo.witnessType.WitnessGenerator(signer, bo.SignDesc())
|
||||
signDesc := bo.SignDesc()
|
||||
signDesc.PrevOutputFetcher = prevOutputFetcher
|
||||
bo.witnessFunc = bo.witnessType.WitnessGenerator(signer, signDesc)
|
||||
|
||||
// Now that we have ensured that the witness generation function has
|
||||
// been initialized, we can proceed to execute it and generate the
|
||||
@ -1397,8 +1401,8 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64,
|
||||
|
||||
// Compute the total amount contained in the inputs.
|
||||
var totalAmt btcutil.Amount
|
||||
for _, input := range inputs {
|
||||
totalAmt += btcutil.Amount(input.SignDesc().Output.Value)
|
||||
for _, inp := range inputs {
|
||||
totalAmt += btcutil.Amount(inp.SignDesc().Output.Value)
|
||||
}
|
||||
|
||||
// We'll actually attempt to target inclusion within the next two
|
||||
@ -1424,10 +1428,10 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64,
|
||||
|
||||
// Next, we add all of the spendable outputs as inputs to the
|
||||
// transaction.
|
||||
for _, input := range inputs {
|
||||
for _, inp := range inputs {
|
||||
txn.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: *input.OutPoint(),
|
||||
Sequence: input.BlocksToMaturity(),
|
||||
PreviousOutPoint: *inp.OutPoint(),
|
||||
Sequence: inp.BlocksToMaturity(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -1440,7 +1444,11 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64,
|
||||
|
||||
// Create a sighash cache to improve the performance of hashing and
|
||||
// signing SigHashAll inputs.
|
||||
hashCache := input.NewTxSigHashesV0Only(txn)
|
||||
prevOutputFetcher, err := input.MultiPrevOutFetcher(inputs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashCache := txscript.NewTxSigHashes(txn, prevOutputFetcher)
|
||||
|
||||
// Create a closure that encapsulates the process of initializing a
|
||||
// particular output's witness generation function, computing the
|
||||
@ -1452,7 +1460,7 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64,
|
||||
// transaction using the SpendableOutput's witness generation
|
||||
// function.
|
||||
inputScript, err := so.CraftInputScript(
|
||||
b.cfg.Signer, txn, hashCache, idx,
|
||||
b.cfg.Signer, txn, hashCache, prevOutputFetcher, idx,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1467,8 +1475,8 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64,
|
||||
|
||||
// Finally, generate a witness for each output and attach it to the
|
||||
// transaction.
|
||||
for i, input := range inputs {
|
||||
if err := addWitness(i, input); err != nil {
|
||||
for i, inp := range inputs {
|
||||
if err := addWitness(i, inp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -1648,7 +1656,7 @@ func (ret *retributionInfo) Encode(w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dencode deserializes a retribution from the passed byte stream.
|
||||
// Decode deserializes a retribution from the passed byte stream.
|
||||
func (ret *retributionInfo) Decode(r io.Reader) error {
|
||||
var scratch [32]byte
|
||||
|
||||
|
@ -1386,8 +1386,11 @@ func getSpendTransactions(signer input.Signer, chanPoint *wire.OutPoint,
|
||||
case input.HtlcAcceptedRevoke:
|
||||
fallthrough
|
||||
case input.HtlcOfferedRevoke:
|
||||
cannedFetcher := txscript.NewCannedPrevOutputFetcher(
|
||||
nil, 0,
|
||||
)
|
||||
inputScript, err := inp.CraftInputScript(
|
||||
signer, htlcSweep, hashCache, 0,
|
||||
signer, htlcSweep, hashCache, cannedFetcher, 0,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -42,6 +42,7 @@ type Input interface {
|
||||
// also nested p2sh outputs.
|
||||
CraftInputScript(signer Signer, txn *wire.MsgTx,
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher,
|
||||
txinIdx int) (*Script, error)
|
||||
|
||||
// BlocksToMaturity returns the relative timelock, as a number of
|
||||
@ -221,9 +222,13 @@ func NewCsvInputWithCltv(outpoint *wire.OutPoint, witnessType WitnessType,
|
||||
// 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) {
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (*Script,
|
||||
error) {
|
||||
|
||||
witnessFunc := bi.witnessType.WitnessGenerator(signer, bi.SignDesc())
|
||||
signDesc := bi.SignDesc()
|
||||
signDesc.PrevOutputFetcher = prevOutputFetcher
|
||||
witnessFunc := bi.witnessType.WitnessGenerator(signer, signDesc)
|
||||
|
||||
return witnessFunc(txn, hashCache, txinIdx)
|
||||
}
|
||||
@ -260,11 +265,14 @@ func MakeHtlcSucceedInput(outpoint *wire.OutPoint,
|
||||
// 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) {
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (*Script,
|
||||
error) {
|
||||
|
||||
desc := h.signDesc
|
||||
desc.SigHashes = hashCache
|
||||
desc.InputIndex = txinIdx
|
||||
desc.PrevOutputFetcher = prevOutputFetcher
|
||||
|
||||
witness, err := SenderHtlcSpendRedeem(
|
||||
signer, &desc, txn, h.preimage,
|
||||
@ -291,7 +299,9 @@ type HtlcSecondLevelAnchorInput struct {
|
||||
// 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)
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher,
|
||||
txinIdx int) (wire.TxWitness, error)
|
||||
}
|
||||
|
||||
// RequiredTxOut returns the tx out needed to be present on the sweep tx for
|
||||
@ -313,9 +323,12 @@ func (i *HtlcSecondLevelAnchorInput) RequiredLockTime() (uint32, bool) {
|
||||
// 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) {
|
||||
prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (*Script,
|
||||
error) {
|
||||
|
||||
witness, err := i.createWitness(signer, txn, hashCache, txinIdx)
|
||||
witness, err := i.createWitness(
|
||||
signer, txn, hashCache, prevOutputFetcher, txinIdx,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -335,11 +348,13 @@ func MakeHtlcSecondLevelTimeoutAnchorInput(signedTx *wire.MsgTx,
|
||||
// 2nd timeout transaction.
|
||||
createWitness := func(signer Signer, txn *wire.MsgTx,
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher,
|
||||
txinIdx int) (wire.TxWitness, error) {
|
||||
|
||||
desc := signDetails.SignDesc
|
||||
desc.SigHashes = NewTxSigHashesV0Only(txn)
|
||||
desc.SigHashes = txscript.NewTxSigHashes(txn, prevOutputFetcher)
|
||||
desc.InputIndex = txinIdx
|
||||
desc.PrevOutputFetcher = prevOutputFetcher
|
||||
|
||||
return SenderHtlcSpendTimeout(
|
||||
signDetails.PeerSig, signDetails.SigHashType, signer,
|
||||
@ -373,11 +388,13 @@ func MakeHtlcSecondLevelSuccessAnchorInput(signedTx *wire.MsgTx,
|
||||
// success transaction.
|
||||
createWitness := func(signer Signer, txn *wire.MsgTx,
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher,
|
||||
txinIdx int) (wire.TxWitness, error) {
|
||||
|
||||
desc := signDetails.SignDesc
|
||||
desc.SigHashes = hashCache
|
||||
desc.InputIndex = txinIdx
|
||||
desc.PrevOutputFetcher = prevOutputFetcher
|
||||
|
||||
return ReceiverHtlcSpendRedeem(
|
||||
signDetails.PeerSig, signDetails.SigHashType,
|
||||
|
@ -74,6 +74,11 @@ type SignDescriptor struct {
|
||||
// generating the final sighash for signing.
|
||||
SigHashes *txscript.TxSigHashes
|
||||
|
||||
// PrevOutputFetcher is an interface that can return the output
|
||||
// information on all UTXOs that are being spent in this transaction.
|
||||
// This MUST be set when spending Taproot outputs.
|
||||
PrevOutputFetcher txscript.PrevOutputFetcher
|
||||
|
||||
// InputIndex is the target input within the transaction that should be
|
||||
// signed.
|
||||
InputIndex int
|
||||
|
@ -1,6 +1,8 @@
|
||||
package input
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
@ -18,3 +20,25 @@ func NewTxSigHashesV0Only(tx *wire.MsgTx) *txscript.TxSigHashes {
|
||||
nilFetcher := txscript.NewCannedPrevOutputFetcher(nil, 0)
|
||||
return txscript.NewTxSigHashes(tx, nilFetcher)
|
||||
}
|
||||
|
||||
// MultiPrevOutFetcher returns a txscript.MultiPrevOutFetcher for the given set
|
||||
// of inputs.
|
||||
func MultiPrevOutFetcher(inputs []Input) (*txscript.MultiPrevOutFetcher, error) {
|
||||
fetcher := txscript.NewMultiPrevOutFetcher(nil)
|
||||
for _, inp := range inputs {
|
||||
op := inp.OutPoint()
|
||||
desc := inp.SignDesc()
|
||||
|
||||
if op == nil {
|
||||
return nil, fmt.Errorf("missing input outpoint")
|
||||
}
|
||||
|
||||
if desc == nil || desc.Output == nil {
|
||||
return nil, fmt.Errorf("missing input utxo information")
|
||||
}
|
||||
|
||||
fetcher.AddPrevOut(*op, desc.Output)
|
||||
}
|
||||
|
||||
return fetcher, nil
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/btcsuite/btcd/btcutil/psbt"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
@ -107,7 +108,8 @@ func (b *BtcWallet) SignPsbt(packet *psbt.Packet) error {
|
||||
// there are inputs that we don't know how to sign, we won't return any
|
||||
// error. So it's possible we're not the final signer.
|
||||
tx := packet.UnsignedTx
|
||||
sigHashes := input.NewTxSigHashesV0Only(tx)
|
||||
prevOutputFetcher := wallet.PsbtPrevOutputFetcher(packet)
|
||||
sigHashes := txscript.NewTxSigHashes(tx, prevOutputFetcher)
|
||||
for idx := range tx.TxIn {
|
||||
in := packet.Inputs[idx]
|
||||
|
||||
|
@ -107,9 +107,15 @@ func (f *FullIntent) CompileFundingTx(extraInputs []*wire.TxIn,
|
||||
|
||||
// Next, sign all inputs that are ours, collecting the signatures in
|
||||
// order of the inputs.
|
||||
prevOutFetcher := NewSegWitV0DualFundingPrevOutputFetcher(
|
||||
f.coinSource, extraInputs,
|
||||
)
|
||||
signDesc := input.SignDescriptor{
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: input.NewTxSigHashesV0Only(fundingTx),
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: txscript.NewTxSigHashes(
|
||||
fundingTx, prevOutFetcher,
|
||||
),
|
||||
PrevOutputFetcher: prevOutFetcher,
|
||||
}
|
||||
for i, txIn := range fundingTx.TxIn {
|
||||
// We can only sign this input if it's ours, so we'll ask the
|
||||
@ -374,3 +380,55 @@ func (w *WalletAssembler) FundingTxAvailable() {}
|
||||
// A compile-time assertion to ensure the WalletAssembler meets the
|
||||
// FundingTxAssembler interface.
|
||||
var _ FundingTxAssembler = (*WalletAssembler)(nil)
|
||||
|
||||
// SegWitV0DualFundingPrevOutputFetcher is a txscript.PrevOutputFetcher that
|
||||
// knows about local and remote funding inputs.
|
||||
//
|
||||
// TODO(guggero): Support dual funding with p2tr inputs, currently only segwit
|
||||
// v0 inputs are supported.
|
||||
type SegWitV0DualFundingPrevOutputFetcher struct {
|
||||
local CoinSource
|
||||
remote *txscript.MultiPrevOutFetcher
|
||||
}
|
||||
|
||||
var _ txscript.PrevOutputFetcher = (*SegWitV0DualFundingPrevOutputFetcher)(nil)
|
||||
|
||||
// NewSegWitV0DualFundingPrevOutputFetcher creates a new
|
||||
// txscript.PrevOutputFetcher from the given local and remote inputs.
|
||||
//
|
||||
// NOTE: Since the actual pkScript and amounts aren't passed in, this will just
|
||||
// make sure that nothing will panic when creating a SegWit v0 sighash. But this
|
||||
// code will NOT WORK for transactions that spend any Taproot inputs!
|
||||
func NewSegWitV0DualFundingPrevOutputFetcher(localSource CoinSource,
|
||||
remoteInputs []*wire.TxIn) txscript.PrevOutputFetcher {
|
||||
|
||||
remote := txscript.NewMultiPrevOutFetcher(nil)
|
||||
for _, inp := range remoteInputs {
|
||||
// We add an empty output to prevent the sighash calculation
|
||||
// from panicking. But this will always detect the inputs as
|
||||
// SegWig v0!
|
||||
remote.AddPrevOut(inp.PreviousOutPoint, &wire.TxOut{})
|
||||
}
|
||||
return &SegWitV0DualFundingPrevOutputFetcher{
|
||||
local: localSource,
|
||||
remote: remote,
|
||||
}
|
||||
}
|
||||
|
||||
// FetchPrevOutput attempts to fetch the previous output referenced by the
|
||||
// passed outpoint.
|
||||
//
|
||||
// NOTE: This is a part of the txscript.PrevOutputFetcher interface.
|
||||
func (d *SegWitV0DualFundingPrevOutputFetcher) FetchPrevOutput(
|
||||
op wire.OutPoint) *wire.TxOut {
|
||||
|
||||
// Try the local source first. This will return nil if our internal
|
||||
// wallet doesn't know the outpoint.
|
||||
coin, err := d.local.CoinFromOutPoint(op)
|
||||
if err == nil && coin != nil {
|
||||
return &coin.TxOut
|
||||
}
|
||||
|
||||
// Fall back to the remote
|
||||
return d.remote.FetchPrevOutput(op)
|
||||
}
|
||||
|
@ -133,9 +133,11 @@ func (r *RPCKeyRing) SendOutputs(outputs []*wire.TxOut,
|
||||
|
||||
// We know at this point that we only have inputs from our own wallet.
|
||||
// So we can just compute the input script using the remote signer.
|
||||
outputFetcher := lnwallet.NewWalletPrevOutputFetcher(r.WalletController)
|
||||
signDesc := input.SignDescriptor{
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: input.NewTxSigHashesV0Only(tx),
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: txscript.NewTxSigHashes(tx, outputFetcher),
|
||||
PrevOutputFetcher: outputFetcher,
|
||||
}
|
||||
for i, txIn := range tx.TxIn {
|
||||
// We can only sign this input if it's ours, so we'll ask the
|
||||
@ -579,6 +581,32 @@ func (r *RPCKeyRing) remoteSign(tx *wire.MsgTx, signDesc *input.SignDescriptor,
|
||||
return nil, fmt.Errorf("error converting TX into PSBT: %v", err)
|
||||
}
|
||||
|
||||
// We need to add witness information for all inputs! Otherwise, we'll
|
||||
// have a problem when attempting to sign a taproot input!
|
||||
for idx := range packet.Inputs {
|
||||
// Skip the input we're signing for, that will get a special
|
||||
// treatment later on.
|
||||
if idx == signDesc.InputIndex {
|
||||
continue
|
||||
}
|
||||
|
||||
txIn := tx.TxIn[idx]
|
||||
info, err := r.WalletController.FetchInputInfo(
|
||||
&txIn.PreviousOutPoint,
|
||||
)
|
||||
if err != nil {
|
||||
log.Warnf("No UTXO info found for index %d "+
|
||||
"(prev_outpoint=%v), won't be able to sign "+
|
||||
"for taproot output!", idx,
|
||||
txIn.PreviousOutPoint)
|
||||
continue
|
||||
}
|
||||
packet.Inputs[idx].WitnessUtxo = &wire.TxOut{
|
||||
Value: int64(info.Value),
|
||||
PkScript: info.PkScript,
|
||||
}
|
||||
}
|
||||
|
||||
// Catch incorrect signing input index, just in case.
|
||||
if signDesc.InputIndex < 0 || signDesc.InputIndex >= len(packet.Inputs) {
|
||||
return nil, fmt.Errorf("invalid input index in sign descriptor")
|
||||
|
@ -2266,3 +2266,36 @@ func validateUpfrontShutdown(shutdown lnwire.DeliveryAddress,
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// WalletPrevOutputFetcher is a txscript.PrevOutputFetcher that can fetch
|
||||
// outputs from a given wallet controller.
|
||||
type WalletPrevOutputFetcher struct {
|
||||
wc WalletController
|
||||
}
|
||||
|
||||
// A compile time assertion that WalletPrevOutputFetcher implements the
|
||||
// txscript.PrevOutputFetcher interface.
|
||||
var _ txscript.PrevOutputFetcher = (*WalletPrevOutputFetcher)(nil)
|
||||
|
||||
// NewWalletPrevOutputFetcher creates a new WalletPrevOutputFetcher that fetches
|
||||
// previous outputs from the given wallet controller.
|
||||
func NewWalletPrevOutputFetcher(wc WalletController) *WalletPrevOutputFetcher {
|
||||
return &WalletPrevOutputFetcher{
|
||||
wc: wc,
|
||||
}
|
||||
}
|
||||
|
||||
// FetchPrevOutput attempts to fetch the previous output referenced by the
|
||||
// passed outpoint. A nil value will be returned if the passed outpoint doesn't
|
||||
// exist.
|
||||
func (w *WalletPrevOutputFetcher) FetchPrevOutput(op wire.OutPoint) *wire.TxOut {
|
||||
utxo, err := w.wc.FetchInputInfo(&op)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &wire.TxOut{
|
||||
Value: int64(utxo.Value),
|
||||
PkScript: utxo.PkScript,
|
||||
}
|
||||
}
|
||||
|
@ -1623,7 +1623,9 @@ func (i *testInput) RequiredTxOut() *wire.TxOut {
|
||||
// encode the spending outpoint and the tx input index as part of the returned
|
||||
// witness.
|
||||
func (i *testInput) CraftInputScript(_ input.Signer, txn *wire.MsgTx,
|
||||
hashCache *txscript.TxSigHashes, txinIdx int) (*input.Script, error) {
|
||||
hashCache *txscript.TxSigHashes,
|
||||
prevOutputFetcher txscript.PrevOutputFetcher,
|
||||
txinIdx int) (*input.Script, error) {
|
||||
|
||||
// We'll encode the outpoint in the witness, so we can assert that the
|
||||
// expected input was signed at the correct index.
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
@ -263,13 +264,18 @@ func createSweepTx(inputs []input.Input, outputs []*wire.TxOut,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashCache := input.NewTxSigHashesV0Only(sweepTx)
|
||||
prevInputFetcher, err := input.MultiPrevOutFetcher(inputs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating prev input fetcher "+
|
||||
"for hash cache: %v", err)
|
||||
}
|
||||
hashCache := txscript.NewTxSigHashes(sweepTx, prevInputFetcher)
|
||||
|
||||
// With all the inputs in place, use each output's unique input script
|
||||
// function to generate the final witness required for spending.
|
||||
addInputScript := func(idx int, tso input.Input) error {
|
||||
inputScript, err := tso.CraftInputScript(
|
||||
signer, sweepTx, hashCache, idx,
|
||||
signer, sweepTx, hashCache, prevInputFetcher, idx,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2,6 +2,7 @@ package lookout
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
@ -177,11 +178,11 @@ func (p *JusticeDescriptor) assembleJusticeTxn(txWeight int64,
|
||||
// First, construct add the breached inputs to our justice transaction
|
||||
// and compute the total amount that will be swept.
|
||||
var totalAmt btcutil.Amount
|
||||
for _, input := range inputs {
|
||||
totalAmt += btcutil.Amount(input.txOut.Value)
|
||||
for _, inp := range inputs {
|
||||
totalAmt += btcutil.Amount(inp.txOut.Value)
|
||||
justiceTxn.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: input.outPoint,
|
||||
Sequence: input.sequence,
|
||||
PreviousOutPoint: inp.outPoint,
|
||||
Sequence: inp.sequence,
|
||||
})
|
||||
}
|
||||
|
||||
@ -217,20 +218,22 @@ func (p *JusticeDescriptor) assembleJusticeTxn(txWeight int64,
|
||||
}
|
||||
|
||||
// Attach each of the provided witnesses to the transaction.
|
||||
for _, input := range inputs {
|
||||
prevOutFetcher, err := prevOutFetcher(inputs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating previous output "+
|
||||
"fetcher: %v", err)
|
||||
}
|
||||
for _, inp := range inputs {
|
||||
// Lookup the input's new post-sort position.
|
||||
i := inputIndex[input.outPoint]
|
||||
justiceTxn.TxIn[i].Witness = input.witness
|
||||
i := inputIndex[inp.outPoint]
|
||||
justiceTxn.TxIn[i].Witness = inp.witness
|
||||
|
||||
// Validate the reconstructed witnesses to ensure they are valid
|
||||
// for the breached inputs.
|
||||
vm, err := txscript.NewEngine(
|
||||
input.txOut.PkScript, justiceTxn, i,
|
||||
inp.txOut.PkScript, justiceTxn, i,
|
||||
txscript.StandardVerifyFlags,
|
||||
nil, nil, input.txOut.Value,
|
||||
txscript.NewCannedPrevOutputFetcher(
|
||||
input.txOut.PkScript, input.txOut.Value,
|
||||
),
|
||||
nil, nil, inp.txOut.Value, prevOutFetcher,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -345,3 +348,20 @@ func buildWitness(witnessStack [][]byte, witnessScript []byte) [][]byte {
|
||||
|
||||
return witness
|
||||
}
|
||||
|
||||
// prevOutFetcher returns a txscript.MultiPrevOutFetcher for the given set
|
||||
// of inputs.
|
||||
func prevOutFetcher(inputs []*breachedInput) (*txscript.MultiPrevOutFetcher,
|
||||
error) {
|
||||
|
||||
fetcher := txscript.NewMultiPrevOutFetcher(nil)
|
||||
for _, inp := range inputs {
|
||||
if inp.txOut == nil {
|
||||
return nil, fmt.Errorf("missing input utxo information")
|
||||
}
|
||||
|
||||
fetcher.AddPrevOut(inp.outPoint, inp.txOut)
|
||||
}
|
||||
|
||||
return fetcher, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/btcutil/txsort"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
@ -262,10 +263,14 @@ func (t *backupTask) craftSessionPayload(
|
||||
// information. This will either be contain both the to-local and
|
||||
// to-remote outputs, or only be the to-local output.
|
||||
inputs := t.inputs()
|
||||
for prevOutPoint, input := range inputs {
|
||||
prevOutputFetcher := txscript.NewMultiPrevOutFetcher(nil)
|
||||
for prevOutPoint, inp := range inputs {
|
||||
prevOutputFetcher.AddPrevOut(
|
||||
prevOutPoint, inp.SignDesc().Output,
|
||||
)
|
||||
justiceTxn.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: prevOutPoint,
|
||||
Sequence: input.BlocksToMaturity(),
|
||||
Sequence: inp.BlocksToMaturity(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -284,7 +289,7 @@ func (t *backupTask) craftSessionPayload(
|
||||
}
|
||||
|
||||
// Construct a sighash cache to improve signing performance.
|
||||
hashCache := input.NewTxSigHashesV0Only(justiceTxn)
|
||||
hashCache := txscript.NewTxSigHashes(justiceTxn, prevOutputFetcher)
|
||||
|
||||
// Since the transaction inputs could have been reordered as a result of
|
||||
// the BIP69 sort, create an index mapping each prevout to it's new
|
||||
@ -303,7 +308,7 @@ func (t *backupTask) craftSessionPayload(
|
||||
|
||||
// Construct the full witness required to spend this input.
|
||||
inputScript, err := inp.CraftInputScript(
|
||||
signer, justiceTxn, hashCache, i,
|
||||
signer, justiceTxn, hashCache, prevOutputFetcher, i,
|
||||
)
|
||||
if err != nil {
|
||||
return hint, nil, err
|
||||
|
Loading…
Reference in New Issue
Block a user