From 7f36b70a4acc01bfbe055fa13a4f53a15899d7df Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 28 Jul 2017 16:24:34 -0700 Subject: [PATCH] lnwire: add new single funder messages from specification This commit adds the new set of single funder messages from the specification. As a result, after this commit and a follow up, all of our messages will directly line up with those that are detailed within the specification. The new set of funding messages are very similar to our prior ones, aside from the main difference of the addition of several channel level constraints that give nodes control over their exposure, throughput, and other values. --- lnwire/accept_channel.go | 154 +++++++++++++++++++++++++++++++ lnwire/funding_created.go | 67 ++++++++++++++ lnwire/funding_signed.go | 59 ++++++++++++ lnwire/open_channel.go | 184 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 464 insertions(+) create mode 100644 lnwire/accept_channel.go create mode 100644 lnwire/funding_created.go create mode 100644 lnwire/funding_signed.go create mode 100644 lnwire/open_channel.go diff --git a/lnwire/accept_channel.go b/lnwire/accept_channel.go new file mode 100644 index 00000000..3cd0e1fb --- /dev/null +++ b/lnwire/accept_channel.go @@ -0,0 +1,154 @@ +package lnwire + +import ( + "io" + + "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcutil" +) + +// AcceptChannel is the message Bob sends to Alice after she initiates the +// single funder channel workflow via a AcceptChannel message. Once Alice +// receives Bob's response, then she has all the items necessary to construct +// the funding transaction, and both commitment transactions. +type AcceptChannel struct { + // PendingChannelID serves to uniquely identify the future channel + // created by the initiated single funder workflow. + PendingChannelID [32]byte + + // 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. + // + // TODO(roasbeef): is msat + MaxValueInFlight btcutil.Amount + + // 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 + + // MinAcceptDepth is the minimum depth that the initiator of the + // channel should wait before considering the channel open. + MinAcceptDepth uint32 + + // HtlcMinimum is the smallest HTLC that the sender of this message + // will accept. + // + // TODO(roasbeef): is msat + HtlcMinimum 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. + // + // TODO(roasbeef): acks the initiator's, same with max in flight? + 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 + + // 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 +} + +// A compile time check to ensure AcceptChannel implements the lnwire.Message +// interface. +var _ Message = (*AcceptChannel)(nil) + +// Encode serializes the target AcceptChannel into the passed io.Writer +// implementation. Serialization will observe the rules defined by the passed +// protocol version. +// +// This is part of the lnwire.Message interface. +func (a *AcceptChannel) Encode(w io.Writer, pver uint32) error { + return writeElements(w, + a.PendingChannelID[:], + a.DustLimit, + a.MaxValueInFlight, + a.ChannelReserve, + a.MinAcceptDepth, + a.HtlcMinimum, + a.CsvDelay, + a.MaxAcceptedHTLCs, + a.FundingKey, + a.RevocationPoint, + a.PaymentPoint, + a.DelayedPaymentPoint, + a.FirstCommitmentPoint, + ) +} + +// Decode deserializes the serialized AcceptChannel stored in the passed +// io.Reader into the target AcceptChannel using the deserialization rules +// defined by the passed protocol version. +// +// This is part of the lnwire.Message interface. +func (a *AcceptChannel) Decode(r io.Reader, pver uint32) error { + return readElements(r, + a.PendingChannelID[:], + &a.DustLimit, + &a.MaxValueInFlight, + &a.ChannelReserve, + &a.MinAcceptDepth, + &a.HtlcMinimum, + &a.CsvDelay, + &a.MaxAcceptedHTLCs, + &a.FundingKey, + &a.RevocationPoint, + &a.PaymentPoint, + &a.DelayedPaymentPoint, + &a.FirstCommitmentPoint, + ) +} + +// MsgType returns the MessageType code which uniquely identifies this message +// as a AcceptChannel on the wire. +// +// This is part of the lnwire.Message interface. +func (a *AcceptChannel) MsgType() MessageType { + return MsgAcceptChannel +} + +// MaxPayloadLength returns the maximum allowed payload length for a +// AcceptChannel message. +// +// This is part of the lnwire.Message interface. +func (a *AcceptChannel) MaxPayloadLength(uint32) uint32 { + // 32 + (8 * 3) + (4 * 2) + (2 * 2) + (33 * 5) + return 233 +} diff --git a/lnwire/funding_created.go b/lnwire/funding_created.go new file mode 100644 index 00000000..b9481ebf --- /dev/null +++ b/lnwire/funding_created.go @@ -0,0 +1,67 @@ +package lnwire + +import ( + "io" + + "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcd/wire" +) + +// FundingCreated is sent from Alice (the initiator) to Bob (the responder), +// once Alice receives Bob's contributions as well as his channel constraints. +// Once bob receives this message, he'll gain access to an immediately +// broadcastable commitment transaction and will reply with a signature for +// Alice's version of the commitment transaction. +type FundingCreated struct { + // PendingChannelID serves to uniquely identify the future channel + // created by the initiated single funder workflow. + PendingChannelID [32]byte + + // FundingPoint is the outpoint of the funding transaction created by + // Alice. With this, Bob is able to generate both his version and + // Alice's version of the commitment transaction. + FundingPoint wire.OutPoint + + // CommitSig is Alice's signature from Bob's version of the commitment + // transaction. + CommitSig *btcec.Signature +} + +// A compile time check to ensure FundingCreated implements the lnwire.Message +// interface. +var _ Message = (*FundingCreated)(nil) + +// Encode serializes the target FundingCreated into the passed io.Writer +// implementation. Serialization will observe the rules defined by the passed +// protocol version. +// +// This is part of the lnwire.Message interface. +func (f *FundingCreated) Encode(w io.Writer, pver uint32) error { + return writeElements(w, f.PendingChannelID[:], f.FundingPoint, f.CommitSig) +} + +// Decode deserializes the serialized FundingCreated stored in the passed +// io.Reader into the target FundingCreated using the deserialization rules +// defined by the passed protocol version. +// +// This is part of the lnwire.Message interface. +func (f *FundingCreated) Decode(r io.Reader, pver uint32) error { + return readElements(r, f.PendingChannelID[:], &f.FundingPoint, &f.CommitSig) +} + +// MsgType returns the uint32 code which uniquely identifies this message as a +// FundingCreated on the wire. +// +// This is part of the lnwire.Message interface. +func (f *FundingCreated) MsgType() MessageType { + return MsgFundingCreated +} + +// MaxPayloadLength returns the maximum allowed payload length for a +// FundingCreated message. +// +// This is part of the lnwire.Message interface. +func (f *FundingCreated) MaxPayloadLength(uint32) uint32 { + // 32 + 32 + 2 + 64 + return 130 +} diff --git a/lnwire/funding_signed.go b/lnwire/funding_signed.go new file mode 100644 index 00000000..7e795986 --- /dev/null +++ b/lnwire/funding_signed.go @@ -0,0 +1,59 @@ +package lnwire + +import ( + "io" + + "github.com/roasbeef/btcd/btcec" +) + +// FundingSigned is sent from Bob (the responder) to Alice (the initiator) +// after receiving the funding outpoint and her signature for Bob's version of +// the commitment transaction. +type FundingSigned struct { + // ChannelPoint is the particular active channel that this + // FundingSigned is bound to. + ChanID ChannelID + + // CommitSig is Bob's signature for Alice's version of the commitment + // transaction. + CommitSig *btcec.Signature +} + +// A compile time check to ensure FundingSigned implements the lnwire.Message +// interface. +var _ Message = (*FundingSigned)(nil) + +// Encode serializes the target FundingSigned into the passed io.Writer +// implementation. Serialization will observe the rules defined by the passed +// protocol version. +// +// This is part of the lnwire.Message interface. +func (f *FundingSigned) Encode(w io.Writer, pver uint32) error { + return writeElements(w, f.ChanID, f.CommitSig) +} + +// Decode deserializes the serialized FundingSigned stored in the passed +// io.Reader into the target FundingSigned using the deserialization rules +// defined by the passed protocol version. +// +// This is part of the lnwire.Message interface. +func (f *FundingSigned) Decode(r io.Reader, pver uint32) error { + return readElements(r, &f.ChanID, &f.CommitSig) +} + +// MsgType returns the uint32 code which uniquely identifies this message as a +// FundingSigned on the wire. +// +// This is part of the lnwire.Message interface. +func (f *FundingSigned) MsgType() MessageType { + return MsgFundingSigned +} + +// MaxPayloadLength returns the maximum allowed payload length for a +// FundingSigned message. +// +// This is part of the lnwire.Message interface. +func (f *FundingSigned) MaxPayloadLength(uint32) uint32 { + // 32 + 64 + return 96 +} diff --git a/lnwire/open_channel.go b/lnwire/open_channel.go new file mode 100644 index 00000000..74e1ac29 --- /dev/null +++ b/lnwire/open_channel.go @@ -0,0 +1,184 @@ +package lnwire + +import ( + "io" + + "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcd/chaincfg/chainhash" + "github.com/roasbeef/btcutil" +) + +// 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. + // + // TODO(roasbeef): is msat + PushAmount btcutil.Amount + + // 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 btcutil.Amount + + // 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. + // + // TODO(roasbeef): is msat + HtlcMinimum uint32 + + // FeePerKiloWeight is the initial fee rate that the initiator suggests + // for both commitment transaction. This value is expressed in sat per + // kilo-weight. + 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 + + // 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 byte +} + +// 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. +// +// This is part of the lnwire.Message interface. +func (o *OpenChannel) Encode(w io.Writer, pver uint32) error { + return writeElements(w, + 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.FirstCommitmentPoint, + o.ChannelFlags, + ) +} + +// 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 { + return 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.FirstCommitmentPoint, + &o.ChannelFlags, + ) +} + +// MsgType returns the MessageType code which uniquely identifies this message +// as a OpenChannel on the wire. +// +// This is part of the lnwire.Message interface. +func (o *OpenChannel) MsgType() MessageType { + return MsgOpenChannel +} + +// MaxPayloadLength returns the maximum allowed payload length for a +// OpenChannel message. +// +// This is part of the lnwire.Message interface. +func (o *OpenChannel) MaxPayloadLength(uint32) uint32 { + // (32 * 2) + (8 * 5) + (4 * 2) + (2 * 2) + (33 * 5) + 1 + return 282 +}