2020-03-30 16:14:04 +00:00
|
|
|
package lnd
|
2020-01-04 22:10:26 +00:00
|
|
|
|
|
|
|
import (
|
2020-08-26 21:14:38 +00:00
|
|
|
"fmt"
|
2020-12-14 22:30:18 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
2022-07-18 06:52:40 +00:00
|
|
|
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
2020-08-26 21:14:38 +00:00
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
2020-01-04 22:10:26 +00:00
|
|
|
"github.com/btcsuite/btcd/txscript"
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
|
|
|
"github.com/lightningnetwork/lnd/input"
|
|
|
|
)
|
|
|
|
|
|
|
|
type LightningChannel struct {
|
|
|
|
LocalChanCfg channeldb.ChannelConfig
|
|
|
|
RemoteChanCfg channeldb.ChannelConfig
|
|
|
|
SignDesc *input.SignDescriptor
|
|
|
|
ChannelState *channeldb.OpenChannel
|
|
|
|
TXSigner *Signer
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateSignDesc derives the SignDescriptor for commitment transactions from
|
|
|
|
// other fields on the LightningChannel.
|
|
|
|
func (lc *LightningChannel) CreateSignDesc() error {
|
|
|
|
localKey := lc.LocalChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
|
|
|
remoteKey := lc.RemoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
|
|
|
|
|
|
|
multiSigScript, err := input.GenMultiSigScript(localKey, remoteKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fundingPkScript, err := input.WitnessScriptHash(multiSigScript)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
lc.SignDesc = &input.SignDescriptor{
|
|
|
|
KeyDesc: lc.LocalChanCfg.MultiSigKey,
|
|
|
|
WitnessScript: multiSigScript,
|
|
|
|
Output: &wire.TxOut{
|
|
|
|
PkScript: fundingPkScript,
|
|
|
|
Value: int64(lc.ChannelState.Capacity),
|
|
|
|
},
|
|
|
|
HashType: txscript.SigHashAll,
|
|
|
|
InputIndex: 0,
|
2023-04-20 09:30:05 +00:00
|
|
|
PrevOutputFetcher: txscript.NewCannedPrevOutputFetcher(
|
|
|
|
fundingPkScript, int64(lc.ChannelState.Capacity),
|
|
|
|
),
|
2020-01-04 22:10:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignedCommitTx function take the latest commitment transaction and populate
|
|
|
|
// it with witness data.
|
|
|
|
func (lc *LightningChannel) SignedCommitTx() (*wire.MsgTx, error) {
|
|
|
|
// Fetch the current commitment transaction, along with their signature
|
|
|
|
// for the transaction.
|
|
|
|
localCommit := lc.ChannelState.LocalCommitment
|
|
|
|
commitTx := localCommit.CommitTx.Copy()
|
2022-07-18 06:52:40 +00:00
|
|
|
theirSig, err := ecdsa.ParseDERSignature(localCommit.CommitSig)
|
2020-12-14 22:30:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-04 22:10:26 +00:00
|
|
|
|
|
|
|
// With this, we then generate the full witness so the caller can
|
|
|
|
// broadcast a fully signed transaction.
|
2020-12-14 22:30:18 +00:00
|
|
|
ourSig, err := lc.TXSigner.SignOutputRaw(commitTx, lc.SignDesc)
|
2020-01-04 22:10:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// With the final signature generated, create the witness stack
|
|
|
|
// required to spend from the multi-sig output.
|
|
|
|
ourKey := lc.LocalChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
|
|
|
theirKey := lc.RemoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
|
|
|
|
|
|
|
commitTx.TxIn[0].Witness = input.SpendMultiSig(
|
|
|
|
lc.SignDesc.WitnessScript, ourKey,
|
|
|
|
ourSig, theirKey, theirSig,
|
|
|
|
)
|
|
|
|
|
|
|
|
return commitTx, nil
|
|
|
|
}
|
2020-08-26 21:14:38 +00:00
|
|
|
|
|
|
|
// ParseOutpoint parses a transaction outpoint in the format <txid>:<idx> into
|
|
|
|
// the wire format.
|
|
|
|
func ParseOutpoint(s string) (*wire.OutPoint, error) {
|
|
|
|
split := strings.Split(s, ":")
|
|
|
|
if len(split) != 2 {
|
|
|
|
return nil, fmt.Errorf("expecting channel point to be in " +
|
|
|
|
"format of: txid:index")
|
|
|
|
}
|
|
|
|
|
|
|
|
index, err := strconv.ParseInt(split[1], 10, 32)
|
|
|
|
if err != nil {
|
2022-07-18 07:50:27 +00:00
|
|
|
return nil, fmt.Errorf("unable to decode output index: %w",
|
2020-08-26 21:14:38 +00:00
|
|
|
err)
|
|
|
|
}
|
|
|
|
|
|
|
|
txid, err := chainhash.NewHashFromStr(split[0])
|
|
|
|
if err != nil {
|
2022-07-18 07:50:27 +00:00
|
|
|
return nil, fmt.Errorf("unable to parse hex string: %w", err)
|
2020-08-26 21:14:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &wire.OutPoint{
|
|
|
|
Hash: *txid,
|
|
|
|
Index: uint32(index),
|
|
|
|
}, nil
|
|
|
|
}
|