Merge pull request #70 from sputn1ck/rbfInputs

Add rbfinputs command
pull/71/head
Oliver Gugger 11 months ago committed by GitHub
commit 2a1997844d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -42,7 +42,7 @@ type closePoolAccountCommand struct {
AuctioneerKey string
Publish bool
SweepAddr string
FeeRate uint16
FeeRate uint32
MinExpiry uint32
MaxNumBlocks uint32
@ -91,7 +91,7 @@ obtained by running 'pool accounts list' `,
cc.cmd.Flags().StringVar(
&cc.SweepAddr, "sweepaddr", "", "address to sweep the funds to",
)
cc.cmd.Flags().Uint16Var(
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)
@ -158,7 +158,7 @@ func (c *closePoolAccountCommand) Execute(_ *cobra.Command, _ []string) error {
func closePoolAccount(extendedKey *hdkeychain.ExtendedKey, apiURL string,
outpoint *wire.OutPoint, auctioneerKey *btcec.PublicKey,
sweepAddr string, publish bool, feeRate uint16, minExpiry,
sweepAddr string, publish bool, feeRate uint32, minExpiry,
maxNumBlocks, maxNumAccounts, maxNumBatchKeys uint32) error {
signer := &lnd.Signer{

@ -0,0 +1,367 @@
package main
import (
"bytes"
"encoding/hex"
"fmt"
"strconv"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/guggero/chantools/btc"
"github.com/guggero/chantools/lnd"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/spf13/cobra"
)
type doubleSpendInputs struct {
APIURL string
InputOutpoints []string
Publish bool
SweepAddr string
FeeRate uint32
RecoveryWindow uint32
rootKey *rootKey
cmd *cobra.Command
}
func newDoubleSpendInputsCommand() *cobra.Command {
cc := &doubleSpendInputs{}
cc.cmd = &cobra.Command{
Use: "doublespendinputs",
Short: "Tries to double spend the given inputs by deriving the " +
"private for the address and sweeping the funds to the given " +
"address. This can only be used with inputs that belong to " +
"an lnd wallet.",
Example: `chantools doublespendinputs \
--inputoutpoints xxxxxxxxx:y,xxxxxxxxx:y \
--sweepaddr bc1q..... \
--feerate 10 \
--publish`,
RunE: cc.Execute,
}
cc.cmd.Flags().StringVar(
&cc.APIURL, "apiurl", defaultAPIURL, "API URL to use (must "+
"be esplora compatible)",
)
cc.cmd.Flags().StringSliceVar(
&cc.InputOutpoints, "inputoutpoints", []string{},
"list of outpoints to double spend in the format txid:vout",
)
cc.cmd.Flags().StringVar(
&cc.SweepAddr, "sweepaddr", "", "address to sweep the funds to",
)
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)
cc.cmd.Flags().Uint32Var(
&cc.RecoveryWindow, "recoverywindow", defaultRecoveryWindow,
"number of keys to scan per internal/external branch; output "+
"will consist of double this amount of keys",
)
cc.cmd.Flags().BoolVar(
&cc.Publish, "publish", false, "publish replacement TX to "+
"the chain API instead of just printing the TX",
)
cc.rootKey = newRootKey(cc.cmd, "deriving the input keys")
return cc.cmd
}
func (c *doubleSpendInputs) Execute(_ *cobra.Command, _ []string) error {
extendedKey, err := c.rootKey.read()
if err != nil {
return fmt.Errorf("error reading root key: %w", err)
}
// Make sure sweep addr is set.
if c.SweepAddr == "" {
return fmt.Errorf("sweep addr is required")
}
// Make sure we have at least one input.
if len(c.InputOutpoints) == 0 {
return fmt.Errorf("inputoutpoints are required")
}
api := &btc.ExplorerAPI{BaseURL: c.APIURL}
addresses := make([]btcutil.Address, 0, len(c.InputOutpoints))
outpoints := make([]*wire.OutPoint, 0, len(c.InputOutpoints))
privKeys := make([]*secp256k1.PrivateKey, 0, len(c.InputOutpoints))
// Get the addresses for the inputs.
for _, input := range c.InputOutpoints {
addrString, err := api.Address(input)
if err != nil {
return err
}
addr, err := btcutil.DecodeAddress(addrString, chainParams)
if err != nil {
return err
}
addresses = append(addresses, addr)
txHash, err := chainhash.NewHashFromStr(input[:64])
if err != nil {
return err
}
vout, err := strconv.Atoi(input[65:])
if err != nil {
return err
}
outpoint := wire.NewOutPoint(txHash, uint32(vout))
outpoints = append(outpoints, outpoint)
}
// Create the paths for the addresses.
p2wkhPath, err := lnd.ParsePath(lnd.WalletDefaultDerivationPath)
if err != nil {
return err
}
p2trPath, err := lnd.ParsePath(lnd.WalletBIP86DerivationPath)
if err != nil {
return err
}
// Start with the txweight estimator.
estimator := input.TxWeightEstimator{}
// Find the key for the given addresses and add their
// output weight to the tx estimator.
for _, addr := range addresses {
var key *hdkeychain.ExtendedKey
switch addr.(type) {
case *btcutil.AddressWitnessPubKeyHash:
key, err = iterateOverPath(
extendedKey, addr, p2wkhPath, c.RecoveryWindow,
)
if err != nil {
return err
}
estimator.AddP2WKHInput()
case *btcutil.AddressTaproot:
key, err = iterateOverPath(
extendedKey, addr, p2trPath, c.RecoveryWindow,
)
if err != nil {
return err
}
estimator.AddTaprootKeySpendInput(txscript.SigHashDefault)
default:
return fmt.Errorf("address type %T not supported", addr)
}
// Get the private key.
privKey, err := key.ECPrivKey()
if err != nil {
return err
}
privKeys = append(privKeys, privKey)
}
// Now that we have the keys, we can create the transaction.
prevOuts := make(map[wire.OutPoint]*wire.TxOut)
// Next get the full value of the inputs.
var totalInput btcutil.Amount
for _, input := range outpoints {
// Get the transaction.
tx, err := api.Transaction(input.Hash.String())
if err != nil {
return err
}
value := tx.Vout[input.Index].Value
// Get the output index.
totalInput += btcutil.Amount(value)
scriptPubkey, err := hex.DecodeString(tx.Vout[input.Index].ScriptPubkey)
if err != nil {
return err
}
// Add the output to the map.
prevOuts[*input] = &wire.TxOut{
Value: int64(value),
PkScript: scriptPubkey,
}
}
// Calculate the fee.
sweepAddr, err := btcutil.DecodeAddress(c.SweepAddr, chainParams)
if err != nil {
return err
}
switch sweepAddr.(type) {
case *btcutil.AddressWitnessPubKeyHash:
estimator.AddP2WKHOutput()
case *btcutil.AddressTaproot:
estimator.AddP2TROutput()
default:
return fmt.Errorf("address type %T not supported", sweepAddr)
}
// Calculate the fee.
feeRateKWeight := chainfee.SatPerKVByte(1000 * c.FeeRate).FeePerKWeight()
totalFee := feeRateKWeight.FeeForWeight(int64(estimator.Weight()))
// Create the transaction.
tx := wire.NewMsgTx(2)
// Add the inputs.
for _, input := range outpoints {
tx.AddTxIn(wire.NewTxIn(input, nil, nil))
}
// Add the output.
sweepScript, err := txscript.PayToAddrScript(sweepAddr)
if err != nil {
return err
}
tx.AddTxOut(wire.NewTxOut(int64(totalInput-totalFee), sweepScript))
// Calculate the signature hash.
prevOutFetcher := txscript.NewMultiPrevOutFetcher(prevOuts)
sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher)
// Sign the inputs depending on the address type.
for i, outpoint := range outpoints {
switch addresses[i].(type) {
case *btcutil.AddressWitnessPubKeyHash:
witness, err := txscript.WitnessSignature(
tx, sigHashes, i, prevOuts[*outpoint].Value,
prevOuts[*outpoint].PkScript,
txscript.SigHashAll, privKeys[i], true,
)
if err != nil {
return err
}
tx.TxIn[i].Witness = witness
case *btcutil.AddressTaproot:
rawTxSig, err := txscript.RawTxInTaprootSignature(
tx, sigHashes, i,
prevOuts[*outpoint].Value,
prevOuts[*outpoint].PkScript,
[]byte{}, txscript.SigHashDefault, privKeys[i],
)
if err != nil {
return err
}
tx.TxIn[i].Witness = wire.TxWitness{
rawTxSig,
}
default:
return fmt.Errorf("address type %T not supported", addresses[i])
}
}
// Serialize the transaction.
var txBuf bytes.Buffer
if err := tx.Serialize(&txBuf); err != nil {
return err
}
// Print the transaction.
fmt.Printf("Sweeping transaction:\n%s\n", hex.EncodeToString(txBuf.Bytes()))
// Publish the transaction.
if c.Publish {
txid, err := api.PublishTx(hex.EncodeToString(txBuf.Bytes()))
if err != nil {
return err
}
fmt.Printf("Published transaction with txid %s\n", txid)
}
return nil
}
// iterateOverPath iterates over the given key path and tries to find the
// private key that corresponds to the given address.
func iterateOverPath(baseKey *hdkeychain.ExtendedKey, addr btcutil.Address,
path []uint32, maxTries uint32) (*hdkeychain.ExtendedKey, error) {
for i := uint32(0); i < maxTries; i++ {
// Check for both the external and internal branch.
for _, branch := range []uint32{0, 1} {
// Create the path to derive the key.
addrPath := append(path, branch, i) //nolint:gocritic
// Derive the key.
derivedKey, err := lnd.DeriveChildren(baseKey, addrPath)
if err != nil {
return nil, err
}
var address btcutil.Address
switch addr.(type) {
case *btcutil.AddressWitnessPubKeyHash:
// Get the address for the derived key.
derivedAddr, err := derivedKey.Address(chainParams)
if err != nil {
return nil, err
}
address, err = btcutil.NewAddressWitnessPubKeyHash(
derivedAddr.ScriptAddress(), chainParams,
)
if err != nil {
return nil, err
}
case *btcutil.AddressTaproot:
pubkey, err := derivedKey.ECPubKey()
if err != nil {
return nil, err
}
pubkey = txscript.ComputeTaprootKeyNoScript(pubkey)
address, err = btcutil.NewAddressTaproot(
schnorr.SerializePubKey(pubkey), chainParams,
)
if err != nil {
return nil, err
}
}
// Compare the addresses.
if address.String() == addr.String() {
return derivedKey, nil
}
}
}
return nil, fmt.Errorf("could not find key for address %s", addr.String())
}

@ -25,7 +25,7 @@ type recoverLoopInCommand struct {
Vout uint32
SwapHash string
SweepAddr string
FeeRate uint16
FeeRate uint32
StartKeyIndex int
NumTries int
@ -73,7 +73,7 @@ func newRecoverLoopInCommand() *cobra.Command {
&cc.SweepAddr, "sweep_addr", "", "address to recover "+
"the funds to",
)
cc.cmd.Flags().Uint16Var(
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", 0, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)

@ -45,7 +45,7 @@ type rescueFundingCommand struct {
RemotePubKey string
SweepAddr string
FeeRate uint16
FeeRate uint32
APIURL string
rootKey *rootKey
@ -115,7 +115,7 @@ chantools rescuefunding \
cc.cmd.Flags().StringVar(
&cc.SweepAddr, "sweepaddr", "", "address to sweep the funds to",
)
cc.cmd.Flags().Uint16Var(
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)

@ -85,6 +85,7 @@ func main() {
newCompactDBCommand(),
newDeletePaymentsCommand(),
newDeriveKeyCommand(),
newDoubleSpendInputsCommand(),
newDropChannelGraphCommand(),
newDumpBackupCommand(),
newDumpChannelsCommand(),

@ -29,7 +29,7 @@ type sweepRemoteClosedCommand struct {
APIURL string
Publish bool
SweepAddr string
FeeRate uint16
FeeRate uint32
rootKey *rootKey
cmd *cobra.Command
@ -77,7 +77,7 @@ Supported remote force-closed channel types are:
cc.cmd.Flags().StringVar(
&cc.SweepAddr, "sweepaddr", "", "address to sweep the funds to",
)
cc.cmd.Flags().Uint16Var(
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)
@ -122,7 +122,7 @@ type targetAddr struct {
}
func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
sweepAddr string, recoveryWindow uint32, feeRate uint16,
sweepAddr string, recoveryWindow uint32, feeRate uint32,
publish bool) error {
var (

@ -29,7 +29,7 @@ type sweepTimeLockCommand struct {
Publish bool
SweepAddr string
MaxCsvLimit uint16
FeeRate uint16
FeeRate uint32
rootKey *rootKey
inputs *inputFlags
@ -71,7 +71,7 @@ parameter to 144.`,
&cc.MaxCsvLimit, "maxcsvlimit", defaultCsvLimit, "maximum CSV "+
"limit to use",
)
cc.cmd.Flags().Uint16Var(
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)
@ -125,7 +125,7 @@ type sweepTarget struct {
func sweepTimeLockFromSummary(extendedKey *hdkeychain.ExtendedKey, apiURL string,
entries []*dataformat.SummaryEntry, sweepAddr string,
maxCsvTimeout uint16, publish bool, feeRate uint16) error {
maxCsvTimeout uint16, publish bool, feeRate uint32) error {
targets := make([]*sweepTarget, 0, len(entries))
for _, entry := range entries {
@ -213,7 +213,7 @@ func sweepTimeLockFromSummary(extendedKey *hdkeychain.ExtendedKey, apiURL string
func sweepTimeLock(extendedKey *hdkeychain.ExtendedKey, apiURL string,
targets []*sweepTarget, sweepAddr string, maxCsvTimeout uint16,
publish bool, feeRate uint16) error {
publish bool, feeRate uint32) error {
// Create signer and transaction template.
signer := &lnd.Signer{

@ -30,7 +30,7 @@ type sweepTimeLockManualCommand struct {
Publish bool
SweepAddr string
MaxCsvLimit uint16
FeeRate uint16
FeeRate uint32
TimeLockAddr string
RemoteRevocationBasePoint string
@ -92,7 +92,7 @@ address is always the one that's longer (because it's P2WSH and not P2PKH).`,
"maximum number of channel updates to try, set to maximum "+
"number of times the channel was used",
)
cc.cmd.Flags().Uint16Var(
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)
@ -144,7 +144,7 @@ func (c *sweepTimeLockManualCommand) Execute(_ *cobra.Command, _ []string) error
func sweepTimeLockManual(extendedKey *hdkeychain.ExtendedKey, apiURL string,
sweepAddr, timeLockAddr string, remoteRevPoint *btcec.PublicKey,
maxCsvTimeout, maxNumChannels uint16, maxNumChanUpdates uint64,
publish bool, feeRate uint16) error {
publish bool, feeRate uint32) error {
// First of all, we need to parse the lock addr and make sure we can
// brute force the script with the information we have. If not, we can't

@ -26,7 +26,7 @@ import (
type zombieRecoveryMakeOfferCommand struct {
Node1 string
Node2 string
FeeRate uint16
FeeRate uint32
rootKey *rootKey
cmd *cobra.Command
@ -60,7 +60,7 @@ a counter offer.`,
&cc.Node2, "node2_keys", "", "the JSON file generated in the"+
"previous step ('preparekeys') command of node 2",
)
cc.cmd.Flags().Uint16Var(
cc.cmd.Flags().Uint32Var(
&cc.FeeRate, "feerate", defaultFeeSatPerVByte, "fee rate to "+
"use for the sweep transaction in sat/vByte",
)

@ -23,6 +23,7 @@ Complete documentation is available at https://github.com/guggero/chantools/.
* [chantools compactdb](chantools_compactdb.md) - Create a copy of a channel.db file in safe/read-only mode
* [chantools deletepayments](chantools_deletepayments.md) - Remove all (failed) payments from a channel DB
* [chantools derivekey](chantools_derivekey.md) - Derive a key with a specific derivation path
* [chantools doublespendinputs](chantools_doublespendinputs.md) - Tries to double spend the given inputs by deriving the private for the address and sweeping the funds to the given address. This can only be used with inputs that belong to an lnd wallet.
* [chantools dropchannelgraph](chantools_dropchannelgraph.md) - Remove all graph related data from a channel DB
* [chantools dumpbackup](chantools_dumpbackup.md) - Dump the content of a channel.backup file
* [chantools dumpchannels](chantools_dumpchannels.md) - Dump all channel information from an lnd channel database

@ -32,7 +32,7 @@ chantools closepoolaccount \
--apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api")
--auctioneerkey string the auctioneer's static public key (default "028e87bdd134238f8347f845d9ecc827b843d0d1e27cdcb46da704d916613f4fce")
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--feerate uint16 fee rate to use for the sweep transaction in sat/vByte (default 30)
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte (default 30)
-h, --help help for closepoolaccount
--maxnumaccounts uint32 the number of account indices to try at most (default 20)
--maxnumbatchkeys uint32 the number of batch keys to try at most (default 500)

@ -0,0 +1,43 @@
## chantools doublespendinputs
Tries to double spend the given inputs by deriving the private for the address and sweeping the funds to the given address. This can only be used with inputs that belong to an lnd wallet.
```
chantools doublespendinputs [flags]
```
### Examples
```
chantools doublespendinputs \
--inputoutpoints xxxxxxxxx:y,xxxxxxxxx:y \
--sweepaddr bc1q..... \
--feerate 10 \
--publish
```
### Options
```
--apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api")
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte (default 30)
-h, --help help for doublespendinputs
--inputoutpoints strings list of outpoints to double spend in the format txid:vout
--publish publish replacement TX to the chain API instead of just printing the TX
--recoverywindow uint32 number of keys to scan per internal/external branch; output will consist of double this amount of keys (default 2500)
--rootkey string BIP32 HD root key of the wallet to use for deriving the input keys; leave empty to prompt for lnd 24 word aezeed
--sweepaddr string address to sweep the funds to
```
### Options inherited from parent commands
```
-r, --regtest Indicates if regtest parameters should be used
-t, --testnet Indicates if testnet parameters should be used
```
### SEE ALSO
* [chantools](chantools.md) - Chantools helps recover funds from lightning channels

@ -23,7 +23,7 @@ chantools recoverloopin \
```
--apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api")
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--feerate uint16 fee rate to use for the sweep transaction in sat/vByte
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte
-h, --help help for recoverloopin
--loop_db_path string path to the loop database file
--num_tries int number of tries to try to find the correct key index (default 1000)

@ -44,7 +44,7 @@ chantools rescuefunding \
--channeldb string lnd channel.db file to rescue a channel from; must contain the pending channel specified with --channelpoint
--confirmedchannelpoint string channel outpoint that got confirmed on chain (<txid>:<txindex>); normally this is the same as the --dbchannelpoint so it will be set to that value ifthis is left empty
--dbchannelpoint string funding transaction outpoint of the channel to rescue (<txid>:<txindex>) as it is recorded in the DB
--feerate uint16 fee rate to use for the sweep transaction in sat/vByte (default 30)
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte (default 30)
-h, --help help for rescuefunding
--localkeyindex uint32 in case a channel DB is not available (but perhaps a channel backup file), the derivation index of the local multisig public key can be specified manually
--remotepubkey string in case a channel DB is not available (but perhaps a channel backup file), the remote multisig public key can be specified manually

@ -34,7 +34,7 @@ chantools sweepremoteclosed \
```
--apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api")
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--feerate uint16 fee rate to use for the sweep transaction in sat/vByte (default 30)
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte (default 30)
-h, --help help for sweepremoteclosed
--publish publish sweep TX to the chain API instead of just printing the TX
--recoverywindow uint32 number of keys to scan per derivation path (default 200)

@ -31,7 +31,7 @@ chantools sweeptimelock \
```
--apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api")
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--feerate uint16 fee rate to use for the sweep transaction in sat/vByte (default 30)
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte (default 30)
--fromchanneldb string channel input is in the format of an lnd channel.db file
--fromsummary string channel input is in the format of chantool's channel summary; specify '-' to read from stdin
-h, --help help for sweeptimelock

@ -36,7 +36,7 @@ chantools sweeptimelockmanual \
```
--apiurl string API URL to use (must be esplora compatible) (default "https://blockstream.info/api")
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--feerate uint16 fee rate to use for the sweep transaction in sat/vByte (default 30)
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte (default 30)
--fromchanneldb string channel input is in the format of an lnd channel.db file
--fromsummary string channel input is in the format of chantool's channel summary; specify '-' to read from stdin
-h, --help help for sweeptimelockmanual

@ -29,7 +29,7 @@ chantools zombierecovery makeoffer \
```
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--feerate uint16 fee rate to use for the sweep transaction in sat/vByte (default 30)
--feerate uint32 fee rate to use for the sweep transaction in sat/vByte (default 30)
-h, --help help for makeoffer
--node1_keys string the JSON file generated in theprevious step ('preparekeys') command of node 1
--node2_keys string the JSON file generated in theprevious step ('preparekeys') command of node 2

@ -13,6 +13,7 @@ import (
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/wallet"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
)
@ -27,8 +28,6 @@ type Signer struct {
func (s *Signer) SignOutputRaw(tx *wire.MsgTx,
signDesc *input.SignDescriptor) (input.Signature, error) {
witnessScript := signDesc.WitnessScript
// First attempt to fetch the private key which corresponds to the
// specified public key.
privKey, err := s.FetchPrivKey(&signDesc.KeyDesc)
@ -36,6 +35,14 @@ func (s *Signer) SignOutputRaw(tx *wire.MsgTx,
return nil, err
}
return s.SignOutputRawWithPrivkey(tx, signDesc, privKey)
}
func (s *Signer) SignOutputRawWithPrivkey(tx *wire.MsgTx,
signDesc *input.SignDescriptor,
privKey *secp256k1.PrivateKey) (input.Signature, error) {
witnessScript := signDesc.WitnessScript
privKey = maybeTweakPrivKey(signDesc, privKey)
sigHashes := txscript.NewTxSigHashes(tx, signDesc.PrevOutputFetcher)
@ -43,7 +50,11 @@ func (s *Signer) SignOutputRaw(tx *wire.MsgTx,
// Are we spending a script path or the key path? The API is
// slightly different, so we need to account for that to get the
// raw signature.
var rawSig []byte
var (
rawSig []byte
err error
)
switch signDesc.SignMethod {
case input.TaprootKeySpendBIP0086SignMethod,
input.TaprootKeySpendSignMethod:
@ -105,7 +116,6 @@ func (s *Signer) SignOutputRaw(tx *wire.MsgTx,
// Chop off the sighash flag at the end of the signature.
return ecdsa.ParseDERSignature(sig[:len(sig)-1])
}
func (s *Signer) ComputeInputScript(_ *wire.MsgTx, _ *input.SignDescriptor) (
*input.Script, error) {

Loading…
Cancel
Save