lnd/lnwallet/aux_signer.go
2024-12-04 13:19:00 -07:00

250 lines
8.3 KiB
Go

package lnwallet
import (
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/fn/v2"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
)
// htlcCustomSigType is the TLV type that is used to encode the custom HTLC
// signatures within the custom data for an existing HTLC.
var htlcCustomSigType tlv.TlvType65543
// AuxHtlcDescriptor is a struct that contains the information needed to sign or
// verify an HTLC for custom channels.
type AuxHtlcDescriptor struct {
// ChanID is the ChannelID of the LightningChannel that this
// paymentDescriptor belongs to. We track this here so we can
// reconstruct the Messages that this paymentDescriptor is built from.
ChanID lnwire.ChannelID
// RHash is the payment hash for this HTLC. The HTLC can be settled iff
// the preimage to this hash is presented.
RHash PaymentHash
// Timeout is the absolute timeout in blocks, after which this HTLC
// expires.
Timeout uint32
// Amount is the HTLC amount in milli-satoshis.
Amount lnwire.MilliSatoshi
// HtlcIndex is the index within the main update log for this HTLC.
// Entries within the log of type Add will have this field populated,
// as other entries will point to the entry via this counter.
//
// NOTE: This field will only be populated if EntryType is Add.
HtlcIndex uint64
// ParentIndex is the HTLC index of the entry that this update settles
// or times out.
//
// NOTE: This field will only be populated if EntryType is Fail or
// Settle.
ParentIndex uint64
// EntryType denotes the exact type of the paymentDescriptor. In the
// case of a Timeout, or Settle type, then the Parent field will point
// into the log to the HTLC being modified.
EntryType updateType
// CustomRecords also stores the set of optional custom records that
// may have been attached to a sent HTLC.
CustomRecords lnwire.CustomRecords
// addCommitHeight[Remote|Local] encodes the height of the commitment
// which included this HTLC on either the remote or local commitment
// chain. This value is used to determine when an HTLC is fully
// "locked-in".
addCommitHeightRemote uint64
addCommitHeightLocal uint64
// removeCommitHeight[Remote|Local] encodes the height of the
// commitment which removed the parent pointer of this
// paymentDescriptor either due to a timeout or a settle. Once both
// these heights are below the tail of both chains, the log entries can
// safely be removed.
removeCommitHeightRemote uint64
removeCommitHeightLocal uint64
}
// AddHeight returns the height at which the HTLC was added to the commitment
// chain. The height is returned based on the chain the HTLC is being added to
// (local or remote chain).
func (a *AuxHtlcDescriptor) AddHeight(
whoseCommitChain lntypes.ChannelParty) uint64 {
if whoseCommitChain.IsRemote() {
return a.addCommitHeightRemote
}
return a.addCommitHeightLocal
}
// RemoveHeight returns the height at which the HTLC was removed from the
// commitment chain. The height is returned based on the chain the HTLC is being
// removed from (local or remote chain).
func (a *AuxHtlcDescriptor) RemoveHeight(
whoseCommitChain lntypes.ChannelParty) uint64 {
if whoseCommitChain.IsRemote() {
return a.removeCommitHeightRemote
}
return a.removeCommitHeightLocal
}
// newAuxHtlcDescriptor creates a new AuxHtlcDescriptor from a payment
// descriptor.
func newAuxHtlcDescriptor(p *paymentDescriptor) AuxHtlcDescriptor {
return AuxHtlcDescriptor{
ChanID: p.ChanID,
RHash: p.RHash,
Timeout: p.Timeout,
Amount: p.Amount,
HtlcIndex: p.HtlcIndex,
ParentIndex: p.ParentIndex,
EntryType: p.EntryType,
CustomRecords: p.CustomRecords.Copy(),
addCommitHeightRemote: p.addCommitHeights.Remote,
addCommitHeightLocal: p.addCommitHeights.Local,
removeCommitHeightRemote: p.removeCommitHeights.Remote,
removeCommitHeightLocal: p.removeCommitHeights.Local,
}
}
// BaseAuxJob is a struct that contains the common fields that are shared among
// the aux sign/verify jobs.
type BaseAuxJob struct {
// OutputIndex is the output index of the HTLC on the commitment
// transaction being signed.
//
// NOTE: If the output is dust from the PoV of the commitment chain,
// then this value will be -1.
OutputIndex int32
// KeyRing is the commitment key ring that contains the keys needed to
// generate the second level HTLC signatures.
KeyRing CommitmentKeyRing
// HTLC is the HTLC that is being signed or verified.
HTLC AuxHtlcDescriptor
// Incoming is a boolean that indicates if the HTLC is incoming or
// outgoing.
Incoming bool
// CommitBlob is the commitment transaction blob that contains the aux
// information for this channel.
CommitBlob fn.Option[tlv.Blob]
// HtlcLeaf is the aux tap leaf that corresponds to the HTLC being
// signed/verified.
HtlcLeaf input.AuxTapLeaf
}
// AuxSigJob is a struct that contains all the information needed to sign an
// HTLC for custom channels.
type AuxSigJob struct {
// SignDesc is the sign desc for this HTLC.
SignDesc input.SignDescriptor
BaseAuxJob
// Resp is a channel that will be used to send the result of the sign
// job. This channel MUST be buffered.
Resp chan AuxSigJobResp
// Cancel is a channel that is closed by the caller if they wish to
// abandon all pending sign jobs part of a single batch. This should
// never be closed by the validator.
Cancel <-chan struct{}
}
// NewAuxSigJob creates a new AuxSigJob.
func NewAuxSigJob(sigJob SignJob, keyRing CommitmentKeyRing, incoming bool,
htlc AuxHtlcDescriptor, commitBlob fn.Option[tlv.Blob],
htlcLeaf input.AuxTapLeaf, cancelChan <-chan struct{}) AuxSigJob {
return AuxSigJob{
SignDesc: sigJob.SignDesc,
BaseAuxJob: BaseAuxJob{
OutputIndex: sigJob.OutputIndex,
KeyRing: keyRing,
HTLC: htlc,
Incoming: incoming,
CommitBlob: commitBlob,
HtlcLeaf: htlcLeaf,
},
Resp: make(chan AuxSigJobResp, 1),
Cancel: cancelChan,
}
}
// AuxSigJobResp is a struct that contains the result of a sign job.
type AuxSigJobResp struct {
// SigBlob is the signature blob that was generated for the HTLC. This
// is an opaque TLV field that may contain the signature and other data.
SigBlob fn.Option[tlv.Blob]
// HtlcIndex is the index of the HTLC that was signed.
HtlcIndex uint64
// Err is the error that occurred when executing the specified
// signature job. In the case that no error occurred, this value will
// be nil.
Err error
}
// AuxVerifyJob is a struct that contains all the information needed to verify
// an HTLC for custom channels.
type AuxVerifyJob struct {
// SigBlob is the signature blob that was generated for the HTLC. This
// is an opaque TLV field that may contain the signature and other data.
SigBlob fn.Option[tlv.Blob]
BaseAuxJob
}
// NewAuxVerifyJob creates a new AuxVerifyJob.
func NewAuxVerifyJob(sig fn.Option[tlv.Blob], keyRing CommitmentKeyRing,
incoming bool, htlc AuxHtlcDescriptor, commitBlob fn.Option[tlv.Blob],
htlcLeaf input.AuxTapLeaf) AuxVerifyJob {
return AuxVerifyJob{
SigBlob: sig,
BaseAuxJob: BaseAuxJob{
KeyRing: keyRing,
HTLC: htlc,
Incoming: incoming,
CommitBlob: commitBlob,
HtlcLeaf: htlcLeaf,
},
}
}
// AuxSigner is an interface that is used to sign and verify HTLCs for custom
// channels. It is similar to the existing SigPool, but uses opaque blobs to
// shuffle around signature information and other metadata.
type AuxSigner interface {
// SubmitSecondLevelSigBatch takes a batch of aux sign jobs and
// processes them asynchronously.
SubmitSecondLevelSigBatch(chanState AuxChanState, commitTx *wire.MsgTx,
sigJob []AuxSigJob) error
// PackSigs takes a series of aux signatures and packs them into a
// single blob that can be sent alongside the CommitSig messages.
PackSigs([]fn.Option[tlv.Blob]) fn.Result[fn.Option[tlv.Blob]]
// UnpackSigs takes a packed blob of signatures and returns the
// original signatures for each HTLC, keyed by HTLC index.
UnpackSigs(fn.Option[tlv.Blob]) fn.Result[[]fn.Option[tlv.Blob]]
// VerifySecondLevelSigs attempts to synchronously verify a batch of aux
// sig jobs.
VerifySecondLevelSigs(chanState AuxChanState, commitTx *wire.MsgTx,
verifyJob []AuxVerifyJob) error
}