mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
7feb8b21e1
In this commit, we update new Taproot related TLVs (nonces, partial sig, sig with nonce, etc). Along the way we were able to get rid of some boiler plate, but most importantly, we're able to better protect against API misuse (using a nonce that isn't initialized, etc) with the new options API. In some areas this introduces a bit of extra boiler plate, and where applicable I used some new helper functions to help cut down on the noise. Note to reviewers: this is done as a single commit, as changing the API breaks all callers, so if we want things to compile it needs to be in a wumbo commit.
338 lines
11 KiB
Go
338 lines
11 KiB
Go
package lnwire
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/lightningnetwork/lnd/tlv"
|
|
)
|
|
|
|
// FundingFlag represents the possible bit mask values for the ChannelFlags
|
|
// field within the OpenChannel struct.
|
|
type FundingFlag uint8
|
|
|
|
const (
|
|
// FFAnnounceChannel is a FundingFlag that when set, indicates the
|
|
// initiator of a funding flow wishes to announce the channel to the
|
|
// greater network.
|
|
FFAnnounceChannel FundingFlag = 1 << iota
|
|
)
|
|
|
|
// OpenChannel is the message Alice sends to Bob if we should like to create a
|
|
// channel with Bob where she's the sole provider of funds to the channel.
|
|
// Single funder channels simplify the initial funding workflow, are supported
|
|
// by nodes backed by SPV Bitcoin clients, and have a simpler security models
|
|
// than dual funded channels.
|
|
type OpenChannel struct {
|
|
// ChainHash is the target chain that the initiator wishes to open a
|
|
// channel within.
|
|
ChainHash chainhash.Hash
|
|
|
|
// PendingChannelID serves to uniquely identify the future channel
|
|
// created by the initiated single funder workflow.
|
|
PendingChannelID [32]byte
|
|
|
|
// FundingAmount is the amount of satoshis that the initiator of the
|
|
// channel wishes to use as the total capacity of the channel. The
|
|
// initial balance of the funding will be this value minus the push
|
|
// amount (if set).
|
|
FundingAmount btcutil.Amount
|
|
|
|
// PushAmount is the value that the initiating party wishes to "push"
|
|
// to the responding as part of the first commitment state. If the
|
|
// responder accepts, then this will be their initial balance.
|
|
PushAmount MilliSatoshi
|
|
|
|
// DustLimit is the specific dust limit the sender of this message
|
|
// would like enforced on their version of the commitment transaction.
|
|
// Any output below this value will be "trimmed" from the commitment
|
|
// transaction, with the amount of the HTLC going to dust.
|
|
DustLimit btcutil.Amount
|
|
|
|
// MaxValueInFlight represents the maximum amount of coins that can be
|
|
// pending within the channel at any given time. If the amount of funds
|
|
// in limbo exceeds this amount, then the channel will be failed.
|
|
MaxValueInFlight MilliSatoshi
|
|
|
|
// ChannelReserve is the amount of BTC that the receiving party MUST
|
|
// maintain a balance above at all times. This is a safety mechanism to
|
|
// ensure that both sides always have skin in the game during the
|
|
// channel's lifetime.
|
|
ChannelReserve btcutil.Amount
|
|
|
|
// HtlcMinimum is the smallest HTLC that the sender of this message
|
|
// will accept.
|
|
HtlcMinimum MilliSatoshi
|
|
|
|
// FeePerKiloWeight is the initial fee rate that the initiator suggests
|
|
// for both commitment transaction. This value is expressed in sat per
|
|
// kilo-weight.
|
|
//
|
|
// TODO(halseth): make SatPerKWeight when fee estimation is in own
|
|
// package. Currently this will cause an import cycle.
|
|
FeePerKiloWeight uint32
|
|
|
|
// CsvDelay is the number of blocks to use for the relative time lock
|
|
// in the pay-to-self output of both commitment transactions.
|
|
CsvDelay uint16
|
|
|
|
// MaxAcceptedHTLCs is the total number of incoming HTLC's that the
|
|
// sender of this channel will accept.
|
|
MaxAcceptedHTLCs uint16
|
|
|
|
// FundingKey is the key that should be used on behalf of the sender
|
|
// within the 2-of-2 multi-sig output that it contained within the
|
|
// funding transaction.
|
|
FundingKey *btcec.PublicKey
|
|
|
|
// RevocationPoint is the base revocation point for the sending party.
|
|
// Any commitment transaction belonging to the receiver of this message
|
|
// should use this key and their per-commitment point to derive the
|
|
// revocation key for the commitment transaction.
|
|
RevocationPoint *btcec.PublicKey
|
|
|
|
// PaymentPoint is the base payment point for the sending party. This
|
|
// key should be combined with the per commitment point for a
|
|
// particular commitment state in order to create the key that should
|
|
// be used in any output that pays directly to the sending party, and
|
|
// also within the HTLC covenant transactions.
|
|
PaymentPoint *btcec.PublicKey
|
|
|
|
// DelayedPaymentPoint is the delay point for the sending party. This
|
|
// key should be combined with the per commitment point to derive the
|
|
// keys that are used in outputs of the sender's commitment transaction
|
|
// where they claim funds.
|
|
DelayedPaymentPoint *btcec.PublicKey
|
|
|
|
// HtlcPoint is the base point used to derive the set of keys for this
|
|
// party that will be used within the HTLC public key scripts. This
|
|
// value is combined with the receiver's revocation base point in order
|
|
// to derive the keys that are used within HTLC scripts.
|
|
HtlcPoint *btcec.PublicKey
|
|
|
|
// FirstCommitmentPoint is the first commitment point for the sending
|
|
// party. This value should be combined with the receiver's revocation
|
|
// base point in order to derive the revocation keys that are placed
|
|
// within the commitment transaction of the sender.
|
|
FirstCommitmentPoint *btcec.PublicKey
|
|
|
|
// ChannelFlags is a bit-field which allows the initiator of the
|
|
// channel to specify further behavior surrounding the channel.
|
|
// Currently, the least significant bit of this bit field indicates the
|
|
// initiator of the channel wishes to advertise this channel publicly.
|
|
ChannelFlags FundingFlag
|
|
|
|
// UpfrontShutdownScript is the script to which the channel funds should
|
|
// be paid when mutually closing the channel. This field is optional, and
|
|
// and has a length prefix, so a zero will be written if it is not set
|
|
// and its length followed by the script will be written if it is set.
|
|
UpfrontShutdownScript DeliveryAddress
|
|
|
|
// ChannelType is the explicit channel type the initiator wishes to
|
|
// open.
|
|
ChannelType *ChannelType
|
|
|
|
// LeaseExpiry represents the absolute expiration height of a channel
|
|
// lease. This is a custom TLV record that will only apply when a leased
|
|
// channel is being opened using the script enforced lease commitment
|
|
// type.
|
|
LeaseExpiry *LeaseExpiry
|
|
|
|
// LocalNonce is an optional field that transmits the
|
|
// local/verification nonce for a party. This nonce will be used to
|
|
// verify the very first commitment transaction signature. This will
|
|
// only be populated if the simple taproot channels type was
|
|
// negotiated.
|
|
LocalNonce OptMusig2NonceTLV
|
|
|
|
// ExtraData is the set of data that was appended to this message to
|
|
// fill out the full maximum transport message size. These fields can
|
|
// be used to specify optional data such as custom TLV fields.
|
|
//
|
|
// NOTE: Since the upfront shutdown script MUST be present (though can
|
|
// be zero-length) if any TLV data is available, the script will be
|
|
// extracted and removed from this blob when decoding. ExtraData will
|
|
// contain all TLV records _except_ the DeliveryAddress record in that
|
|
// case.
|
|
ExtraData ExtraOpaqueData
|
|
}
|
|
|
|
// A compile time check to ensure OpenChannel implements the lnwire.Message
|
|
// interface.
|
|
var _ Message = (*OpenChannel)(nil)
|
|
|
|
// Encode serializes the target OpenChannel into the passed io.Writer
|
|
// implementation. Serialization will observe the rules defined by the passed
|
|
// protocol version.
|
|
func (o *OpenChannel) Encode(w *bytes.Buffer, pver uint32) error {
|
|
recordProducers := []tlv.RecordProducer{&o.UpfrontShutdownScript}
|
|
if o.ChannelType != nil {
|
|
recordProducers = append(recordProducers, o.ChannelType)
|
|
}
|
|
if o.LeaseExpiry != nil {
|
|
recordProducers = append(recordProducers, o.LeaseExpiry)
|
|
}
|
|
o.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
|
|
recordProducers = append(recordProducers, &localNonce)
|
|
})
|
|
err := EncodeMessageExtraData(&o.ExtraData, recordProducers...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteBytes(w, o.ChainHash[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteBytes(w, o.PendingChannelID[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteSatoshi(w, o.FundingAmount); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteMilliSatoshi(w, o.PushAmount); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteSatoshi(w, o.DustLimit); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteMilliSatoshi(w, o.MaxValueInFlight); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteSatoshi(w, o.ChannelReserve); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteMilliSatoshi(w, o.HtlcMinimum); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteUint32(w, o.FeePerKiloWeight); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteUint16(w, o.CsvDelay); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteUint16(w, o.MaxAcceptedHTLCs); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WritePublicKey(w, o.FundingKey); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WritePublicKey(w, o.RevocationPoint); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WritePublicKey(w, o.PaymentPoint); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WritePublicKey(w, o.DelayedPaymentPoint); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WritePublicKey(w, o.HtlcPoint); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WritePublicKey(w, o.FirstCommitmentPoint); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteFundingFlag(w, o.ChannelFlags); err != nil {
|
|
return err
|
|
}
|
|
|
|
return WriteBytes(w, o.ExtraData)
|
|
}
|
|
|
|
// Decode deserializes the serialized OpenChannel stored in the passed
|
|
// io.Reader into the target OpenChannel using the deserialization rules
|
|
// defined by the passed protocol version.
|
|
//
|
|
// This is part of the lnwire.Message interface.
|
|
func (o *OpenChannel) Decode(r io.Reader, pver uint32) error {
|
|
// Read all the mandatory fields in the open message.
|
|
err := ReadElements(r,
|
|
o.ChainHash[:],
|
|
o.PendingChannelID[:],
|
|
&o.FundingAmount,
|
|
&o.PushAmount,
|
|
&o.DustLimit,
|
|
&o.MaxValueInFlight,
|
|
&o.ChannelReserve,
|
|
&o.HtlcMinimum,
|
|
&o.FeePerKiloWeight,
|
|
&o.CsvDelay,
|
|
&o.MaxAcceptedHTLCs,
|
|
&o.FundingKey,
|
|
&o.RevocationPoint,
|
|
&o.PaymentPoint,
|
|
&o.DelayedPaymentPoint,
|
|
&o.HtlcPoint,
|
|
&o.FirstCommitmentPoint,
|
|
&o.ChannelFlags,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// For backwards compatibility, the optional extra data blob for
|
|
// OpenChannel must contain an entry for the upfront shutdown script.
|
|
// We'll read it out and attempt to parse it.
|
|
var tlvRecords ExtraOpaqueData
|
|
if err := ReadElements(r, &tlvRecords); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Next we'll parse out the set of known records, keeping the raw tlv
|
|
// bytes untouched to ensure we don't drop any bytes erroneously.
|
|
var (
|
|
chanType ChannelType
|
|
leaseExpiry LeaseExpiry
|
|
localNonce = o.LocalNonce.Zero()
|
|
)
|
|
typeMap, err := tlvRecords.ExtractRecords(
|
|
&o.UpfrontShutdownScript, &chanType, &leaseExpiry,
|
|
&localNonce,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set the corresponding TLV types if they were included in the stream.
|
|
if val, ok := typeMap[ChannelTypeRecordType]; ok && val == nil {
|
|
o.ChannelType = &chanType
|
|
}
|
|
if val, ok := typeMap[LeaseExpiryRecordType]; ok && val == nil {
|
|
o.LeaseExpiry = &leaseExpiry
|
|
}
|
|
if val, ok := typeMap[o.LocalNonce.TlvType()]; ok && val == nil {
|
|
o.LocalNonce = tlv.SomeRecordT(localNonce)
|
|
}
|
|
|
|
o.ExtraData = tlvRecords
|
|
|
|
return nil
|
|
}
|
|
|
|
// MsgType returns the MessageType code which uniquely identifies this message
|
|
// as an OpenChannel on the wire.
|
|
//
|
|
// This is part of the lnwire.Message interface.
|
|
func (o *OpenChannel) MsgType() MessageType {
|
|
return MsgOpenChannel
|
|
}
|