mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
lnwallet: factor out func GetSignedCommitTx
This pure function creates signed commit transaction, using various inputs passed as struct TaprootSignedCommitTxInputs and a signer. This is needed to be able to store the inputs without a signature in SCB and sign the transaction in chantools scbforceclose. See https://github.com/lightningnetwork/lnd/pull/8183/files#r1423959791
This commit is contained in:
parent
e7776a4c1e
commit
90c45ddd8f
@ -6433,29 +6433,84 @@ func (lc *LightningChannel) AbsoluteThawHeight() (uint32, error) {
|
||||
return lc.channelState.AbsoluteThawHeight()
|
||||
}
|
||||
|
||||
// getSignedCommitTx function take the latest commitment transaction and
|
||||
// populate it with witness data.
|
||||
func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
|
||||
// Fetch the current commitment transaction, along with their signature
|
||||
// for the transaction.
|
||||
localCommit := lc.channelState.LocalCommitment
|
||||
commitTx := localCommit.CommitTx.Copy()
|
||||
// SignedCommitTxInputs contains data needed to create a signed commit
|
||||
// transaction using a signer. See GetSignedCommitTx.
|
||||
type SignedCommitTxInputs struct {
|
||||
// CommitTx is the latest version of the commitment state, broadcast
|
||||
// able by us.
|
||||
CommitTx *wire.MsgTx
|
||||
|
||||
ourKey := lc.channelState.LocalChanCfg.MultiSigKey
|
||||
theirKey := lc.channelState.RemoteChanCfg.MultiSigKey
|
||||
// CommitSig is one half of the signature required to fully complete
|
||||
// the script for the commitment transaction above. This is the
|
||||
// signature signed by the remote party for our version of the
|
||||
// commitment transactions.
|
||||
CommitSig []byte
|
||||
|
||||
// OurKey is our key to be used within the 2-of-2 output script
|
||||
// for the owner of this channel.
|
||||
OurKey keychain.KeyDescriptor
|
||||
|
||||
// TheirKey is their key to be used within the 2-of-2 output script
|
||||
// for the owner of this channel.
|
||||
TheirKey keychain.KeyDescriptor
|
||||
|
||||
// SignDesc is the primary sign descriptor that is capable of signing
|
||||
// the commitment transaction that spends the multi-sig output.
|
||||
SignDesc *input.SignDescriptor
|
||||
|
||||
// Taproot holds fields needed in case of a taproot channel.
|
||||
// Iff the channel is of taproot type, this field is filled.
|
||||
Taproot fn.Option[TaprootSignedCommitTxInputs]
|
||||
}
|
||||
|
||||
// TaprootSignedCommitTxInputs contains additional data needed to create a
|
||||
// signed commit transaction using a signer, used in case of a taproot channel.
|
||||
// See GetSignedCommitTx.
|
||||
type TaprootSignedCommitTxInputs struct {
|
||||
// CommitHeight is the update number that this channel state represents.
|
||||
// It is the total number of commitment updates up to this point. This
|
||||
// can be viewed as sort of a "commitment height" as this number is
|
||||
// monotonically increasing. This number is used to make a signature
|
||||
// for a taproot channel, since it is used by shachain nonce producer
|
||||
// (TaprootNonceProducer).
|
||||
CommitHeight uint64
|
||||
|
||||
// TaprootNonceProducer is used to generate a shachain tree for the
|
||||
// purpose of generating verification nonces for taproot channels.
|
||||
TaprootNonceProducer shachain.Producer
|
||||
|
||||
// TapscriptRoot is the root of the tapscript tree that will be used to
|
||||
// create the funding output. This is an optional field that should
|
||||
// only be set for taproot channels.
|
||||
TapscriptRoot fn.Option[chainhash.Hash]
|
||||
}
|
||||
|
||||
// GetSignedCommitTx creates the witness stack of a channel commitment
|
||||
// transaction. It can handle all commitment types (taproot, legacy). It is
|
||||
// exported to give outside tooling the possibility to recreate the witness.
|
||||
// A key use case is generating the witness data for a commitment transaction
|
||||
// from a Static Channel Backup (SCB).
|
||||
func GetSignedCommitTx(inputs SignedCommitTxInputs,
|
||||
signer input.Signer) (*wire.MsgTx, error) {
|
||||
|
||||
commitTx := inputs.CommitTx.Copy()
|
||||
|
||||
var witness wire.TxWitness
|
||||
switch {
|
||||
// If this is a taproot channel, then we'll need to re-derive the nonce
|
||||
// we need to generate a new signature
|
||||
case lc.channelState.ChanType.IsTaproot():
|
||||
case inputs.Taproot.IsSome():
|
||||
// Extract Taproot from fn.Option. It is safe to call
|
||||
// UnsafeFromSome because we just checked that it is some.
|
||||
taproot := inputs.Taproot.UnsafeFromSome()
|
||||
|
||||
// First, we'll need to re-derive the local nonce we sent to
|
||||
// the remote party to create this musig session. We pass in
|
||||
// the same height here as we're generating the nonce needed
|
||||
// for the _current_ state.
|
||||
localNonce, err := channeldb.NewMusigVerificationNonce(
|
||||
ourKey.PubKey, lc.currentHeight,
|
||||
lc.taprootNonceProducer,
|
||||
inputs.OurKey.PubKey, taproot.CommitHeight,
|
||||
taproot.TaprootNonceProducer,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to re-derive "+
|
||||
@ -6463,19 +6518,20 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
|
||||
}
|
||||
|
||||
tapscriptTweak := fn.MapOption(TapscriptRootToTweak)(
|
||||
lc.channelState.TapscriptRoot,
|
||||
taproot.TapscriptRoot,
|
||||
)
|
||||
|
||||
// Now that we have the local nonce, we'll re-create the musig
|
||||
// session we had for this height.
|
||||
musigSession := NewPartialMusigSession(
|
||||
*localNonce, ourKey, theirKey, lc.Signer,
|
||||
&lc.fundingOutput, LocalMusigCommit, tapscriptTweak,
|
||||
*localNonce, inputs.OurKey, inputs.TheirKey, signer,
|
||||
inputs.SignDesc.Output, LocalMusigCommit,
|
||||
tapscriptTweak,
|
||||
)
|
||||
|
||||
var remoteSig lnwire.PartialSigWithNonce
|
||||
err = remoteSig.Decode(
|
||||
bytes.NewReader(localCommit.CommitSig),
|
||||
bytes.NewReader(inputs.CommitSig),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to decode remote "+
|
||||
@ -6521,15 +6577,15 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
|
||||
// Otherwise, the final witness we generate will be a normal p2wsh
|
||||
// multi-sig spend.
|
||||
default:
|
||||
theirSig, err := ecdsa.ParseDERSignature(localCommit.CommitSig)
|
||||
theirSig, err := ecdsa.ParseDERSignature(inputs.CommitSig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// With this, we then generate the full witness so the caller
|
||||
// can broadcast a fully signed transaction.
|
||||
lc.signDesc.SigHashes = input.NewTxSigHashesV0Only(commitTx)
|
||||
ourSig, err := lc.Signer.SignOutputRaw(commitTx, lc.signDesc)
|
||||
inputs.SignDesc.SigHashes = input.NewTxSigHashesV0Only(commitTx)
|
||||
ourSig, err := signer.SignOutputRaw(commitTx, inputs.SignDesc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -6537,9 +6593,9 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
|
||||
// With the final signature generated, create the witness stack
|
||||
// required to spend from the multi-sig output.
|
||||
witness = input.SpendMultiSig(
|
||||
lc.signDesc.WitnessScript,
|
||||
ourKey.PubKey.SerializeCompressed(), ourSig,
|
||||
theirKey.PubKey.SerializeCompressed(), theirSig,
|
||||
inputs.SignDesc.WitnessScript,
|
||||
inputs.OurKey.PubKey.SerializeCompressed(), ourSig,
|
||||
inputs.TheirKey.PubKey.SerializeCompressed(), theirSig,
|
||||
)
|
||||
}
|
||||
|
||||
@ -6548,6 +6604,32 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
|
||||
return commitTx, nil
|
||||
}
|
||||
|
||||
// getSignedCommitTx method takes the latest commitment transaction and
|
||||
// populates it with witness data.
|
||||
func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
|
||||
// Fetch the current commitment transaction, along with their signature
|
||||
// for the transaction.
|
||||
localCommit := lc.channelState.LocalCommitment
|
||||
|
||||
inputs := SignedCommitTxInputs{
|
||||
CommitTx: localCommit.CommitTx,
|
||||
CommitSig: localCommit.CommitSig,
|
||||
OurKey: lc.channelState.LocalChanCfg.MultiSigKey,
|
||||
TheirKey: lc.channelState.RemoteChanCfg.MultiSigKey,
|
||||
SignDesc: lc.signDesc,
|
||||
}
|
||||
|
||||
if lc.channelState.ChanType.IsTaproot() {
|
||||
inputs.Taproot = fn.Some(TaprootSignedCommitTxInputs{
|
||||
CommitHeight: lc.currentHeight,
|
||||
TaprootNonceProducer: lc.taprootNonceProducer,
|
||||
TapscriptRoot: lc.channelState.TapscriptRoot,
|
||||
})
|
||||
}
|
||||
|
||||
return GetSignedCommitTx(inputs, lc.Signer)
|
||||
}
|
||||
|
||||
// CommitOutputResolution carries the necessary information required to allow
|
||||
// us to sweep our commitment output in the case that either party goes to
|
||||
// chain.
|
||||
|
Loading…
Reference in New Issue
Block a user