diff --git a/.golangci.yml b/.golangci.yml index ee9246b2..5ffd56ac 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -8,6 +8,7 @@ run: skip-dirs: - channeldb/migration_01_to_11 + - channeldb/migration/lnwire21 build-tags: - autopilotrpc diff --git a/channeldb/migration/lnwire21/accept_channel.go b/channeldb/migration/lnwire21/accept_channel.go new file mode 100644 index 00000000..da9daa69 --- /dev/null +++ b/channeldb/migration/lnwire21/accept_channel.go @@ -0,0 +1,182 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcutil" +) + +// AcceptChannel is the message Bob sends to Alice after she initiates the +// single funder channel workflow via an 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. + 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 + + // MinAcceptDepth is the minimum depth that the initiator of the + // channel should wait before considering the channel open. + MinAcceptDepth 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 + + // 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 + + // 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 +} + +// 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.HtlcMinimum, + a.MinAcceptDepth, + a.CsvDelay, + a.MaxAcceptedHTLCs, + a.FundingKey, + a.RevocationPoint, + a.PaymentPoint, + a.DelayedPaymentPoint, + a.HtlcPoint, + a.FirstCommitmentPoint, + a.UpfrontShutdownScript, + ) +} + +// 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 { + // Read all the mandatory fields in the accept message. + err := ReadElements(r, + a.PendingChannelID[:], + &a.DustLimit, + &a.MaxValueInFlight, + &a.ChannelReserve, + &a.HtlcMinimum, + &a.MinAcceptDepth, + &a.CsvDelay, + &a.MaxAcceptedHTLCs, + &a.FundingKey, + &a.RevocationPoint, + &a.PaymentPoint, + &a.DelayedPaymentPoint, + &a.HtlcPoint, + &a.FirstCommitmentPoint, + ) + if err != nil { + return err + } + + // Check for the optional upfront shutdown script field. If it is not there, + // silence the EOF error. + err = ReadElement(r, &a.UpfrontShutdownScript) + if err != nil && err != io.EOF { + return err + } + return nil +} + +// MsgType returns the MessageType code which uniquely identifies this message +// as an 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 * 4) + (4 * 1) + (2 * 2) + (33 * 6) + var length uint32 = 270 // base length + + // Upfront shutdown script max length. + length += 2 + deliveryAddressMaxSize + + return length +} diff --git a/channeldb/migration/lnwire21/announcement_signatures.go b/channeldb/migration/lnwire21/announcement_signatures.go new file mode 100644 index 00000000..639704de --- /dev/null +++ b/channeldb/migration/lnwire21/announcement_signatures.go @@ -0,0 +1,108 @@ +package lnwire + +import ( + "io" + "io/ioutil" +) + +// AnnounceSignatures is a direct message between two endpoints of a +// channel and serves as an opt-in mechanism to allow the announcement of +// the channel to the rest of the network. It contains the necessary +// signatures by the sender to construct the channel announcement message. +type AnnounceSignatures struct { + // ChannelID is the unique description of the funding transaction. + // Channel id is better for users and debugging and short channel id is + // used for quick test on existence of the particular utxo inside the + // block chain, because it contains information about block. + ChannelID ChannelID + + // ShortChannelID is the unique description of the funding + // transaction. It is constructed with the most significant 3 bytes + // as the block height, the next 3 bytes indicating the transaction + // index within the block, and the least significant two bytes + // indicating the output index which pays to the channel. + ShortChannelID ShortChannelID + + // NodeSignature is the signature which contains the signed announce + // channel message, by this signature we proof that we possess of the + // node pub key and creating the reference node_key -> bitcoin_key. + NodeSignature Sig + + // BitcoinSignature is the signature which contains the signed node + // public key, by this signature we proof that we possess of the + // bitcoin key and and creating the reverse reference bitcoin_key -> + // node_key. + BitcoinSignature Sig + + // ExtraOpaqueData is the set of data that was appended to this + // message, some of which we may not actually know how to iterate or + // parse. By holding onto this data, we ensure that we're able to + // properly validate the set of signatures that cover these new fields, + // and ensure we're able to make upgrades to the network in a forwards + // compatible manner. + ExtraOpaqueData []byte +} + +// A compile time check to ensure AnnounceSignatures implements the +// lnwire.Message interface. +var _ Message = (*AnnounceSignatures)(nil) + +// Decode deserializes a serialized AnnounceSignatures stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures) Decode(r io.Reader, pver uint32) error { + err := ReadElements(r, + &a.ChannelID, + &a.ShortChannelID, + &a.NodeSignature, + &a.BitcoinSignature, + ) + if err != nil { + return err + } + + // Now that we've read out all the fields that we explicitly know of, + // we'll collect the remainder into the ExtraOpaqueData field. If there + // aren't any bytes, then we'll snip off the slice to avoid carrying + // around excess capacity. + a.ExtraOpaqueData, err = ioutil.ReadAll(r) + if err != nil { + return err + } + if len(a.ExtraOpaqueData) == 0 { + a.ExtraOpaqueData = nil + } + + return nil +} + +// Encode serializes the target AnnounceSignatures into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + a.ChannelID, + a.ShortChannelID, + a.NodeSignature, + a.BitcoinSignature, + a.ExtraOpaqueData, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures) MsgType() MessageType { + return MsgAnnounceSignatures +} + +// MaxPayloadLength returns the maximum allowed payload size for this message +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *AnnounceSignatures) MaxPayloadLength(pver uint32) uint32 { + return 65533 +} diff --git a/channeldb/migration/lnwire21/channel_announcement.go b/channeldb/migration/lnwire21/channel_announcement.go new file mode 100644 index 00000000..46efeed8 --- /dev/null +++ b/channeldb/migration/lnwire21/channel_announcement.go @@ -0,0 +1,160 @@ +package lnwire + +import ( + "bytes" + "io" + "io/ioutil" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// ChannelAnnouncement message is used to announce the existence of a channel +// between two peers in the overlay, which is propagated by the discovery +// service over broadcast handler. +type ChannelAnnouncement struct { + // This signatures are used by nodes in order to create cross + // references between node's channel and node. Requiring both nodes + // to sign indicates they are both willing to route other payments via + // this node. + NodeSig1 Sig + NodeSig2 Sig + + // This signatures are used by nodes in order to create cross + // references between node's channel and node. Requiring the bitcoin + // signatures proves they control the channel. + BitcoinSig1 Sig + BitcoinSig2 Sig + + // Features is the feature vector that encodes the features supported + // by the target node. This field can be used to signal the type of the + // channel, or modifications to the fields that would normally follow + // this vector. + Features *RawFeatureVector + + // ChainHash denotes the target chain that this channel was opened + // within. This value should be the genesis hash of the target chain. + ChainHash chainhash.Hash + + // ShortChannelID is the unique description of the funding transaction, + // or where exactly it's located within the target blockchain. + ShortChannelID ShortChannelID + + // The public keys of the two nodes who are operating the channel, such + // that is NodeID1 the numerically-lesser than NodeID2 (ascending + // numerical order). + NodeID1 [33]byte + NodeID2 [33]byte + + // Public keys which corresponds to the keys which was declared in + // multisig funding transaction output. + BitcoinKey1 [33]byte + BitcoinKey2 [33]byte + + // ExtraOpaqueData is the set of data that was appended to this + // message, some of which we may not actually know how to iterate or + // parse. By holding onto this data, we ensure that we're able to + // properly validate the set of signatures that cover these new fields, + // and ensure we're able to make upgrades to the network in a forwards + // compatible manner. + ExtraOpaqueData []byte +} + +// A compile time check to ensure ChannelAnnouncement implements the +// lnwire.Message interface. +var _ Message = (*ChannelAnnouncement)(nil) + +// Decode deserializes a serialized ChannelAnnouncement stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *ChannelAnnouncement) Decode(r io.Reader, pver uint32) error { + err := ReadElements(r, + &a.NodeSig1, + &a.NodeSig2, + &a.BitcoinSig1, + &a.BitcoinSig2, + &a.Features, + a.ChainHash[:], + &a.ShortChannelID, + &a.NodeID1, + &a.NodeID2, + &a.BitcoinKey1, + &a.BitcoinKey2, + ) + if err != nil { + return err + } + + // Now that we've read out all the fields that we explicitly know of, + // we'll collect the remainder into the ExtraOpaqueData field. If there + // aren't any bytes, then we'll snip off the slice to avoid carrying + // around excess capacity. + a.ExtraOpaqueData, err = ioutil.ReadAll(r) + if err != nil { + return err + } + if len(a.ExtraOpaqueData) == 0 { + a.ExtraOpaqueData = nil + } + + return nil +} + +// Encode serializes the target ChannelAnnouncement into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (a *ChannelAnnouncement) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + a.NodeSig1, + a.NodeSig2, + a.BitcoinSig1, + a.BitcoinSig2, + a.Features, + a.ChainHash[:], + a.ShortChannelID, + a.NodeID1, + a.NodeID2, + a.BitcoinKey1, + a.BitcoinKey2, + a.ExtraOpaqueData, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (a *ChannelAnnouncement) MsgType() MessageType { + return MsgChannelAnnouncement +} + +// MaxPayloadLength returns the maximum allowed payload size for this message +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *ChannelAnnouncement) MaxPayloadLength(pver uint32) uint32 { + return 65533 +} + +// DataToSign is used to retrieve part of the announcement message which should +// be signed. +func (a *ChannelAnnouncement) DataToSign() ([]byte, error) { + // We should not include the signatures itself. + var w bytes.Buffer + err := WriteElements(&w, + a.Features, + a.ChainHash[:], + a.ShortChannelID, + a.NodeID1, + a.NodeID2, + a.BitcoinKey1, + a.BitcoinKey2, + a.ExtraOpaqueData, + ) + if err != nil { + return nil, err + } + + return w.Bytes(), nil +} diff --git a/channeldb/migration/lnwire21/channel_id.go b/channeldb/migration/lnwire21/channel_id.go new file mode 100644 index 00000000..0a9e0822 --- /dev/null +++ b/channeldb/migration/lnwire21/channel_id.go @@ -0,0 +1,91 @@ +package lnwire + +import ( + "encoding/binary" + "encoding/hex" + "math" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" +) + +const ( + // MaxFundingTxOutputs is the maximum number of allowed outputs on a + // funding transaction within the protocol. This is due to the fact + // that we use 2-bytes to encode the index within the funding output + // during the funding workflow. Funding transaction with more outputs + // than this are considered invalid within the protocol. + MaxFundingTxOutputs = math.MaxUint16 +) + +// ChannelID is a series of 32-bytes that uniquely identifies all channels +// within the network. The ChannelID is computed using the outpoint of the +// funding transaction (the txid, and output index). Given a funding output the +// ChannelID can be calculated by XOR'ing the big-endian serialization of the +// txid and the big-endian serialization of the output index, truncated to +// 2 bytes. +type ChannelID [32]byte + +// ConnectionWideID is an all-zero ChannelID, which is used to represent a +// message intended for all channels to specific peer. +var ConnectionWideID = ChannelID{} + +// String returns the string representation of the ChannelID. This is just the +// hex string encoding of the ChannelID itself. +func (c ChannelID) String() string { + return hex.EncodeToString(c[:]) +} + +// NewChanIDFromOutPoint converts a target OutPoint into a ChannelID that is +// usable within the network. In order to convert the OutPoint into a ChannelID, +// we XOR the lower 2-bytes of the txid within the OutPoint with the big-endian +// serialization of the Index of the OutPoint, truncated to 2-bytes. +func NewChanIDFromOutPoint(op *wire.OutPoint) ChannelID { + // First we'll copy the txid of the outpoint into our channel ID slice. + var cid ChannelID + copy(cid[:], op.Hash[:]) + + // With the txid copied over, we'll now XOR the lower 2-bytes of the + // partial channelID with big-endian serialization of output index. + xorTxid(&cid, uint16(op.Index)) + + return cid +} + +// xorTxid performs the transformation needed to transform an OutPoint into a +// ChannelID. To do this, we expect the cid parameter to contain the txid +// unaltered and the outputIndex to be the output index +func xorTxid(cid *ChannelID, outputIndex uint16) { + var buf [2]byte + binary.BigEndian.PutUint16(buf[:], outputIndex) + + cid[30] ^= buf[0] + cid[31] ^= buf[1] +} + +// GenPossibleOutPoints generates all the possible outputs given a channel ID. +// In order to generate these possible outpoints, we perform a brute-force +// search through the candidate output index space, performing a reverse +// mapping from channelID back to OutPoint. +func (c *ChannelID) GenPossibleOutPoints() [MaxFundingTxOutputs]wire.OutPoint { + var possiblePoints [MaxFundingTxOutputs]wire.OutPoint + for i := uint16(0); i < MaxFundingTxOutputs; i++ { + cidCopy := *c + xorTxid(&cidCopy, i) + + possiblePoints[i] = wire.OutPoint{ + Hash: chainhash.Hash(cidCopy), + Index: uint32(i), + } + } + + return possiblePoints +} + +// IsChanPoint returns true if the OutPoint passed corresponds to the target +// ChannelID. +func (c ChannelID) IsChanPoint(op *wire.OutPoint) bool { + candidateCid := NewChanIDFromOutPoint(op) + + return candidateCid == c +} diff --git a/channeldb/migration/lnwire21/channel_reestablish.go b/channeldb/migration/lnwire21/channel_reestablish.go new file mode 100644 index 00000000..6fa8f8ac --- /dev/null +++ b/channeldb/migration/lnwire21/channel_reestablish.go @@ -0,0 +1,166 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcd/btcec" +) + +// ChannelReestablish is a message sent between peers that have an existing +// open channel upon connection reestablishment. This message allows both sides +// to report their local state, and their current knowledge of the state of the +// remote commitment chain. If a deviation is detected and can be recovered +// from, then the necessary messages will be retransmitted. If the level of +// desynchronization is irreconcilable, then the channel will be force closed. +type ChannelReestablish struct { + // ChanID is the channel ID of the channel state we're attempting to + // synchronize with the remote party. + ChanID ChannelID + + // NextLocalCommitHeight is the next local commitment height of the + // sending party. If the height of the sender's commitment chain from + // the receiver's Pov is one less that this number, then the sender + // should re-send the *exact* same proposed commitment. + // + // In other words, the receiver should re-send their last sent + // commitment iff: + // + // * NextLocalCommitHeight == remoteCommitChain.Height + // + // This covers the case of a lost commitment which was sent by the + // sender of this message, but never received by the receiver of this + // message. + NextLocalCommitHeight uint64 + + // RemoteCommitTailHeight is the height of the receiving party's + // unrevoked commitment from the PoV of the sender of this message. If + // the height of the receiver's commitment is *one more* than this + // value, then their prior RevokeAndAck message should be + // retransmitted. + // + // In other words, the receiver should re-send their last sent + // RevokeAndAck message iff: + // + // * localCommitChain.tail().Height == RemoteCommitTailHeight + 1 + // + // This covers the case of a lost revocation, wherein the receiver of + // the message sent a revocation for a prior state, but the sender of + // the message never fully processed it. + RemoteCommitTailHeight uint64 + + // LastRemoteCommitSecret is the last commitment secret that the + // receiving node has sent to the sending party. This will be the + // secret of the last revoked commitment transaction. Including this + // provides proof that the sending node at least knows of this state, + // as they couldn't have produced it if it wasn't sent, as the value + // can be authenticated by querying the shachain or the receiving + // party. + LastRemoteCommitSecret [32]byte + + // LocalUnrevokedCommitPoint is the commitment point used in the + // current un-revoked commitment transaction of the sending party. + LocalUnrevokedCommitPoint *btcec.PublicKey +} + +// A compile time check to ensure ChannelReestablish implements the +// lnwire.Message interface. +var _ Message = (*ChannelReestablish)(nil) + +// Encode serializes the target ChannelReestablish into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (a *ChannelReestablish) Encode(w io.Writer, pver uint32) error { + err := WriteElements(w, + a.ChanID, + a.NextLocalCommitHeight, + a.RemoteCommitTailHeight, + ) + if err != nil { + return err + } + + // If the commit point wasn't sent, then we won't write out any of the + // remaining fields as they're optional. + if a.LocalUnrevokedCommitPoint == nil { + return nil + } + + // Otherwise, we'll write out the remaining elements. + return WriteElements(w, a.LastRemoteCommitSecret[:], + a.LocalUnrevokedCommitPoint) +} + +// Decode deserializes a serialized ChannelReestablish stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *ChannelReestablish) Decode(r io.Reader, pver uint32) error { + err := ReadElements(r, + &a.ChanID, + &a.NextLocalCommitHeight, + &a.RemoteCommitTailHeight, + ) + if err != nil { + return err + } + + // This message has currently defined optional fields. As a result, + // we'll only proceed if there's still bytes remaining within the + // reader. + // + // We'll manually parse out the optional fields in order to be able to + // still utilize the io.Reader interface. + + // We'll first attempt to read the optional commit secret, if we're at + // the EOF, then this means the field wasn't included so we can exit + // early. + var buf [32]byte + _, err = io.ReadFull(r, buf[:32]) + if err == io.EOF { + return nil + } else if err != nil { + return err + } + + // If the field is present, then we'll copy it over and proceed. + copy(a.LastRemoteCommitSecret[:], buf[:]) + + // We'll conclude by parsing out the commitment point. We don't check + // the error in this case, as it has included the commit secret, then + // they MUST also include the commit point. + return ReadElement(r, &a.LocalUnrevokedCommitPoint) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (a *ChannelReestablish) MsgType() MessageType { + return MsgChannelReestablish +} + +// MaxPayloadLength returns the maximum allowed payload size for this message +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *ChannelReestablish) MaxPayloadLength(pver uint32) uint32 { + var length uint32 + + // ChanID - 32 bytes + length += 32 + + // NextLocalCommitHeight - 8 bytes + length += 8 + + // RemoteCommitTailHeight - 8 bytes + length += 8 + + // LastRemoteCommitSecret - 32 bytes + length += 32 + + // LocalUnrevokedCommitPoint - 33 bytes + length += 33 + + return length +} diff --git a/channeldb/migration/lnwire21/channel_update.go b/channeldb/migration/lnwire21/channel_update.go new file mode 100644 index 00000000..037f3d55 --- /dev/null +++ b/channeldb/migration/lnwire21/channel_update.go @@ -0,0 +1,258 @@ +package lnwire + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// ChanUpdateMsgFlags is a bitfield that signals whether optional fields are +// present in the ChannelUpdate. +type ChanUpdateMsgFlags uint8 + +const ( + // ChanUpdateOptionMaxHtlc is a bit that indicates whether the + // optional htlc_maximum_msat field is present in this ChannelUpdate. + ChanUpdateOptionMaxHtlc ChanUpdateMsgFlags = 1 << iota +) + +// String returns the bitfield flags as a string. +func (c ChanUpdateMsgFlags) String() string { + return fmt.Sprintf("%08b", c) +} + +// HasMaxHtlc returns true if the htlc_maximum_msat option bit is set in the +// message flags. +func (c ChanUpdateMsgFlags) HasMaxHtlc() bool { + return c&ChanUpdateOptionMaxHtlc != 0 +} + +// ChanUpdateChanFlags is a bitfield that signals various options concerning a +// particular channel edge. Each bit is to be examined in order to determine +// how the ChannelUpdate message is to be interpreted. +type ChanUpdateChanFlags uint8 + +const ( + // ChanUpdateDirection indicates the direction of a channel update. If + // this bit is set to 0 if Node1 (the node with the "smaller" Node ID) + // is updating the channel, and to 1 otherwise. + ChanUpdateDirection ChanUpdateChanFlags = 1 << iota + + // ChanUpdateDisabled is a bit that indicates if the channel edge + // selected by the ChanUpdateDirection bit is to be treated as being + // disabled. + ChanUpdateDisabled +) + +// IsDisabled determines whether the channel flags has the disabled bit set. +func (c ChanUpdateChanFlags) IsDisabled() bool { + return c&ChanUpdateDisabled == ChanUpdateDisabled +} + +// String returns the bitfield flags as a string. +func (c ChanUpdateChanFlags) String() string { + return fmt.Sprintf("%08b", c) +} + +// ChannelUpdate message is used after channel has been initially announced. +// Each side independently announces its fees and minimum expiry for HTLCs and +// other parameters. Also this message is used to redeclare initially set +// channel parameters. +type ChannelUpdate struct { + // Signature is used to validate the announced data and prove the + // ownership of node id. + Signature Sig + + // ChainHash denotes the target chain that this channel was opened + // within. This value should be the genesis hash of the target chain. + // Along with the short channel ID, this uniquely identifies the + // channel globally in a blockchain. + ChainHash chainhash.Hash + + // ShortChannelID is the unique description of the funding transaction. + ShortChannelID ShortChannelID + + // Timestamp allows ordering in the case of multiple announcements. We + // should ignore the message if timestamp is not greater than + // the last-received. + Timestamp uint32 + + // MessageFlags is a bitfield that describes whether optional fields + // are present in this update. Currently, the least-significant bit + // must be set to 1 if the optional field MaxHtlc is present. + MessageFlags ChanUpdateMsgFlags + + // ChannelFlags is a bitfield that describes additional meta-data + // concerning how the update is to be interpreted. Currently, the + // least-significant bit must be set to 0 if the creating node + // corresponds to the first node in the previously sent channel + // announcement and 1 otherwise. If the second bit is set, then the + // channel is set to be disabled. + ChannelFlags ChanUpdateChanFlags + + // TimeLockDelta is the minimum number of blocks this node requires to + // be added to the expiry of HTLCs. This is a security parameter + // determined by the node operator. This value represents the required + // gap between the time locks of the incoming and outgoing HTLC's set + // to this node. + TimeLockDelta uint16 + + // HtlcMinimumMsat is the minimum HTLC value which will be accepted. + HtlcMinimumMsat MilliSatoshi + + // BaseFee is the base fee that must be used for incoming HTLC's to + // this particular channel. This value will be tacked onto the required + // for a payment independent of the size of the payment. + BaseFee uint32 + + // FeeRate is the fee rate that will be charged per millionth of a + // satoshi. + FeeRate uint32 + + // HtlcMaximumMsat is the maximum HTLC value which will be accepted. + HtlcMaximumMsat MilliSatoshi + + // ExtraOpaqueData is the set of data that was appended to this + // message, some of which we may not actually know how to iterate or + // parse. By holding onto this data, we ensure that we're able to + // properly validate the set of signatures that cover these new fields, + // and ensure we're able to make upgrades to the network in a forwards + // compatible manner. + ExtraOpaqueData []byte +} + +// A compile time check to ensure ChannelUpdate implements the lnwire.Message +// interface. +var _ Message = (*ChannelUpdate)(nil) + +// Decode deserializes a serialized ChannelUpdate stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *ChannelUpdate) Decode(r io.Reader, pver uint32) error { + err := ReadElements(r, + &a.Signature, + a.ChainHash[:], + &a.ShortChannelID, + &a.Timestamp, + &a.MessageFlags, + &a.ChannelFlags, + &a.TimeLockDelta, + &a.HtlcMinimumMsat, + &a.BaseFee, + &a.FeeRate, + ) + if err != nil { + return err + } + + // Now check whether the max HTLC field is present and read it if so. + if a.MessageFlags.HasMaxHtlc() { + if err := ReadElements(r, &a.HtlcMaximumMsat); err != nil { + return err + } + } + + // Now that we've read out all the fields that we explicitly know of, + // we'll collect the remainder into the ExtraOpaqueData field. If there + // aren't any bytes, then we'll snip off the slice to avoid carrying + // around excess capacity. + a.ExtraOpaqueData, err = ioutil.ReadAll(r) + if err != nil { + return err + } + if len(a.ExtraOpaqueData) == 0 { + a.ExtraOpaqueData = nil + } + + return nil +} + +// Encode serializes the target ChannelUpdate into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (a *ChannelUpdate) Encode(w io.Writer, pver uint32) error { + err := WriteElements(w, + a.Signature, + a.ChainHash[:], + a.ShortChannelID, + a.Timestamp, + a.MessageFlags, + a.ChannelFlags, + a.TimeLockDelta, + a.HtlcMinimumMsat, + a.BaseFee, + a.FeeRate, + ) + if err != nil { + return err + } + + // Now append optional fields if they are set. Currently, the only + // optional field is max HTLC. + if a.MessageFlags.HasMaxHtlc() { + if err := WriteElements(w, a.HtlcMaximumMsat); err != nil { + return err + } + } + + // Finally, append any extra opaque data. + return WriteElements(w, a.ExtraOpaqueData) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (a *ChannelUpdate) MsgType() MessageType { + return MsgChannelUpdate +} + +// MaxPayloadLength returns the maximum allowed payload size for this message +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *ChannelUpdate) MaxPayloadLength(pver uint32) uint32 { + return 65533 +} + +// DataToSign is used to retrieve part of the announcement message which should +// be signed. +func (a *ChannelUpdate) DataToSign() ([]byte, error) { + + // We should not include the signatures itself. + var w bytes.Buffer + err := WriteElements(&w, + a.ChainHash[:], + a.ShortChannelID, + a.Timestamp, + a.MessageFlags, + a.ChannelFlags, + a.TimeLockDelta, + a.HtlcMinimumMsat, + a.BaseFee, + a.FeeRate, + ) + if err != nil { + return nil, err + } + + // Now append optional fields if they are set. Currently, the only + // optional field is max HTLC. + if a.MessageFlags.HasMaxHtlc() { + if err := WriteElements(&w, a.HtlcMaximumMsat); err != nil { + return nil, err + } + } + + // Finally, append any extra opaque data. + if err := WriteElements(&w, a.ExtraOpaqueData); err != nil { + return nil, err + } + + return w.Bytes(), nil +} diff --git a/channeldb/migration/lnwire21/closing_signed.go b/channeldb/migration/lnwire21/closing_signed.go new file mode 100644 index 00000000..91b90646 --- /dev/null +++ b/channeldb/migration/lnwire21/closing_signed.go @@ -0,0 +1,88 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcutil" +) + +// ClosingSigned is sent by both parties to a channel once the channel is clear +// of HTLCs, and is primarily concerned with negotiating fees for the close +// transaction. Each party provides a signature for a transaction with a fee +// that they believe is fair. The process terminates when both sides agree on +// the same fee, or when one side force closes the channel. +// +// NOTE: The responder is able to send a signature without any additional +// messages as all transactions are assembled observing BIP 69 which defines a +// canonical ordering for input/outputs. Therefore, both sides are able to +// arrive at an identical closure transaction as they know the order of the +// inputs/outputs. +type ClosingSigned struct { + // ChannelID serves to identify which channel is to be closed. + ChannelID ChannelID + + // FeeSatoshis is the total fee in satoshis that the party to the + // channel would like to propose for the close transaction. + FeeSatoshis btcutil.Amount + + // Signature is for the proposed channel close transaction. + Signature Sig +} + +// NewClosingSigned creates a new empty ClosingSigned message. +func NewClosingSigned(cid ChannelID, fs btcutil.Amount, + sig Sig) *ClosingSigned { + + return &ClosingSigned{ + ChannelID: cid, + FeeSatoshis: fs, + Signature: sig, + } +} + +// A compile time check to ensure ClosingSigned implements the lnwire.Message +// interface. +var _ Message = (*ClosingSigned)(nil) + +// Decode deserializes a serialized ClosingSigned message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *ClosingSigned) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, &c.ChannelID, &c.FeeSatoshis, &c.Signature) +} + +// Encode serializes the target ClosingSigned into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *ClosingSigned) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, c.ChannelID, c.FeeSatoshis, c.Signature) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *ClosingSigned) MsgType() MessageType { + return MsgClosingSigned +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// ClosingSigned complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *ClosingSigned) MaxPayloadLength(uint32) uint32 { + var length uint32 + + // ChannelID - 32 bytes + length += 32 + + // FeeSatoshis - 8 bytes + length += 8 + + // Signature - 64 bytes + length += 64 + + return length +} diff --git a/channeldb/migration/lnwire21/commit_sig.go b/channeldb/migration/lnwire21/commit_sig.go new file mode 100644 index 00000000..f15a9738 --- /dev/null +++ b/channeldb/migration/lnwire21/commit_sig.go @@ -0,0 +1,95 @@ +package lnwire + +import ( + "io" +) + +// CommitSig is sent by either side to stage any pending HTLC's in the +// receiver's pending set into a new commitment state. Implicitly, the new +// commitment transaction constructed which has been signed by CommitSig +// includes all HTLC's in the remote node's pending set. A CommitSig message +// may be sent after a series of UpdateAddHTLC/UpdateFulfillHTLC messages in +// order to batch add several HTLC's with a single signature covering all +// implicitly accepted HTLC's. +type CommitSig struct { + // ChanID uniquely identifies to which currently active channel this + // CommitSig applies to. + ChanID ChannelID + + // CommitSig is Alice's signature for Bob's new commitment transaction. + // Alice is able to send this signature without requesting any + // additional data due to the piggybacking of Bob's next revocation + // hash in his prior RevokeAndAck message, as well as the canonical + // ordering used for all inputs/outputs within commitment transactions. + // If initiating a new commitment state, this signature should ONLY + // cover all of the sending party's pending log updates, and the log + // updates of the remote party that have been ACK'd. + CommitSig Sig + + // HtlcSigs is a signature for each relevant HTLC output within the + // created commitment. The order of the signatures is expected to be + // identical to the placement of the HTLC's within the BIP 69 sorted + // commitment transaction. For each outgoing HTLC (from the PoV of the + // sender of this message), a signature for an HTLC timeout transaction + // should be signed, for each incoming HTLC the HTLC timeout + // transaction should be signed. + HtlcSigs []Sig +} + +// NewCommitSig creates a new empty CommitSig message. +func NewCommitSig() *CommitSig { + return &CommitSig{} +} + +// A compile time check to ensure CommitSig implements the lnwire.Message +// interface. +var _ Message = (*CommitSig)(nil) + +// Decode deserializes a serialized CommitSig message stored in the +// passed io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *CommitSig) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.CommitSig, + &c.HtlcSigs, + ) +} + +// Encode serializes the target CommitSig into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *CommitSig) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.CommitSig, + c.HtlcSigs, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *CommitSig) MsgType() MessageType { + return MsgCommitSig +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// CommitSig complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *CommitSig) MaxPayloadLength(uint32) uint32 { + // 32 + 64 + 2 + max_allowed_htlcs + return MaxMessagePayload +} + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of peer.LinkUpdater interface. +func (c *CommitSig) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/channeldb/migration/lnwire21/error.go b/channeldb/migration/lnwire21/error.go new file mode 100644 index 00000000..19911d1f --- /dev/null +++ b/channeldb/migration/lnwire21/error.go @@ -0,0 +1,139 @@ +package lnwire + +import ( + "fmt" + "io" +) + +// FundingError represents a set of errors that can be encountered and sent +// during the funding workflow. +type FundingError uint8 + +const ( + // ErrMaxPendingChannels is returned by remote peer when the number of + // active pending channels exceeds their maximum policy limit. + ErrMaxPendingChannels FundingError = 1 + + // ErrSynchronizingChain is returned by a remote peer that receives a + // channel update or a funding request while it's still syncing to the + // latest state of the blockchain. + ErrSynchronizingChain FundingError = 2 + + // ErrChanTooLarge is returned by a remote peer that receives a + // FundingOpen request for a channel that is above their current + // soft-limit. + ErrChanTooLarge FundingError = 3 +) + +// String returns a human readable version of the target FundingError. +func (e FundingError) String() string { + switch e { + case ErrMaxPendingChannels: + return "Number of pending channels exceed maximum" + case ErrSynchronizingChain: + return "Synchronizing blockchain" + case ErrChanTooLarge: + return "channel too large" + default: + return "unknown error" + } +} + +// Error returns the human readable version of the target FundingError. +// +// NOTE: Satisfies the Error interface. +func (e FundingError) Error() string { + return e.String() +} + +// ErrorData is a set of bytes associated with a particular sent error. A +// receiving node SHOULD only print out data verbatim if the string is composed +// solely of printable ASCII characters. For reference, the printable character +// set includes byte values 32 through 127 inclusive. +type ErrorData []byte + +// Error represents a generic error bound to an exact channel. The message +// format is purposefully general in order to allow expression of a wide array +// of possible errors. Each Error message is directed at a particular open +// channel referenced by ChannelPoint. +type Error struct { + // ChanID references the active channel in which the error occurred + // within. If the ChanID is all zeros, then this error applies to the + // entire established connection. + ChanID ChannelID + + // Data is the attached error data that describes the exact failure + // which caused the error message to be sent. + Data ErrorData +} + +// NewError creates a new Error message. +func NewError() *Error { + return &Error{} +} + +// A compile time check to ensure Error implements the lnwire.Message +// interface. +var _ Message = (*Error)(nil) + +// Error returns the string representation to Error. +// +// NOTE: Satisfies the error interface. +func (c *Error) Error() string { + errMsg := "non-ascii data" + if isASCII(c.Data) { + errMsg = string(c.Data) + } + + return fmt.Sprintf("chan_id=%v, err=%v", c.ChanID, errMsg) +} + +// Decode deserializes a serialized Error message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *Error) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.Data, + ) +} + +// Encode serializes the target Error into the passed io.Writer observing the +// protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *Error) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.Data, + ) +} + +// MsgType returns the integer uniquely identifying an Error message on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *Error) MsgType() MessageType { + return MsgError +} + +// MaxPayloadLength returns the maximum allowed payload size for an Error +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *Error) MaxPayloadLength(uint32) uint32 { + // 32 + 2 + 65501 + return MaxMessagePayload +} + +// isASCII is a helper method that checks whether all bytes in `data` would be +// printable ASCII characters if interpreted as a string. +func isASCII(data []byte) bool { + for _, c := range data { + if c < 32 || c > 126 { + return false + } + } + return true +} diff --git a/channeldb/migration/lnwire21/features.go b/channeldb/migration/lnwire21/features.go new file mode 100644 index 00000000..279e72c9 --- /dev/null +++ b/channeldb/migration/lnwire21/features.go @@ -0,0 +1,482 @@ +package lnwire + +import ( + "encoding/binary" + "errors" + "io" +) + +var ( + // ErrFeaturePairExists signals an error in feature vector construction + // where the opposing bit in a feature pair has already been set. + ErrFeaturePairExists = errors.New("feature pair exists") +) + +// FeatureBit represents a feature that can be enabled in either a local or +// global feature vector at a specific bit position. Feature bits follow the +// "it's OK to be odd" rule, where features at even bit positions must be known +// to a node receiving them from a peer while odd bits do not. In accordance, +// feature bits are usually assigned in pairs, first being assigned an odd bit +// position which may later be changed to the preceding even position once +// knowledge of the feature becomes required on the network. +type FeatureBit uint16 + +const ( + // DataLossProtectRequired is a feature bit that indicates that a peer + // *requires* the other party know about the data-loss-protect optional + // feature. If the remote peer does not know of such a feature, then + // the sending peer SHOLUD disconnect them. The data-loss-protect + // feature allows a peer that's lost partial data to recover their + // settled funds of the latest commitment state. + DataLossProtectRequired FeatureBit = 0 + + // DataLossProtectOptional is an optional feature bit that indicates + // that the sending peer knows of this new feature and can activate it + // it. The data-loss-protect feature allows a peer that's lost partial + // data to recover their settled funds of the latest commitment state. + DataLossProtectOptional FeatureBit = 1 + + // InitialRoutingSync is a local feature bit meaning that the receiving + // node should send a complete dump of routing information when a new + // connection is established. + InitialRoutingSync FeatureBit = 3 + + // UpfrontShutdownScriptRequired is a feature bit which indicates that a + // peer *requires* that the remote peer accept an upfront shutdown script to + // which payout is enforced on cooperative closes. + UpfrontShutdownScriptRequired FeatureBit = 4 + + // UpfrontShutdownScriptOptional is an optional feature bit which indicates + // that the peer will accept an upfront shutdown script to which payout is + // enforced on cooperative closes. + UpfrontShutdownScriptOptional FeatureBit = 5 + + // GossipQueriesRequired is a feature bit that indicates that the + // receiving peer MUST know of the set of features that allows nodes to + // more efficiently query the network view of peers on the network for + // reconciliation purposes. + GossipQueriesRequired FeatureBit = 6 + + // GossipQueriesOptional is an optional feature bit that signals that + // the setting peer knows of the set of features that allows more + // efficient network view reconciliation. + GossipQueriesOptional FeatureBit = 7 + + // TLVOnionPayloadRequired is a feature bit that indicates a node is + // able to decode the new TLV information included in the onion packet. + TLVOnionPayloadRequired FeatureBit = 8 + + // TLVOnionPayloadOptional is an optional feature bit that indicates a + // node is able to decode the new TLV information included in the onion + // packet. + TLVOnionPayloadOptional FeatureBit = 9 + + // StaticRemoteKeyRequired is a required feature bit that signals that + // within one's commitment transaction, the key used for the remote + // party's non-delay output should not be tweaked. + StaticRemoteKeyRequired FeatureBit = 12 + + // StaticRemoteKeyOptional is an optional feature bit that signals that + // within one's commitment transaction, the key used for the remote + // party's non-delay output should not be tweaked. + StaticRemoteKeyOptional FeatureBit = 13 + + // PaymentAddrRequired is a required feature bit that signals that a + // node requires payment addresses, which are used to mitigate probing + // attacks on the receiver of a payment. + PaymentAddrRequired FeatureBit = 14 + + // PaymentAddrOptional is an optional feature bit that signals that a + // node supports payment addresses, which are used to mitigate probing + // attacks on the receiver of a payment. + PaymentAddrOptional FeatureBit = 15 + + // MPPOptional is a required feature bit that signals that the receiver + // of a payment requires settlement of an invoice with more than one + // HTLC. + MPPRequired FeatureBit = 16 + + // MPPOptional is an optional feature bit that signals that the receiver + // of a payment supports settlement of an invoice with more than one + // HTLC. + MPPOptional FeatureBit = 17 + + // WumboChannelsRequired is a required feature bit that signals that a + // node is willing to accept channels larger than 2^24 satoshis. + WumboChannelsRequired FeatureBit = 18 + + // WumboChannelsOptional is an optional feature bit that signals that a + // node is willing to accept channels larger than 2^24 satoshis. + WumboChannelsOptional FeatureBit = 19 + + // AnchorsRequired is a required feature bit that signals that the node + // requires channels to be made using commitments having anchor + // outputs. + AnchorsRequired FeatureBit = 20 + + // AnchorsOptional is an optional feature bit that signals that the + // node supports channels to be made using commitments having anchor + // outputs. + AnchorsOptional FeatureBit = 21 + + // AnchorsZeroFeeHtlcTxRequired is a required feature bit that signals + // that the node requires channels having zero-fee second-level HTLC + // transactions, which also imply anchor commitments. + AnchorsZeroFeeHtlcTxRequired FeatureBit = 22 + + // AnchorsZeroFeeHtlcTxRequired is an optional feature bit that signals + // that the node supports channels having zero-fee second-level HTLC + // transactions, which also imply anchor commitments. + AnchorsZeroFeeHtlcTxOptional FeatureBit = 23 + + // maxAllowedSize is a maximum allowed size of feature vector. + // + // NOTE: Within the protocol, the maximum allowed message size is 65535 + // bytes for all messages. Accounting for the overhead within the feature + // message to signal the type of message, that leaves us with 65533 bytes + // for the init message itself. Next, we reserve 4 bytes to encode the + // lengths of both the local and global feature vectors, so 65529 bytes + // for the local and global features. Knocking off one byte for the sake + // of the calculation, that leads us to 32764 bytes for each feature + // vector, or 131056 different features. + maxAllowedSize = 32764 +) + +// IsRequired returns true if the feature bit is even, and false otherwise. +func (b FeatureBit) IsRequired() bool { + return b&0x01 == 0x00 +} + +// Features is a mapping of known feature bits to a descriptive name. All known +// feature bits must be assigned a name in this mapping, and feature bit pairs +// must be assigned together for correct behavior. +var Features = map[FeatureBit]string{ + DataLossProtectRequired: "data-loss-protect", + DataLossProtectOptional: "data-loss-protect", + InitialRoutingSync: "initial-routing-sync", + UpfrontShutdownScriptRequired: "upfront-shutdown-script", + UpfrontShutdownScriptOptional: "upfront-shutdown-script", + GossipQueriesRequired: "gossip-queries", + GossipQueriesOptional: "gossip-queries", + TLVOnionPayloadRequired: "tlv-onion", + TLVOnionPayloadOptional: "tlv-onion", + StaticRemoteKeyOptional: "static-remote-key", + StaticRemoteKeyRequired: "static-remote-key", + PaymentAddrOptional: "payment-addr", + PaymentAddrRequired: "payment-addr", + MPPOptional: "multi-path-payments", + MPPRequired: "multi-path-payments", + AnchorsRequired: "anchor-commitments", + AnchorsOptional: "anchor-commitments", + AnchorsZeroFeeHtlcTxRequired: "anchors-zero-fee-htlc-tx", + AnchorsZeroFeeHtlcTxOptional: "anchors-zero-fee-htlc-tx", + WumboChannelsRequired: "wumbo-channels", + WumboChannelsOptional: "wumbo-channels", +} + +// RawFeatureVector represents a set of feature bits as defined in BOLT-09. A +// RawFeatureVector itself just stores a set of bit flags but can be used to +// construct a FeatureVector which binds meaning to each bit. Feature vectors +// can be serialized and deserialized to/from a byte representation that is +// transmitted in Lightning network messages. +type RawFeatureVector struct { + features map[FeatureBit]bool +} + +// NewRawFeatureVector creates a feature vector with all of the feature bits +// given as arguments enabled. +func NewRawFeatureVector(bits ...FeatureBit) *RawFeatureVector { + fv := &RawFeatureVector{features: make(map[FeatureBit]bool)} + for _, bit := range bits { + fv.Set(bit) + } + return fv +} + +// Merges sets all feature bits in other on the receiver's feature vector. +func (fv *RawFeatureVector) Merge(other *RawFeatureVector) error { + for bit := range other.features { + err := fv.SafeSet(bit) + if err != nil { + return err + } + } + return nil +} + +// Clone makes a copy of a feature vector. +func (fv *RawFeatureVector) Clone() *RawFeatureVector { + newFeatures := NewRawFeatureVector() + for bit := range fv.features { + newFeatures.Set(bit) + } + return newFeatures +} + +// IsSet returns whether a particular feature bit is enabled in the vector. +func (fv *RawFeatureVector) IsSet(feature FeatureBit) bool { + return fv.features[feature] +} + +// Set marks a feature as enabled in the vector. +func (fv *RawFeatureVector) Set(feature FeatureBit) { + fv.features[feature] = true +} + +// SafeSet sets the chosen feature bit in the feature vector, but returns an +// error if the opposing feature bit is already set. This ensures both that we +// are creating properly structured feature vectors, and in some cases, that +// peers are sending properly encoded ones, i.e. it can't be both optional and +// required. +func (fv *RawFeatureVector) SafeSet(feature FeatureBit) error { + if _, ok := fv.features[feature^1]; ok { + return ErrFeaturePairExists + } + + fv.Set(feature) + return nil +} + +// Unset marks a feature as disabled in the vector. +func (fv *RawFeatureVector) Unset(feature FeatureBit) { + delete(fv.features, feature) +} + +// SerializeSize returns the number of bytes needed to represent feature vector +// in byte format. +func (fv *RawFeatureVector) SerializeSize() int { + // We calculate byte-length via the largest bit index. + return fv.serializeSize(8) +} + +// SerializeSize32 returns the number of bytes needed to represent feature +// vector in base32 format. +func (fv *RawFeatureVector) SerializeSize32() int { + // We calculate base32-length via the largest bit index. + return fv.serializeSize(5) +} + +// serializeSize returns the number of bytes required to encode the feature +// vector using at most width bits per encoded byte. +func (fv *RawFeatureVector) serializeSize(width int) int { + // Find the largest feature bit index + max := -1 + for feature := range fv.features { + index := int(feature) + if index > max { + max = index + } + } + if max == -1 { + return 0 + } + + return max/width + 1 +} + +// Encode writes the feature vector in byte representation. Every feature +// encoded as a bit, and the bit vector is serialized using the least number of +// bytes. Since the bit vector length is variable, the first two bytes of the +// serialization represent the length. +func (fv *RawFeatureVector) Encode(w io.Writer) error { + // Write length of feature vector. + var l [2]byte + length := fv.SerializeSize() + binary.BigEndian.PutUint16(l[:], uint16(length)) + if _, err := w.Write(l[:]); err != nil { + return err + } + + return fv.encode(w, length, 8) +} + +// EncodeBase256 writes the feature vector in base256 representation. Every +// feature is encoded as a bit, and the bit vector is serialized using the least +// number of bytes. +func (fv *RawFeatureVector) EncodeBase256(w io.Writer) error { + length := fv.SerializeSize() + return fv.encode(w, length, 8) +} + +// EncodeBase32 writes the feature vector in base32 representation. Every feature +// is encoded as a bit, and the bit vector is serialized using the least number of +// bytes. +func (fv *RawFeatureVector) EncodeBase32(w io.Writer) error { + length := fv.SerializeSize32() + return fv.encode(w, length, 5) +} + +// encode writes the feature vector +func (fv *RawFeatureVector) encode(w io.Writer, length, width int) error { + // Generate the data and write it. + data := make([]byte, length) + for feature := range fv.features { + byteIndex := int(feature) / width + bitIndex := int(feature) % width + data[length-byteIndex-1] |= 1 << uint(bitIndex) + } + + _, err := w.Write(data) + return err +} + +// Decode reads the feature vector from its byte representation. Every feature +// is encoded as a bit, and the bit vector is serialized using the least number +// of bytes. Since the bit vector length is variable, the first two bytes of the +// serialization represent the length. +func (fv *RawFeatureVector) Decode(r io.Reader) error { + // Read the length of the feature vector. + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + length := binary.BigEndian.Uint16(l[:]) + + return fv.decode(r, int(length), 8) +} + +// DecodeBase256 reads the feature vector from its base256 representation. Every +// feature encoded as a bit, and the bit vector is serialized using the least +// number of bytes. +func (fv *RawFeatureVector) DecodeBase256(r io.Reader, length int) error { + return fv.decode(r, length, 8) +} + +// DecodeBase32 reads the feature vector from its base32 representation. Every +// feature encoded as a bit, and the bit vector is serialized using the least +// number of bytes. +func (fv *RawFeatureVector) DecodeBase32(r io.Reader, length int) error { + return fv.decode(r, length, 5) +} + +// decode reads a feature vector from the next length bytes of the io.Reader, +// assuming each byte has width feature bits encoded per byte. +func (fv *RawFeatureVector) decode(r io.Reader, length, width int) error { + // Read the feature vector data. + data := make([]byte, length) + if _, err := io.ReadFull(r, data); err != nil { + return err + } + + // Set feature bits from parsed data. + bitsNumber := len(data) * width + for i := 0; i < bitsNumber; i++ { + byteIndex := int(i / width) + bitIndex := uint(i % width) + if (data[length-byteIndex-1]>>bitIndex)&1 == 1 { + fv.Set(FeatureBit(i)) + } + } + + return nil +} + +// FeatureVector represents a set of enabled features. The set stores +// information on enabled flags and metadata about the feature names. A feature +// vector is serializable to a compact byte representation that is included in +// Lightning network messages. +type FeatureVector struct { + *RawFeatureVector + featureNames map[FeatureBit]string +} + +// NewFeatureVector constructs a new FeatureVector from a raw feature vector +// and mapping of feature definitions. If the feature vector argument is nil, a +// new one will be constructed with no enabled features. +func NewFeatureVector(featureVector *RawFeatureVector, + featureNames map[FeatureBit]string) *FeatureVector { + + if featureVector == nil { + featureVector = NewRawFeatureVector() + } + return &FeatureVector{ + RawFeatureVector: featureVector, + featureNames: featureNames, + } +} + +// EmptyFeatureVector returns a feature vector with no bits set. +func EmptyFeatureVector() *FeatureVector { + return NewFeatureVector(nil, Features) +} + +// HasFeature returns whether a particular feature is included in the set. The +// feature can be seen as set either if the bit is set directly OR the queried +// bit has the same meaning as its corresponding even/odd bit, which is set +// instead. The second case is because feature bits are generally assigned in +// pairs where both the even and odd position represent the same feature. +func (fv *FeatureVector) HasFeature(feature FeatureBit) bool { + return fv.IsSet(feature) || + (fv.isFeatureBitPair(feature) && fv.IsSet(feature^1)) +} + +// RequiresFeature returns true if the referenced feature vector *requires* +// that the given required bit be set. This method can be used with both +// optional and required feature bits as a parameter. +func (fv *FeatureVector) RequiresFeature(feature FeatureBit) bool { + // If we weren't passed a required feature bit, then we'll flip the + // lowest bit to query for the required version of the feature. This + // lets callers pass in both the optional and required bits. + if !feature.IsRequired() { + feature ^= 1 + } + + return fv.IsSet(feature) +} + +// UnknownRequiredFeatures returns a list of feature bits set in the vector +// that are unknown and in an even bit position. Feature bits with an even +// index must be known to a node receiving the feature vector in a message. +func (fv *FeatureVector) UnknownRequiredFeatures() []FeatureBit { + var unknown []FeatureBit + for feature := range fv.features { + if feature%2 == 0 && !fv.IsKnown(feature) { + unknown = append(unknown, feature) + } + } + return unknown +} + +// Name returns a string identifier for the feature represented by this bit. If +// the bit does not represent a known feature, this returns a string indicating +// as such. +func (fv *FeatureVector) Name(bit FeatureBit) string { + name, known := fv.featureNames[bit] + if !known { + return "unknown" + } + return name +} + +// IsKnown returns whether this feature bit represents a known feature. +func (fv *FeatureVector) IsKnown(bit FeatureBit) bool { + _, known := fv.featureNames[bit] + return known +} + +// isFeatureBitPair returns whether this feature bit and its corresponding +// even/odd bit both represent the same feature. This may often be the case as +// bits are generally assigned in pairs, first being assigned an odd bit +// position then being promoted to an even bit position once the network is +// ready. +func (fv *FeatureVector) isFeatureBitPair(bit FeatureBit) bool { + name1, known1 := fv.featureNames[bit] + name2, known2 := fv.featureNames[bit^1] + return known1 && known2 && name1 == name2 +} + +// Features returns the set of raw features contained in the feature vector. +func (fv *FeatureVector) Features() map[FeatureBit]struct{} { + fs := make(map[FeatureBit]struct{}, len(fv.RawFeatureVector.features)) + for b := range fv.RawFeatureVector.features { + fs[b] = struct{}{} + } + return fs +} + +// Clone copies a feature vector, carrying over its feature bits. The feature +// names are not copied. +func (fv *FeatureVector) Clone() *FeatureVector { + features := fv.RawFeatureVector.Clone() + return NewFeatureVector(features, fv.featureNames) +} diff --git a/channeldb/migration/lnwire21/funding_created.go b/channeldb/migration/lnwire21/funding_created.go new file mode 100644 index 00000000..c14321ec --- /dev/null +++ b/channeldb/migration/lnwire21/funding_created.go @@ -0,0 +1,66 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/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 Sig +} + +// 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/channeldb/migration/lnwire21/funding_locked.go b/channeldb/migration/lnwire21/funding_locked.go new file mode 100644 index 00000000..c441b0be --- /dev/null +++ b/channeldb/migration/lnwire21/funding_locked.go @@ -0,0 +1,83 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcd/btcec" +) + +// FundingLocked is the message that both parties to a new channel creation +// send once they have observed the funding transaction being confirmed on the +// blockchain. FundingLocked contains the signatures necessary for the channel +// participants to advertise the existence of the channel to the rest of the +// network. +type FundingLocked struct { + // ChanID is the outpoint of the channel's funding transaction. This + // can be used to query for the channel in the database. + ChanID ChannelID + + // NextPerCommitmentPoint is the secret that can be used to revoke the + // next commitment transaction for the channel. + NextPerCommitmentPoint *btcec.PublicKey +} + +// NewFundingLocked creates a new FundingLocked message, populating it with the +// necessary IDs and revocation secret. +func NewFundingLocked(cid ChannelID, npcp *btcec.PublicKey) *FundingLocked { + return &FundingLocked{ + ChanID: cid, + NextPerCommitmentPoint: npcp, + } +} + +// A compile time check to ensure FundingLocked implements the lnwire.Message +// interface. +var _ Message = (*FundingLocked)(nil) + +// Decode deserializes the serialized FundingLocked message stored in the +// passed io.Reader into the target FundingLocked using the deserialization +// rules defined by the passed protocol version. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.NextPerCommitmentPoint) +} + +// Encode serializes the target FundingLocked message 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 (c *FundingLocked) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.NextPerCommitmentPoint) +} + +// MsgType returns the uint32 code which uniquely identifies this message as a +// FundingLocked message on the wire. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) MsgType() MessageType { + return MsgFundingLocked +} + +// MaxPayloadLength returns the maximum allowed payload length for a +// FundingLocked message. This is calculated by summing the max length of all +// the fields within a FundingLocked message. +// +// This is part of the lnwire.Message interface. +func (c *FundingLocked) MaxPayloadLength(uint32) uint32 { + var length uint32 + + // ChanID - 32 bytes + length += 32 + + // NextPerCommitmentPoint - 33 bytes + length += 33 + + // 65 bytes + return length +} diff --git a/channeldb/migration/lnwire21/funding_signed.go b/channeldb/migration/lnwire21/funding_signed.go new file mode 100644 index 00000000..620f8b37 --- /dev/null +++ b/channeldb/migration/lnwire21/funding_signed.go @@ -0,0 +1,55 @@ +package lnwire + +import "io" + +// 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 Sig +} + +// 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/channeldb/migration/lnwire21/gossip_timestamp_range.go b/channeldb/migration/lnwire21/gossip_timestamp_range.go new file mode 100644 index 00000000..3c28cd05 --- /dev/null +++ b/channeldb/migration/lnwire21/gossip_timestamp_range.go @@ -0,0 +1,80 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// GossipTimestampRange is a message that allows the sender to restrict the set +// of future gossip announcements sent by the receiver. Nodes should send this +// if they have the gossip-queries feature bit active. Nodes are able to send +// new GossipTimestampRange messages to replace the prior window. +type GossipTimestampRange struct { + // ChainHash denotes the chain that the sender wishes to restrict the + // set of received announcements of. + ChainHash chainhash.Hash + + // FirstTimestamp is the timestamp of the earliest announcement message + // that should be sent by the receiver. + FirstTimestamp uint32 + + // TimestampRange is the horizon beyond the FirstTimestamp that any + // announcement messages should be sent for. The receiving node MUST + // NOT send any announcements that have a timestamp greater than + // FirstTimestamp + TimestampRange. + TimestampRange uint32 +} + +// NewGossipTimestampRange creates a new empty GossipTimestampRange message. +func NewGossipTimestampRange() *GossipTimestampRange { + return &GossipTimestampRange{} +} + +// A compile time check to ensure GossipTimestampRange implements the +// lnwire.Message interface. +var _ Message = (*GossipTimestampRange)(nil) + +// Decode deserializes a serialized GossipTimestampRange message stored in the +// passed io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (g *GossipTimestampRange) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + g.ChainHash[:], + &g.FirstTimestamp, + &g.TimestampRange, + ) +} + +// Encode serializes the target GossipTimestampRange into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (g *GossipTimestampRange) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + g.ChainHash[:], + g.FirstTimestamp, + g.TimestampRange, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (g *GossipTimestampRange) MsgType() MessageType { + return MsgGossipTimestampRange +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// GossipTimestampRange complete message observing the specified protocol +// version. +// +// This is part of the lnwire.Message interface. +func (g *GossipTimestampRange) MaxPayloadLength(uint32) uint32 { + // 32 + 4 + 4 + // + // TODO(roasbeef): update to 8 byte timestmaps? + return 40 +} diff --git a/channeldb/migration/lnwire21/init_message.go b/channeldb/migration/lnwire21/init_message.go new file mode 100644 index 00000000..e1ddbb01 --- /dev/null +++ b/channeldb/migration/lnwire21/init_message.go @@ -0,0 +1,73 @@ +package lnwire + +import "io" + +// Init is the first message reveals the features supported or required by this +// node. Nodes wait for receipt of the other's features to simplify error +// diagnosis where features are incompatible. Each node MUST wait to receive +// init before sending any other messages. +type Init struct { + // GlobalFeatures is a legacy feature vector used for backwards + // compatibility with older nodes. Any features defined here should be + // merged with those presented in Features. + GlobalFeatures *RawFeatureVector + + // Features is a feature vector containing the features supported by + // the remote node. + // + // NOTE: Older nodes may place some features in GlobalFeatures, but all + // new features are to be added in Features. When handling an Init + // message, any GlobalFeatures should be merged into the unified + // Features field. + Features *RawFeatureVector +} + +// NewInitMessage creates new instance of init message object. +func NewInitMessage(gf *RawFeatureVector, f *RawFeatureVector) *Init { + return &Init{ + GlobalFeatures: gf, + Features: f, + } +} + +// A compile time check to ensure Init implements the lnwire.Message +// interface. +var _ Message = (*Init)(nil) + +// Decode deserializes a serialized Init message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (msg *Init) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &msg.GlobalFeatures, + &msg.Features, + ) +} + +// Encode serializes the target Init into the passed io.Writer observing +// the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (msg *Init) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + msg.GlobalFeatures, + msg.Features, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (msg *Init) MsgType() MessageType { + return MsgInit +} + +// MaxPayloadLength returns the maximum allowed payload size for an Init +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (msg *Init) MaxPayloadLength(uint32) uint32 { + return 2 + 2 + maxAllowedSize + 2 + maxAllowedSize +} diff --git a/channeldb/migration/lnwire21/lnwire.go b/channeldb/migration/lnwire21/lnwire.go new file mode 100644 index 00000000..ca0e449e --- /dev/null +++ b/channeldb/migration/lnwire21/lnwire.go @@ -0,0 +1,845 @@ +package lnwire + +import ( + "bytes" + "encoding/binary" + "fmt" + "image/color" + "io" + "math" + + "net" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" + "github.com/go-errors/errors" + "github.com/lightningnetwork/lnd/tor" +) + +// MaxSliceLength is the maximum allowed length for any opaque byte slices in +// the wire protocol. +const MaxSliceLength = 65535 + +// PkScript is simple type definition which represents a raw serialized public +// key script. +type PkScript []byte + +// addressType specifies the network protocol and version that should be used +// when connecting to a node at a particular address. +type addressType uint8 + +const ( + // noAddr denotes a blank address. An address of this type indicates + // that a node doesn't have any advertised addresses. + noAddr addressType = 0 + + // tcp4Addr denotes an IPv4 TCP address. + tcp4Addr addressType = 1 + + // tcp6Addr denotes an IPv6 TCP address. + tcp6Addr addressType = 2 + + // v2OnionAddr denotes a version 2 Tor onion service address. + v2OnionAddr addressType = 3 + + // v3OnionAddr denotes a version 3 Tor (prop224) onion service address. + v3OnionAddr addressType = 4 +) + +// AddrLen returns the number of bytes that it takes to encode the target +// address. +func (a addressType) AddrLen() uint16 { + switch a { + case noAddr: + return 0 + case tcp4Addr: + return 6 + case tcp6Addr: + return 18 + case v2OnionAddr: + return 12 + case v3OnionAddr: + return 37 + default: + return 0 + } +} + +// WriteElement is a one-stop shop to write the big endian representation of +// any element which is to be serialized for the wire protocol. The passed +// io.Writer should be backed by an appropriately sized byte slice, or be able +// to dynamically expand to accommodate additional data. +// +// TODO(roasbeef): this should eventually draw from a buffer pool for +// serialization. +func WriteElement(w io.Writer, element interface{}) error { + switch e := element.(type) { + case NodeAlias: + if _, err := w.Write(e[:]); err != nil { + return err + } + + case ShortChanIDEncoding: + var b [1]byte + b[0] = uint8(e) + if _, err := w.Write(b[:]); err != nil { + return err + } + case uint8: + var b [1]byte + b[0] = e + if _, err := w.Write(b[:]); err != nil { + return err + } + case FundingFlag: + var b [1]byte + b[0] = uint8(e) + if _, err := w.Write(b[:]); err != nil { + return err + } + case uint16: + var b [2]byte + binary.BigEndian.PutUint16(b[:], e) + if _, err := w.Write(b[:]); err != nil { + return err + } + case ChanUpdateMsgFlags: + var b [1]byte + b[0] = uint8(e) + if _, err := w.Write(b[:]); err != nil { + return err + } + case ChanUpdateChanFlags: + var b [1]byte + b[0] = uint8(e) + if _, err := w.Write(b[:]); err != nil { + return err + } + case MilliSatoshi: + var b [8]byte + binary.BigEndian.PutUint64(b[:], uint64(e)) + if _, err := w.Write(b[:]); err != nil { + return err + } + case btcutil.Amount: + var b [8]byte + binary.BigEndian.PutUint64(b[:], uint64(e)) + if _, err := w.Write(b[:]); err != nil { + return err + } + case uint32: + var b [4]byte + binary.BigEndian.PutUint32(b[:], e) + if _, err := w.Write(b[:]); err != nil { + return err + } + case uint64: + var b [8]byte + binary.BigEndian.PutUint64(b[:], e) + if _, err := w.Write(b[:]); err != nil { + return err + } + case *btcec.PublicKey: + if e == nil { + return fmt.Errorf("cannot write nil pubkey") + } + + var b [33]byte + serializedPubkey := e.SerializeCompressed() + copy(b[:], serializedPubkey) + if _, err := w.Write(b[:]); err != nil { + return err + } + case []Sig: + var b [2]byte + numSigs := uint16(len(e)) + binary.BigEndian.PutUint16(b[:], numSigs) + if _, err := w.Write(b[:]); err != nil { + return err + } + + for _, sig := range e { + if err := WriteElement(w, sig); err != nil { + return err + } + } + case Sig: + // Write buffer + if _, err := w.Write(e[:]); err != nil { + return err + } + case PingPayload: + var l [2]byte + binary.BigEndian.PutUint16(l[:], uint16(len(e))) + if _, err := w.Write(l[:]); err != nil { + return err + } + + if _, err := w.Write(e[:]); err != nil { + return err + } + case PongPayload: + var l [2]byte + binary.BigEndian.PutUint16(l[:], uint16(len(e))) + if _, err := w.Write(l[:]); err != nil { + return err + } + + if _, err := w.Write(e[:]); err != nil { + return err + } + case ErrorData: + var l [2]byte + binary.BigEndian.PutUint16(l[:], uint16(len(e))) + if _, err := w.Write(l[:]); err != nil { + return err + } + + if _, err := w.Write(e[:]); err != nil { + return err + } + case OpaqueReason: + var l [2]byte + binary.BigEndian.PutUint16(l[:], uint16(len(e))) + if _, err := w.Write(l[:]); err != nil { + return err + } + + if _, err := w.Write(e[:]); err != nil { + return err + } + case [33]byte: + if _, err := w.Write(e[:]); err != nil { + return err + } + case []byte: + if _, err := w.Write(e[:]); err != nil { + return err + } + case PkScript: + // The largest script we'll accept is a p2wsh which is exactly + // 34 bytes long. + scriptLength := len(e) + if scriptLength > 34 { + return fmt.Errorf("'PkScript' too long") + } + + if err := wire.WriteVarBytes(w, 0, e); err != nil { + return err + } + case *RawFeatureVector: + if e == nil { + return fmt.Errorf("cannot write nil feature vector") + } + + if err := e.Encode(w); err != nil { + return err + } + + case wire.OutPoint: + var h [32]byte + copy(h[:], e.Hash[:]) + if _, err := w.Write(h[:]); err != nil { + return err + } + + if e.Index > math.MaxUint16 { + return fmt.Errorf("index for outpoint (%v) is "+ + "greater than max index of %v", e.Index, + math.MaxUint16) + } + + var idx [2]byte + binary.BigEndian.PutUint16(idx[:], uint16(e.Index)) + if _, err := w.Write(idx[:]); err != nil { + return err + } + + case ChannelID: + if _, err := w.Write(e[:]); err != nil { + return err + } + case FailCode: + if err := WriteElement(w, uint16(e)); err != nil { + return err + } + case ShortChannelID: + // Check that field fit in 3 bytes and write the blockHeight + if e.BlockHeight > ((1 << 24) - 1) { + return errors.New("block height should fit in 3 bytes") + } + + var blockHeight [4]byte + binary.BigEndian.PutUint32(blockHeight[:], e.BlockHeight) + + if _, err := w.Write(blockHeight[1:]); err != nil { + return err + } + + // Check that field fit in 3 bytes and write the txIndex + if e.TxIndex > ((1 << 24) - 1) { + return errors.New("tx index should fit in 3 bytes") + } + + var txIndex [4]byte + binary.BigEndian.PutUint32(txIndex[:], e.TxIndex) + if _, err := w.Write(txIndex[1:]); err != nil { + return err + } + + // Write the txPosition + var txPosition [2]byte + binary.BigEndian.PutUint16(txPosition[:], e.TxPosition) + if _, err := w.Write(txPosition[:]); err != nil { + return err + } + + case *net.TCPAddr: + if e == nil { + return fmt.Errorf("cannot write nil TCPAddr") + } + + if e.IP.To4() != nil { + var descriptor [1]byte + descriptor[0] = uint8(tcp4Addr) + if _, err := w.Write(descriptor[:]); err != nil { + return err + } + + var ip [4]byte + copy(ip[:], e.IP.To4()) + if _, err := w.Write(ip[:]); err != nil { + return err + } + } else { + var descriptor [1]byte + descriptor[0] = uint8(tcp6Addr) + if _, err := w.Write(descriptor[:]); err != nil { + return err + } + var ip [16]byte + copy(ip[:], e.IP.To16()) + if _, err := w.Write(ip[:]); err != nil { + return err + } + } + var port [2]byte + binary.BigEndian.PutUint16(port[:], uint16(e.Port)) + if _, err := w.Write(port[:]); err != nil { + return err + } + + case *tor.OnionAddr: + if e == nil { + return errors.New("cannot write nil onion address") + } + + var suffixIndex int + switch len(e.OnionService) { + case tor.V2Len: + descriptor := []byte{byte(v2OnionAddr)} + if _, err := w.Write(descriptor); err != nil { + return err + } + suffixIndex = tor.V2Len - tor.OnionSuffixLen + case tor.V3Len: + descriptor := []byte{byte(v3OnionAddr)} + if _, err := w.Write(descriptor); err != nil { + return err + } + suffixIndex = tor.V3Len - tor.OnionSuffixLen + default: + return errors.New("unknown onion service length") + } + + host, err := tor.Base32Encoding.DecodeString( + e.OnionService[:suffixIndex], + ) + if err != nil { + return err + } + if _, err := w.Write(host); err != nil { + return err + } + + var port [2]byte + binary.BigEndian.PutUint16(port[:], uint16(e.Port)) + if _, err := w.Write(port[:]); err != nil { + return err + } + + case []net.Addr: + // First, we'll encode all the addresses into an intermediate + // buffer. We need to do this in order to compute the total + // length of the addresses. + var addrBuf bytes.Buffer + for _, address := range e { + if err := WriteElement(&addrBuf, address); err != nil { + return err + } + } + + // With the addresses fully encoded, we can now write out the + // number of bytes needed to encode them. + addrLen := addrBuf.Len() + if err := WriteElement(w, uint16(addrLen)); err != nil { + return err + } + + // Finally, we'll write out the raw addresses themselves, but + // only if we have any bytes to write. + if addrLen > 0 { + if _, err := w.Write(addrBuf.Bytes()); err != nil { + return err + } + } + case color.RGBA: + if err := WriteElements(w, e.R, e.G, e.B); err != nil { + return err + } + + case DeliveryAddress: + var length [2]byte + binary.BigEndian.PutUint16(length[:], uint16(len(e))) + if _, err := w.Write(length[:]); err != nil { + return err + } + if _, err := w.Write(e[:]); err != nil { + return err + } + + case bool: + var b [1]byte + if e { + b[0] = 1 + } + if _, err := w.Write(b[:]); err != nil { + return err + } + default: + return fmt.Errorf("unknown type in WriteElement: %T", e) + } + + return nil +} + +// WriteElements is writes each element in the elements slice to the passed +// io.Writer using WriteElement. +func WriteElements(w io.Writer, elements ...interface{}) error { + for _, element := range elements { + err := WriteElement(w, element) + if err != nil { + return err + } + } + return nil +} + +// ReadElement is a one-stop utility function to deserialize any datastructure +// encoded using the serialization format of lnwire. +func ReadElement(r io.Reader, element interface{}) error { + var err error + switch e := element.(type) { + case *bool: + var b [1]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + + if b[0] == 1 { + *e = true + } + + case *NodeAlias: + var a [32]byte + if _, err := io.ReadFull(r, a[:]); err != nil { + return err + } + + alias, err := NewNodeAlias(string(a[:])) + if err != nil { + return err + } + + *e = alias + case *ShortChanIDEncoding: + var b [1]uint8 + if _, err := r.Read(b[:]); err != nil { + return err + } + *e = ShortChanIDEncoding(b[0]) + case *uint8: + var b [1]uint8 + if _, err := r.Read(b[:]); err != nil { + return err + } + *e = b[0] + case *FundingFlag: + var b [1]uint8 + if _, err := r.Read(b[:]); err != nil { + return err + } + *e = FundingFlag(b[0]) + case *uint16: + var b [2]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + *e = binary.BigEndian.Uint16(b[:]) + case *ChanUpdateMsgFlags: + var b [1]uint8 + if _, err := r.Read(b[:]); err != nil { + return err + } + *e = ChanUpdateMsgFlags(b[0]) + case *ChanUpdateChanFlags: + var b [1]uint8 + if _, err := r.Read(b[:]); err != nil { + return err + } + *e = ChanUpdateChanFlags(b[0]) + case *uint32: + var b [4]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + *e = binary.BigEndian.Uint32(b[:]) + case *uint64: + var b [8]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + *e = binary.BigEndian.Uint64(b[:]) + case *MilliSatoshi: + var b [8]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + *e = MilliSatoshi(int64(binary.BigEndian.Uint64(b[:]))) + case *btcutil.Amount: + var b [8]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + *e = btcutil.Amount(int64(binary.BigEndian.Uint64(b[:]))) + case **btcec.PublicKey: + var b [btcec.PubKeyBytesLenCompressed]byte + if _, err = io.ReadFull(r, b[:]); err != nil { + return err + } + + pubKey, err := btcec.ParsePubKey(b[:], btcec.S256()) + if err != nil { + return err + } + *e = pubKey + case **RawFeatureVector: + f := NewRawFeatureVector() + err = f.Decode(r) + if err != nil { + return err + } + + *e = f + + case *[]Sig: + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + numSigs := binary.BigEndian.Uint16(l[:]) + + var sigs []Sig + if numSigs > 0 { + sigs = make([]Sig, numSigs) + for i := 0; i < int(numSigs); i++ { + if err := ReadElement(r, &sigs[i]); err != nil { + return err + } + } + } + + *e = sigs + + case *Sig: + if _, err := io.ReadFull(r, e[:]); err != nil { + return err + } + case *OpaqueReason: + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + reasonLen := binary.BigEndian.Uint16(l[:]) + + *e = OpaqueReason(make([]byte, reasonLen)) + if _, err := io.ReadFull(r, *e); err != nil { + return err + } + case *ErrorData: + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + errorLen := binary.BigEndian.Uint16(l[:]) + + *e = ErrorData(make([]byte, errorLen)) + if _, err := io.ReadFull(r, *e); err != nil { + return err + } + case *PingPayload: + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + pingLen := binary.BigEndian.Uint16(l[:]) + + *e = PingPayload(make([]byte, pingLen)) + if _, err := io.ReadFull(r, *e); err != nil { + return err + } + case *PongPayload: + var l [2]byte + if _, err := io.ReadFull(r, l[:]); err != nil { + return err + } + pongLen := binary.BigEndian.Uint16(l[:]) + + *e = PongPayload(make([]byte, pongLen)) + if _, err := io.ReadFull(r, *e); err != nil { + return err + } + case *[33]byte: + if _, err := io.ReadFull(r, e[:]); err != nil { + return err + } + case []byte: + if _, err := io.ReadFull(r, e); err != nil { + return err + } + case *PkScript: + pkScript, err := wire.ReadVarBytes(r, 0, 34, "pkscript") + if err != nil { + return err + } + *e = pkScript + case *wire.OutPoint: + var h [32]byte + if _, err = io.ReadFull(r, h[:]); err != nil { + return err + } + hash, err := chainhash.NewHash(h[:]) + if err != nil { + return err + } + + var idxBytes [2]byte + _, err = io.ReadFull(r, idxBytes[:]) + if err != nil { + return err + } + index := binary.BigEndian.Uint16(idxBytes[:]) + + *e = wire.OutPoint{ + Hash: *hash, + Index: uint32(index), + } + case *FailCode: + if err := ReadElement(r, (*uint16)(e)); err != nil { + return err + } + case *ChannelID: + if _, err := io.ReadFull(r, e[:]); err != nil { + return err + } + + case *ShortChannelID: + var blockHeight [4]byte + if _, err = io.ReadFull(r, blockHeight[1:]); err != nil { + return err + } + + var txIndex [4]byte + if _, err = io.ReadFull(r, txIndex[1:]); err != nil { + return err + } + + var txPosition [2]byte + if _, err = io.ReadFull(r, txPosition[:]); err != nil { + return err + } + + *e = ShortChannelID{ + BlockHeight: binary.BigEndian.Uint32(blockHeight[:]), + TxIndex: binary.BigEndian.Uint32(txIndex[:]), + TxPosition: binary.BigEndian.Uint16(txPosition[:]), + } + + case *[]net.Addr: + // First, we'll read the number of total bytes that have been + // used to encode the set of addresses. + var numAddrsBytes [2]byte + if _, err = io.ReadFull(r, numAddrsBytes[:]); err != nil { + return err + } + addrsLen := binary.BigEndian.Uint16(numAddrsBytes[:]) + + // With the number of addresses, read, we'll now pull in the + // buffer of the encoded addresses into memory. + addrs := make([]byte, addrsLen) + if _, err := io.ReadFull(r, addrs[:]); err != nil { + return err + } + addrBuf := bytes.NewReader(addrs) + + // Finally, we'll parse the remaining address payload in + // series, using the first byte to denote how to decode the + // address itself. + var ( + addresses []net.Addr + addrBytesRead uint16 + ) + + for addrBytesRead < addrsLen { + var descriptor [1]byte + if _, err = io.ReadFull(addrBuf, descriptor[:]); err != nil { + return err + } + + addrBytesRead++ + + var address net.Addr + switch aType := addressType(descriptor[0]); aType { + case noAddr: + addrBytesRead += aType.AddrLen() + continue + + case tcp4Addr: + var ip [4]byte + if _, err := io.ReadFull(addrBuf, ip[:]); err != nil { + return err + } + + var port [2]byte + if _, err := io.ReadFull(addrBuf, port[:]); err != nil { + return err + } + + address = &net.TCPAddr{ + IP: net.IP(ip[:]), + Port: int(binary.BigEndian.Uint16(port[:])), + } + addrBytesRead += aType.AddrLen() + + case tcp6Addr: + var ip [16]byte + if _, err := io.ReadFull(addrBuf, ip[:]); err != nil { + return err + } + + var port [2]byte + if _, err := io.ReadFull(addrBuf, port[:]); err != nil { + return err + } + + address = &net.TCPAddr{ + IP: net.IP(ip[:]), + Port: int(binary.BigEndian.Uint16(port[:])), + } + addrBytesRead += aType.AddrLen() + + case v2OnionAddr: + var h [tor.V2DecodedLen]byte + if _, err := io.ReadFull(addrBuf, h[:]); err != nil { + return err + } + + var p [2]byte + if _, err := io.ReadFull(addrBuf, p[:]); err != nil { + return err + } + + onionService := tor.Base32Encoding.EncodeToString(h[:]) + onionService += tor.OnionSuffix + port := int(binary.BigEndian.Uint16(p[:])) + + address = &tor.OnionAddr{ + OnionService: onionService, + Port: port, + } + addrBytesRead += aType.AddrLen() + + case v3OnionAddr: + var h [tor.V3DecodedLen]byte + if _, err := io.ReadFull(addrBuf, h[:]); err != nil { + return err + } + + var p [2]byte + if _, err := io.ReadFull(addrBuf, p[:]); err != nil { + return err + } + + onionService := tor.Base32Encoding.EncodeToString(h[:]) + onionService += tor.OnionSuffix + port := int(binary.BigEndian.Uint16(p[:])) + + address = &tor.OnionAddr{ + OnionService: onionService, + Port: port, + } + addrBytesRead += aType.AddrLen() + + default: + return &ErrUnknownAddrType{aType} + } + + addresses = append(addresses, address) + } + + *e = addresses + case *color.RGBA: + err := ReadElements(r, + &e.R, + &e.G, + &e.B, + ) + if err != nil { + return err + } + case *DeliveryAddress: + var addrLen [2]byte + if _, err = io.ReadFull(r, addrLen[:]); err != nil { + return err + } + length := binary.BigEndian.Uint16(addrLen[:]) + + var addrBytes [deliveryAddressMaxSize]byte + if length > deliveryAddressMaxSize { + return fmt.Errorf("cannot read %d bytes into addrBytes", length) + } + if _, err = io.ReadFull(r, addrBytes[:length]); err != nil { + return err + } + *e = addrBytes[:length] + default: + return fmt.Errorf("unknown type in ReadElement: %T", e) + } + + return nil +} + +// ReadElements deserializes a variable number of elements into the passed +// io.Reader, with each element being deserialized according to the ReadElement +// function. +func ReadElements(r io.Reader, elements ...interface{}) error { + for _, element := range elements { + err := ReadElement(r, element) + if err != nil { + return err + } + } + return nil +} diff --git a/channeldb/migration/lnwire21/message.go b/channeldb/migration/lnwire21/message.go new file mode 100644 index 00000000..b5c27339 --- /dev/null +++ b/channeldb/migration/lnwire21/message.go @@ -0,0 +1,296 @@ +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers +// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go +// Copyright (C) 2015-2017 The Lightning Network Developers + +package lnwire + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +// MaxMessagePayload is the maximum bytes a message can be regardless of other +// individual limits imposed by messages themselves. +const MaxMessagePayload = 65535 // 65KB + +// MessageType is the unique 2 byte big-endian integer that indicates the type +// of message on the wire. All messages have a very simple header which +// consists simply of 2-byte message type. We omit a length field, and checksum +// as the Lightning Protocol is intended to be encapsulated within a +// confidential+authenticated cryptographic messaging protocol. +type MessageType uint16 + +// The currently defined message types within this current version of the +// Lightning protocol. +const ( + MsgInit MessageType = 16 + MsgError = 17 + MsgPing = 18 + MsgPong = 19 + MsgOpenChannel = 32 + MsgAcceptChannel = 33 + MsgFundingCreated = 34 + MsgFundingSigned = 35 + MsgFundingLocked = 36 + MsgShutdown = 38 + MsgClosingSigned = 39 + MsgUpdateAddHTLC = 128 + MsgUpdateFulfillHTLC = 130 + MsgUpdateFailHTLC = 131 + MsgCommitSig = 132 + MsgRevokeAndAck = 133 + MsgUpdateFee = 134 + MsgUpdateFailMalformedHTLC = 135 + MsgChannelReestablish = 136 + MsgChannelAnnouncement = 256 + MsgNodeAnnouncement = 257 + MsgChannelUpdate = 258 + MsgAnnounceSignatures = 259 + MsgQueryShortChanIDs = 261 + MsgReplyShortChanIDsEnd = 262 + MsgQueryChannelRange = 263 + MsgReplyChannelRange = 264 + MsgGossipTimestampRange = 265 +) + +// String return the string representation of message type. +func (t MessageType) String() string { + switch t { + case MsgInit: + return "Init" + case MsgOpenChannel: + return "MsgOpenChannel" + case MsgAcceptChannel: + return "MsgAcceptChannel" + case MsgFundingCreated: + return "MsgFundingCreated" + case MsgFundingSigned: + return "MsgFundingSigned" + case MsgFundingLocked: + return "FundingLocked" + case MsgShutdown: + return "Shutdown" + case MsgClosingSigned: + return "ClosingSigned" + case MsgUpdateAddHTLC: + return "UpdateAddHTLC" + case MsgUpdateFailHTLC: + return "UpdateFailHTLC" + case MsgUpdateFulfillHTLC: + return "UpdateFulfillHTLC" + case MsgCommitSig: + return "CommitSig" + case MsgRevokeAndAck: + return "RevokeAndAck" + case MsgUpdateFailMalformedHTLC: + return "UpdateFailMalformedHTLC" + case MsgChannelReestablish: + return "ChannelReestablish" + case MsgError: + return "Error" + case MsgChannelAnnouncement: + return "ChannelAnnouncement" + case MsgChannelUpdate: + return "ChannelUpdate" + case MsgNodeAnnouncement: + return "NodeAnnouncement" + case MsgPing: + return "Ping" + case MsgAnnounceSignatures: + return "AnnounceSignatures" + case MsgPong: + return "Pong" + case MsgUpdateFee: + return "UpdateFee" + case MsgQueryShortChanIDs: + return "QueryShortChanIDs" + case MsgReplyShortChanIDsEnd: + return "ReplyShortChanIDsEnd" + case MsgQueryChannelRange: + return "QueryChannelRange" + case MsgReplyChannelRange: + return "ReplyChannelRange" + case MsgGossipTimestampRange: + return "GossipTimestampRange" + default: + return "" + } +} + +// UnknownMessage is an implementation of the error interface that allows the +// creation of an error in response to an unknown message. +type UnknownMessage struct { + messageType MessageType +} + +// Error returns a human readable string describing the error. +// +// This is part of the error interface. +func (u *UnknownMessage) Error() string { + return fmt.Sprintf("unable to parse message of unknown type: %v", + u.messageType) +} + +// Serializable is an interface which defines a lightning wire serializable +// object. +type Serializable interface { + // Decode reads the bytes stream and converts it to the object. + Decode(io.Reader, uint32) error + + // Encode converts object to the bytes stream and write it into the + // writer. + Encode(io.Writer, uint32) error +} + +// Message is an interface that defines a lightning wire protocol message. The +// interface is general in order to allow implementing types full control over +// the representation of its data. +type Message interface { + Serializable + MsgType() MessageType + MaxPayloadLength(uint32) uint32 +} + +// makeEmptyMessage creates a new empty message of the proper concrete type +// based on the passed message type. +func makeEmptyMessage(msgType MessageType) (Message, error) { + var msg Message + + switch msgType { + case MsgInit: + msg = &Init{} + case MsgOpenChannel: + msg = &OpenChannel{} + case MsgAcceptChannel: + msg = &AcceptChannel{} + case MsgFundingCreated: + msg = &FundingCreated{} + case MsgFundingSigned: + msg = &FundingSigned{} + case MsgFundingLocked: + msg = &FundingLocked{} + case MsgShutdown: + msg = &Shutdown{} + case MsgClosingSigned: + msg = &ClosingSigned{} + case MsgUpdateAddHTLC: + msg = &UpdateAddHTLC{} + case MsgUpdateFailHTLC: + msg = &UpdateFailHTLC{} + case MsgUpdateFulfillHTLC: + msg = &UpdateFulfillHTLC{} + case MsgCommitSig: + msg = &CommitSig{} + case MsgRevokeAndAck: + msg = &RevokeAndAck{} + case MsgUpdateFee: + msg = &UpdateFee{} + case MsgUpdateFailMalformedHTLC: + msg = &UpdateFailMalformedHTLC{} + case MsgChannelReestablish: + msg = &ChannelReestablish{} + case MsgError: + msg = &Error{} + case MsgChannelAnnouncement: + msg = &ChannelAnnouncement{} + case MsgChannelUpdate: + msg = &ChannelUpdate{} + case MsgNodeAnnouncement: + msg = &NodeAnnouncement{} + case MsgPing: + msg = &Ping{} + case MsgAnnounceSignatures: + msg = &AnnounceSignatures{} + case MsgPong: + msg = &Pong{} + case MsgQueryShortChanIDs: + msg = &QueryShortChanIDs{} + case MsgReplyShortChanIDsEnd: + msg = &ReplyShortChanIDsEnd{} + case MsgQueryChannelRange: + msg = &QueryChannelRange{} + case MsgReplyChannelRange: + msg = &ReplyChannelRange{} + case MsgGossipTimestampRange: + msg = &GossipTimestampRange{} + default: + return nil, &UnknownMessage{msgType} + } + + return msg, nil +} + +// WriteMessage writes a lightning Message to w including the necessary header +// information and returns the number of bytes written. +func WriteMessage(w io.Writer, msg Message, pver uint32) (int, error) { + totalBytes := 0 + + // Encode the message payload itself into a temporary buffer. + // TODO(roasbeef): create buffer pool + var bw bytes.Buffer + if err := msg.Encode(&bw, pver); err != nil { + return totalBytes, err + } + payload := bw.Bytes() + lenp := len(payload) + + // Enforce maximum overall message payload. + if lenp > MaxMessagePayload { + return totalBytes, fmt.Errorf("message payload is too large - "+ + "encoded %d bytes, but maximum message payload is %d bytes", + lenp, MaxMessagePayload) + } + + // Enforce maximum message payload on the message type. + mpl := msg.MaxPayloadLength(pver) + if uint32(lenp) > mpl { + return totalBytes, fmt.Errorf("message payload is too large - "+ + "encoded %d bytes, but maximum message payload of "+ + "type %v is %d bytes", lenp, msg.MsgType(), mpl) + } + + // With the initial sanity checks complete, we'll now write out the + // message type itself. + var mType [2]byte + binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType())) + n, err := w.Write(mType[:]) + totalBytes += n + if err != nil { + return totalBytes, err + } + + // With the message type written, we'll now write out the raw payload + // itself. + n, err = w.Write(payload) + totalBytes += n + + return totalBytes, err +} + +// ReadMessage reads, validates, and parses the next Lightning message from r +// for the provided protocol version. +func ReadMessage(r io.Reader, pver uint32) (Message, error) { + // First, we'll read out the first two bytes of the message so we can + // create the proper empty message. + var mType [2]byte + if _, err := io.ReadFull(r, mType[:]); err != nil { + return nil, err + } + + msgType := MessageType(binary.BigEndian.Uint16(mType[:])) + + // Now that we know the target message type, we can create the proper + // empty message type and decode the message into it. + msg, err := makeEmptyMessage(msgType) + if err != nil { + return nil, err + } + if err := msg.Decode(r, pver); err != nil { + return nil, err + } + + return msg, nil +} diff --git a/channeldb/migration/lnwire21/msat.go b/channeldb/migration/lnwire21/msat.go new file mode 100644 index 00000000..d3789dfa --- /dev/null +++ b/channeldb/migration/lnwire21/msat.go @@ -0,0 +1,51 @@ +package lnwire + +import ( + "fmt" + + "github.com/btcsuite/btcutil" +) + +const ( + // mSatScale is a value that's used to scale satoshis to milli-satoshis, and + // the other way around. + mSatScale uint64 = 1000 + + // MaxMilliSatoshi is the maximum number of msats that can be expressed + // in this data type. + MaxMilliSatoshi = ^MilliSatoshi(0) +) + +// MilliSatoshi are the native unit of the Lightning Network. A milli-satoshi +// is simply 1/1000th of a satoshi. There are 1000 milli-satoshis in a single +// satoshi. Within the network, all HTLC payments are denominated in +// milli-satoshis. As milli-satoshis aren't deliverable on the native +// blockchain, before settling to broadcasting, the values are rounded down to +// the nearest satoshi. +type MilliSatoshi uint64 + +// NewMSatFromSatoshis creates a new MilliSatoshi instance from a target amount +// of satoshis. +func NewMSatFromSatoshis(sat btcutil.Amount) MilliSatoshi { + return MilliSatoshi(uint64(sat) * mSatScale) +} + +// ToBTC converts the target MilliSatoshi amount to its corresponding value +// when expressed in BTC. +func (m MilliSatoshi) ToBTC() float64 { + sat := m.ToSatoshis() + return sat.ToBTC() +} + +// ToSatoshis converts the target MilliSatoshi amount to satoshis. Simply, this +// sheds a factor of 1000 from the mSAT amount in order to convert it to SAT. +func (m MilliSatoshi) ToSatoshis() btcutil.Amount { + return btcutil.Amount(uint64(m) / mSatScale) +} + +// String returns the string representation of the mSAT amount. +func (m MilliSatoshi) String() string { + return fmt.Sprintf("%v mSAT", uint64(m)) +} + +// TODO(roasbeef): extend with arithmetic operations? diff --git a/channeldb/migration/lnwire21/netaddress.go b/channeldb/migration/lnwire21/netaddress.go new file mode 100644 index 00000000..f31ac1f9 --- /dev/null +++ b/channeldb/migration/lnwire21/netaddress.go @@ -0,0 +1,54 @@ +package lnwire + +import ( + "fmt" + "net" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/wire" +) + +// NetAddress represents information pertaining to the identity and network +// reachability of a peer. Information stored includes the node's identity +// public key for establishing a confidential+authenticated connection, the +// service bits it supports, and a TCP address the node is reachable at. +// +// TODO(roasbeef): merge with LinkNode in some fashion +type NetAddress struct { + // IdentityKey is the long-term static public key for a node. This node is + // used throughout the network as a node's identity key. It is used to + // authenticate any data sent to the network on behalf of the node, and + // additionally to establish a confidential+authenticated connection with + // the node. + IdentityKey *btcec.PublicKey + + // Address is the IP address and port of the node. This is left + // general so that multiple implementations can be used. + Address net.Addr + + // ChainNet is the Bitcoin network this node is associated with. + // TODO(roasbeef): make a slice in the future for multi-chain + ChainNet wire.BitcoinNet +} + +// A compile time assertion to ensure that NetAddress meets the net.Addr +// interface. +var _ net.Addr = (*NetAddress)(nil) + +// String returns a human readable string describing the target NetAddress. The +// current string format is: @host. +// +// This part of the net.Addr interface. +func (n *NetAddress) String() string { + // TODO(roasbeef): use base58? + pubkey := n.IdentityKey.SerializeCompressed() + + return fmt.Sprintf("%x@%v", pubkey, n.Address) +} + +// Network returns the name of the network this address is bound to. +// +// This part of the net.Addr interface. +func (n *NetAddress) Network() string { + return n.Address.Network() +} diff --git a/channeldb/migration/lnwire21/node_announcement.go b/channeldb/migration/lnwire21/node_announcement.go new file mode 100644 index 00000000..35534352 --- /dev/null +++ b/channeldb/migration/lnwire21/node_announcement.go @@ -0,0 +1,192 @@ +package lnwire + +import ( + "bytes" + "fmt" + "image/color" + "io" + "io/ioutil" + "net" + "unicode/utf8" +) + +// ErrUnknownAddrType is an error returned if we encounter an unknown address type +// when parsing addresses. +type ErrUnknownAddrType struct { + addrType addressType +} + +// Error returns a human readable string describing the error. +// +// NOTE: implements the error interface. +func (e ErrUnknownAddrType) Error() string { + return fmt.Sprintf("unknown address type: %v", e.addrType) +} + +// ErrInvalidNodeAlias is an error returned if a node alias we parse on the +// wire is invalid, as in it has non UTF-8 characters. +type ErrInvalidNodeAlias struct{} + +// Error returns a human readable string describing the error. +// +// NOTE: implements the error interface. +func (e ErrInvalidNodeAlias) Error() string { + return "node alias has non-utf8 characters" +} + +// NodeAlias is a hex encoded UTF-8 string that may be displayed as an +// alternative to the node's ID. Notice that aliases are not unique and may be +// freely chosen by the node operators. +type NodeAlias [32]byte + +// NewNodeAlias creates a new instance of a NodeAlias. Verification is +// performed on the passed string to ensure it meets the alias requirements. +func NewNodeAlias(s string) (NodeAlias, error) { + var n NodeAlias + + if len(s) > 32 { + return n, fmt.Errorf("alias too large: max is %v, got %v", 32, + len(s)) + } + + if !utf8.ValidString(s) { + return n, &ErrInvalidNodeAlias{} + } + + copy(n[:], []byte(s)) + return n, nil +} + +// String returns a utf8 string representation of the alias bytes. +func (n NodeAlias) String() string { + // Trim trailing zero-bytes for presentation + return string(bytes.Trim(n[:], "\x00")) +} + +// NodeAnnouncement message is used to announce the presence of a Lightning +// node and also to signal that the node is accepting incoming connections. +// Each NodeAnnouncement authenticating the advertised information within the +// announcement via a signature using the advertised node pubkey. +type NodeAnnouncement struct { + // Signature is used to prove the ownership of node id. + Signature Sig + + // Features is the list of protocol features this node supports. + Features *RawFeatureVector + + // Timestamp allows ordering in the case of multiple announcements. + Timestamp uint32 + + // NodeID is a public key which is used as node identification. + NodeID [33]byte + + // RGBColor is used to customize their node's appearance in maps and + // graphs + RGBColor color.RGBA + + // Alias is used to customize their node's appearance in maps and + // graphs + Alias NodeAlias + + // Address includes two specification fields: 'ipv6' and 'port' on + // which the node is accepting incoming connections. + Addresses []net.Addr + + // ExtraOpaqueData is the set of data that was appended to this + // message, some of which we may not actually know how to iterate or + // parse. By holding onto this data, we ensure that we're able to + // properly validate the set of signatures that cover these new fields, + // and ensure we're able to make upgrades to the network in a forwards + // compatible manner. + ExtraOpaqueData []byte +} + +// A compile time check to ensure NodeAnnouncement implements the +// lnwire.Message interface. +var _ Message = (*NodeAnnouncement)(nil) + +// Decode deserializes a serialized NodeAnnouncement stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *NodeAnnouncement) Decode(r io.Reader, pver uint32) error { + err := ReadElements(r, + &a.Signature, + &a.Features, + &a.Timestamp, + &a.NodeID, + &a.RGBColor, + &a.Alias, + &a.Addresses, + ) + if err != nil { + return err + } + + // Now that we've read out all the fields that we explicitly know of, + // we'll collect the remainder into the ExtraOpaqueData field. If there + // aren't any bytes, then we'll snip off the slice to avoid carrying + // around excess capacity. + a.ExtraOpaqueData, err = ioutil.ReadAll(r) + if err != nil { + return err + } + if len(a.ExtraOpaqueData) == 0 { + a.ExtraOpaqueData = nil + } + + return nil +} + +// Encode serializes the target NodeAnnouncement into the passed io.Writer +// observing the protocol version specified. +// +func (a *NodeAnnouncement) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + a.Signature, + a.Features, + a.Timestamp, + a.NodeID, + a.RGBColor, + a.Alias, + a.Addresses, + a.ExtraOpaqueData, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (a *NodeAnnouncement) MsgType() MessageType { + return MsgNodeAnnouncement +} + +// MaxPayloadLength returns the maximum allowed payload size for this message +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (a *NodeAnnouncement) MaxPayloadLength(pver uint32) uint32 { + return 65533 +} + +// DataToSign returns the part of the message that should be signed. +func (a *NodeAnnouncement) DataToSign() ([]byte, error) { + + // We should not include the signatures itself. + var w bytes.Buffer + err := WriteElements(&w, + a.Features, + a.Timestamp, + a.NodeID, + a.RGBColor, + a.Alias[:], + a.Addresses, + a.ExtraOpaqueData, + ) + if err != nil { + return nil, err + } + + return w.Bytes(), nil +} diff --git a/channeldb/migration/lnwire21/onion_error.go b/channeldb/migration/lnwire21/onion_error.go new file mode 100644 index 00000000..35555e26 --- /dev/null +++ b/channeldb/migration/lnwire21/onion_error.go @@ -0,0 +1,1428 @@ +package lnwire + +import ( + "bufio" + "crypto/sha256" + "encoding/binary" + "fmt" + "io" + + "bytes" + + "github.com/davecgh/go-spew/spew" + "github.com/go-errors/errors" + "github.com/lightningnetwork/lnd/tlv" +) + +// FailureMessage represents the onion failure object identified by its unique +// failure code. +type FailureMessage interface { + // Code returns a failure code describing the exact nature of the + // error. + Code() FailCode + + // Error returns a human readable string describing the error. With + // this method, the FailureMessage interface meets the built-in error + // interface. + Error() string +} + +// FailureMessageLength is the size of the failure message plus the size of +// padding. The FailureMessage message should always be EXACTLY this size. +const FailureMessageLength = 256 + +const ( + // FlagBadOnion error flag describes an unparsable, encrypted by + // previous node. + FlagBadOnion FailCode = 0x8000 + + // FlagPerm error flag indicates a permanent failure. + FlagPerm FailCode = 0x4000 + + // FlagNode error flag indicates a node failure. + FlagNode FailCode = 0x2000 + + // FlagUpdate error flag indicates a new channel update is enclosed + // within the error. + FlagUpdate FailCode = 0x1000 +) + +// FailCode specifies the precise reason that an upstream HTLC was canceled. +// Each UpdateFailHTLC message carries a FailCode which is to be passed +// backwards, encrypted at each step back to the source of the HTLC within the +// route. +type FailCode uint16 + +// The currently defined onion failure types within this current version of the +// Lightning protocol. +const ( + CodeNone FailCode = 0 + CodeInvalidRealm = FlagBadOnion | 1 + CodeTemporaryNodeFailure = FlagNode | 2 + CodePermanentNodeFailure = FlagPerm | FlagNode | 2 + CodeRequiredNodeFeatureMissing = FlagPerm | FlagNode | 3 + CodeInvalidOnionVersion = FlagBadOnion | FlagPerm | 4 + CodeInvalidOnionHmac = FlagBadOnion | FlagPerm | 5 + CodeInvalidOnionKey = FlagBadOnion | FlagPerm | 6 + CodeTemporaryChannelFailure = FlagUpdate | 7 + CodePermanentChannelFailure = FlagPerm | 8 + CodeRequiredChannelFeatureMissing = FlagPerm | 9 + CodeUnknownNextPeer = FlagPerm | 10 + CodeAmountBelowMinimum = FlagUpdate | 11 + CodeFeeInsufficient = FlagUpdate | 12 + CodeIncorrectCltvExpiry = FlagUpdate | 13 + CodeExpiryTooSoon = FlagUpdate | 14 + CodeChannelDisabled = FlagUpdate | 20 + CodeIncorrectOrUnknownPaymentDetails = FlagPerm | 15 + CodeIncorrectPaymentAmount = FlagPerm | 16 + CodeFinalExpiryTooSoon FailCode = 17 + CodeFinalIncorrectCltvExpiry FailCode = 18 + CodeFinalIncorrectHtlcAmount FailCode = 19 + CodeExpiryTooFar FailCode = 21 + CodeInvalidOnionPayload = FlagPerm | 22 + CodeMPPTimeout FailCode = 23 +) + +// String returns the string representation of the failure code. +func (c FailCode) String() string { + switch c { + case CodeInvalidRealm: + return "InvalidRealm" + + case CodeTemporaryNodeFailure: + return "TemporaryNodeFailure" + + case CodePermanentNodeFailure: + return "PermanentNodeFailure" + + case CodeRequiredNodeFeatureMissing: + return "RequiredNodeFeatureMissing" + + case CodeInvalidOnionVersion: + return "InvalidOnionVersion" + + case CodeInvalidOnionHmac: + return "InvalidOnionHmac" + + case CodeInvalidOnionKey: + return "InvalidOnionKey" + + case CodeTemporaryChannelFailure: + return "TemporaryChannelFailure" + + case CodePermanentChannelFailure: + return "PermanentChannelFailure" + + case CodeRequiredChannelFeatureMissing: + return "RequiredChannelFeatureMissing" + + case CodeUnknownNextPeer: + return "UnknownNextPeer" + + case CodeAmountBelowMinimum: + return "AmountBelowMinimum" + + case CodeFeeInsufficient: + return "FeeInsufficient" + + case CodeIncorrectCltvExpiry: + return "IncorrectCltvExpiry" + + case CodeIncorrectPaymentAmount: + return "IncorrectPaymentAmount" + + case CodeExpiryTooSoon: + return "ExpiryTooSoon" + + case CodeChannelDisabled: + return "ChannelDisabled" + + case CodeIncorrectOrUnknownPaymentDetails: + return "IncorrectOrUnknownPaymentDetails" + + case CodeFinalExpiryTooSoon: + return "FinalExpiryTooSoon" + + case CodeFinalIncorrectCltvExpiry: + return "FinalIncorrectCltvExpiry" + + case CodeFinalIncorrectHtlcAmount: + return "FinalIncorrectHtlcAmount" + + case CodeExpiryTooFar: + return "ExpiryTooFar" + + case CodeInvalidOnionPayload: + return "InvalidOnionPayload" + + case CodeMPPTimeout: + return "MPPTimeout" + + default: + return "" + } +} + +// FailInvalidRealm is returned if the realm byte is unknown. +// +// NOTE: May be returned by any node in the payment route. +type FailInvalidRealm struct{} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailInvalidRealm) Error() string { + return f.Code().String() +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailInvalidRealm) Code() FailCode { + return CodeInvalidRealm +} + +// FailTemporaryNodeFailure is returned if an otherwise unspecified transient +// error occurs for the entire node. +// +// NOTE: May be returned by any node in the payment route. +type FailTemporaryNodeFailure struct{} + +// Code returns the failure unique code. +// NOTE: Part of the FailureMessage interface. +func (f *FailTemporaryNodeFailure) Code() FailCode { + return CodeTemporaryNodeFailure +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailTemporaryNodeFailure) Error() string { + return f.Code().String() +} + +// FailPermanentNodeFailure is returned if an otherwise unspecified permanent +// error occurs for the entire node. +// +// NOTE: May be returned by any node in the payment route. +type FailPermanentNodeFailure struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailPermanentNodeFailure) Code() FailCode { + return CodePermanentNodeFailure +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailPermanentNodeFailure) Error() string { + return f.Code().String() +} + +// FailRequiredNodeFeatureMissing is returned if a node has requirement +// advertised in its node_announcement features which were not present in the +// onion. +// +// NOTE: May be returned by any node in the payment route. +type FailRequiredNodeFeatureMissing struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailRequiredNodeFeatureMissing) Code() FailCode { + return CodeRequiredNodeFeatureMissing +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailRequiredNodeFeatureMissing) Error() string { + return f.Code().String() +} + +// FailPermanentChannelFailure is return if an otherwise unspecified permanent +// error occurs for the outgoing channel (eg. channel (recently). +// +// NOTE: May be returned by any node in the payment route. +type FailPermanentChannelFailure struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailPermanentChannelFailure) Code() FailCode { + return CodePermanentChannelFailure +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailPermanentChannelFailure) Error() string { + return f.Code().String() +} + +// FailRequiredChannelFeatureMissing is returned if the outgoing channel has a +// requirement advertised in its channel announcement features which were not +// present in the onion. +// +// NOTE: May only be returned by intermediate nodes. +type FailRequiredChannelFeatureMissing struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailRequiredChannelFeatureMissing) Code() FailCode { + return CodeRequiredChannelFeatureMissing +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailRequiredChannelFeatureMissing) Error() string { + return f.Code().String() +} + +// FailUnknownNextPeer is returned if the next peer specified by the onion is +// not known. +// +// NOTE: May only be returned by intermediate nodes. +type FailUnknownNextPeer struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailUnknownNextPeer) Code() FailCode { + return CodeUnknownNextPeer +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailUnknownNextPeer) Error() string { + return f.Code().String() +} + +// FailIncorrectPaymentAmount is returned if the amount paid is less than the +// amount expected, the final node MUST fail the HTLC. If the amount paid is +// more than twice the amount expected, the final node SHOULD fail the HTLC. +// This allows the sender to reduce information leakage by altering the amount, +// without allowing accidental gross overpayment. +// +// NOTE: May only be returned by the final node in the path. +type FailIncorrectPaymentAmount struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailIncorrectPaymentAmount) Code() FailCode { + return CodeIncorrectPaymentAmount +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailIncorrectPaymentAmount) Error() string { + return f.Code().String() +} + +// FailIncorrectDetails is returned for two reasons: +// +// 1) if the payment hash has already been paid, the final node MAY treat the +// payment hash as unknown, or may succeed in accepting the HTLC. If the +// payment hash is unknown, the final node MUST fail the HTLC. +// +// 2) if the amount paid is less than the amount expected, the final node MUST +// fail the HTLC. If the amount paid is more than twice the amount expected, +// the final node SHOULD fail the HTLC. This allows the sender to reduce +// information leakage by altering the amount, without allowing accidental +// gross overpayment. +// +// NOTE: May only be returned by the final node in the path. +type FailIncorrectDetails struct { + // amount is the value of the extended HTLC. + amount MilliSatoshi + + // height is the block height when the htlc was received. + height uint32 +} + +// NewFailIncorrectDetails makes a new instance of the FailIncorrectDetails +// error bound to the specified HTLC amount and acceptance height. +func NewFailIncorrectDetails(amt MilliSatoshi, + height uint32) *FailIncorrectDetails { + + return &FailIncorrectDetails{ + amount: amt, + height: height, + } +} + +// Amount is the value of the extended HTLC. +func (f *FailIncorrectDetails) Amount() MilliSatoshi { + return f.amount +} + +// Height is the block height when the htlc was received. +func (f *FailIncorrectDetails) Height() uint32 { + return f.height +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailIncorrectDetails) Code() FailCode { + return CodeIncorrectOrUnknownPaymentDetails +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailIncorrectDetails) Error() string { + return fmt.Sprintf( + "%v(amt=%v, height=%v)", CodeIncorrectOrUnknownPaymentDetails, + f.amount, f.height, + ) +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailIncorrectDetails) Decode(r io.Reader, pver uint32) error { + err := ReadElement(r, &f.amount) + switch { + // This is an optional tack on that was added later in the protocol. As + // a result, older nodes may not include this value. We'll account for + // this by checking for io.EOF here which means that no bytes were read + // at all. + case err == io.EOF: + return nil + + case err != nil: + return err + } + + // At a later stage, the height field was also tacked on. We need to + // check for io.EOF here as well. + err = ReadElement(r, &f.height) + switch { + case err == io.EOF: + return nil + + case err != nil: + return err + } + + return nil +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailIncorrectDetails) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, f.amount, f.height) +} + +// FailFinalExpiryTooSoon is returned if the cltv_expiry is too low, the final +// node MUST fail the HTLC. +// +// NOTE: May only be returned by the final node in the path. +type FailFinalExpiryTooSoon struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailFinalExpiryTooSoon) Code() FailCode { + return CodeFinalExpiryTooSoon +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailFinalExpiryTooSoon) Error() string { + return f.Code().String() +} + +// NewFinalExpiryTooSoon creates new instance of the FailFinalExpiryTooSoon. +func NewFinalExpiryTooSoon() *FailFinalExpiryTooSoon { + return &FailFinalExpiryTooSoon{} +} + +// FailInvalidOnionVersion is returned if the onion version byte is unknown. +// +// NOTE: May be returned only by intermediate nodes. +type FailInvalidOnionVersion struct { + // OnionSHA256 hash of the onion blob which haven't been proceeded. + OnionSHA256 [sha256.Size]byte +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailInvalidOnionVersion) Error() string { + return fmt.Sprintf("InvalidOnionVersion(onion_sha=%x)", f.OnionSHA256[:]) +} + +// NewInvalidOnionVersion creates new instance of the FailInvalidOnionVersion. +func NewInvalidOnionVersion(onion []byte) *FailInvalidOnionVersion { + return &FailInvalidOnionVersion{OnionSHA256: sha256.Sum256(onion)} +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailInvalidOnionVersion) Code() FailCode { + return CodeInvalidOnionVersion +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailInvalidOnionVersion) Decode(r io.Reader, pver uint32) error { + return ReadElement(r, f.OnionSHA256[:]) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailInvalidOnionVersion) Encode(w io.Writer, pver uint32) error { + return WriteElement(w, f.OnionSHA256[:]) +} + +// FailInvalidOnionHmac is return if the onion HMAC is incorrect. +// +// NOTE: May only be returned by intermediate nodes. +type FailInvalidOnionHmac struct { + // OnionSHA256 hash of the onion blob which haven't been proceeded. + OnionSHA256 [sha256.Size]byte +} + +// NewInvalidOnionHmac creates new instance of the FailInvalidOnionHmac. +func NewInvalidOnionHmac(onion []byte) *FailInvalidOnionHmac { + return &FailInvalidOnionHmac{OnionSHA256: sha256.Sum256(onion)} +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailInvalidOnionHmac) Code() FailCode { + return CodeInvalidOnionHmac +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailInvalidOnionHmac) Decode(r io.Reader, pver uint32) error { + return ReadElement(r, f.OnionSHA256[:]) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailInvalidOnionHmac) Encode(w io.Writer, pver uint32) error { + return WriteElement(w, f.OnionSHA256[:]) +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailInvalidOnionHmac) Error() string { + return fmt.Sprintf("InvalidOnionHMAC(onion_sha=%x)", f.OnionSHA256[:]) +} + +// FailInvalidOnionKey is return if the ephemeral key in the onion is +// unparsable. +// +// NOTE: May only be returned by intermediate nodes. +type FailInvalidOnionKey struct { + // OnionSHA256 hash of the onion blob which haven't been proceeded. + OnionSHA256 [sha256.Size]byte +} + +// NewInvalidOnionKey creates new instance of the FailInvalidOnionKey. +func NewInvalidOnionKey(onion []byte) *FailInvalidOnionKey { + return &FailInvalidOnionKey{OnionSHA256: sha256.Sum256(onion)} +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailInvalidOnionKey) Code() FailCode { + return CodeInvalidOnionKey +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailInvalidOnionKey) Decode(r io.Reader, pver uint32) error { + return ReadElement(r, f.OnionSHA256[:]) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailInvalidOnionKey) Encode(w io.Writer, pver uint32) error { + return WriteElement(w, f.OnionSHA256[:]) +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailInvalidOnionKey) Error() string { + return fmt.Sprintf("InvalidOnionKey(onion_sha=%x)", f.OnionSHA256[:]) +} + +// parseChannelUpdateCompatabilityMode will attempt to parse a channel updated +// encoded into an onion error payload in two ways. First, we'll try the +// compatibility oriented version wherein we'll _skip_ the length prefixing on +// the channel update message. Older versions of c-lighting do this so we'll +// attempt to parse these messages in order to retain compatibility. If we're +// unable to pull out a fully valid version, then we'll fall back to the +// regular parsing mechanism which includes the length prefix an NO type byte. +func parseChannelUpdateCompatabilityMode(r *bufio.Reader, + chanUpdate *ChannelUpdate, pver uint32) error { + + // We'll peek out two bytes from the buffer without advancing the + // buffer so we can decide how to parse the remainder of it. + maybeTypeBytes, err := r.Peek(2) + if err != nil { + return err + } + + // Some nodes well prefix an additional set of bytes in front of their + // channel updates. These bytes will _almost_ always be 258 or the type + // of the ChannelUpdate message. + typeInt := binary.BigEndian.Uint16(maybeTypeBytes) + if typeInt == MsgChannelUpdate { + // At this point it's likely the case that this is a channel + // update message with its type prefixed, so we'll snip off the + // first two bytes and parse it as normal. + var throwAwayTypeBytes [2]byte + _, err := r.Read(throwAwayTypeBytes[:]) + if err != nil { + return err + } + } + + // At this pint, we've either decided to keep the entire thing, or snip + // off the first two bytes. In either case, we can just read it as + // normal. + return chanUpdate.Decode(r, pver) +} + +// FailTemporaryChannelFailure is if an otherwise unspecified transient error +// occurs for the outgoing channel (eg. channel capacity reached, too many +// in-flight htlcs) +// +// NOTE: May only be returned by intermediate nodes. +type FailTemporaryChannelFailure struct { + // Update is used to update information about state of the channel + // which caused the failure. + // + // NOTE: This field is optional. + Update *ChannelUpdate +} + +// NewTemporaryChannelFailure creates new instance of the FailTemporaryChannelFailure. +func NewTemporaryChannelFailure(update *ChannelUpdate) *FailTemporaryChannelFailure { + return &FailTemporaryChannelFailure{Update: update} +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailTemporaryChannelFailure) Code() FailCode { + return CodeTemporaryChannelFailure +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailTemporaryChannelFailure) Error() string { + if f.Update == nil { + return f.Code().String() + } + + return fmt.Sprintf("TemporaryChannelFailure(update=%v)", + spew.Sdump(f.Update)) +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailTemporaryChannelFailure) Decode(r io.Reader, pver uint32) error { + var length uint16 + err := ReadElement(r, &length) + if err != nil { + return err + } + + if length != 0 { + f.Update = &ChannelUpdate{} + return parseChannelUpdateCompatabilityMode( + bufio.NewReader(r), f.Update, pver, + ) + } + + return nil +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailTemporaryChannelFailure) Encode(w io.Writer, pver uint32) error { + var payload []byte + if f.Update != nil { + var bw bytes.Buffer + if err := f.Update.Encode(&bw, pver); err != nil { + return err + } + payload = bw.Bytes() + } + + if err := WriteElement(w, uint16(len(payload))); err != nil { + return err + } + + _, err := w.Write(payload) + return err +} + +// FailAmountBelowMinimum is returned if the HTLC does not reach the current +// minimum amount, we tell them the amount of the incoming HTLC and the current +// channel setting for the outgoing channel. +// +// NOTE: May only be returned by the intermediate nodes in the path. +type FailAmountBelowMinimum struct { + // HtlcMsat is the wrong amount of the incoming HTLC. + HtlcMsat MilliSatoshi + + // Update is used to update information about state of the channel + // which caused the failure. + Update ChannelUpdate +} + +// NewAmountBelowMinimum creates new instance of the FailAmountBelowMinimum. +func NewAmountBelowMinimum(htlcMsat MilliSatoshi, + update ChannelUpdate) *FailAmountBelowMinimum { + + return &FailAmountBelowMinimum{ + HtlcMsat: htlcMsat, + Update: update, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailAmountBelowMinimum) Code() FailCode { + return CodeAmountBelowMinimum +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailAmountBelowMinimum) Error() string { + return fmt.Sprintf("AmountBelowMinimum(amt=%v, update=%v", f.HtlcMsat, + spew.Sdump(f.Update)) +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailAmountBelowMinimum) Decode(r io.Reader, pver uint32) error { + if err := ReadElement(r, &f.HtlcMsat); err != nil { + return err + } + + var length uint16 + if err := ReadElement(r, &length); err != nil { + return err + } + + f.Update = ChannelUpdate{} + return parseChannelUpdateCompatabilityMode( + bufio.NewReader(r), &f.Update, pver, + ) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailAmountBelowMinimum) Encode(w io.Writer, pver uint32) error { + if err := WriteElement(w, f.HtlcMsat); err != nil { + return err + } + + return writeOnionErrorChanUpdate(w, &f.Update, pver) +} + +// FailFeeInsufficient is returned if the HTLC does not pay sufficient fee, we +// tell them the amount of the incoming HTLC and the current channel setting +// for the outgoing channel. +// +// NOTE: May only be returned by intermediate nodes. +type FailFeeInsufficient struct { + // HtlcMsat is the wrong amount of the incoming HTLC. + HtlcMsat MilliSatoshi + + // Update is used to update information about state of the channel + // which caused the failure. + Update ChannelUpdate +} + +// NewFeeInsufficient creates new instance of the FailFeeInsufficient. +func NewFeeInsufficient(htlcMsat MilliSatoshi, + update ChannelUpdate) *FailFeeInsufficient { + return &FailFeeInsufficient{ + HtlcMsat: htlcMsat, + Update: update, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailFeeInsufficient) Code() FailCode { + return CodeFeeInsufficient +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailFeeInsufficient) Error() string { + return fmt.Sprintf("FeeInsufficient(htlc_amt==%v, update=%v", f.HtlcMsat, + spew.Sdump(f.Update)) +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailFeeInsufficient) Decode(r io.Reader, pver uint32) error { + if err := ReadElement(r, &f.HtlcMsat); err != nil { + return err + } + + var length uint16 + if err := ReadElement(r, &length); err != nil { + return err + } + + f.Update = ChannelUpdate{} + return parseChannelUpdateCompatabilityMode( + bufio.NewReader(r), &f.Update, pver, + ) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailFeeInsufficient) Encode(w io.Writer, pver uint32) error { + if err := WriteElement(w, f.HtlcMsat); err != nil { + return err + } + + return writeOnionErrorChanUpdate(w, &f.Update, pver) +} + +// FailIncorrectCltvExpiry is returned if outgoing cltv value does not match +// the update add htlc's cltv expiry minus cltv expiry delta for the outgoing +// channel, we tell them the cltv expiry and the current channel setting for +// the outgoing channel. +// +// NOTE: May only be returned by intermediate nodes. +type FailIncorrectCltvExpiry struct { + // CltvExpiry is the wrong absolute timeout in blocks, after which + // outgoing HTLC expires. + CltvExpiry uint32 + + // Update is used to update information about state of the channel + // which caused the failure. + Update ChannelUpdate +} + +// NewIncorrectCltvExpiry creates new instance of the FailIncorrectCltvExpiry. +func NewIncorrectCltvExpiry(cltvExpiry uint32, + update ChannelUpdate) *FailIncorrectCltvExpiry { + + return &FailIncorrectCltvExpiry{ + CltvExpiry: cltvExpiry, + Update: update, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailIncorrectCltvExpiry) Code() FailCode { + return CodeIncorrectCltvExpiry +} + +func (f *FailIncorrectCltvExpiry) Error() string { + return fmt.Sprintf("IncorrectCltvExpiry(expiry=%v, update=%v", + f.CltvExpiry, spew.Sdump(f.Update)) +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailIncorrectCltvExpiry) Decode(r io.Reader, pver uint32) error { + if err := ReadElement(r, &f.CltvExpiry); err != nil { + return err + } + + var length uint16 + if err := ReadElement(r, &length); err != nil { + return err + } + + f.Update = ChannelUpdate{} + return parseChannelUpdateCompatabilityMode( + bufio.NewReader(r), &f.Update, pver, + ) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailIncorrectCltvExpiry) Encode(w io.Writer, pver uint32) error { + if err := WriteElement(w, f.CltvExpiry); err != nil { + return err + } + + return writeOnionErrorChanUpdate(w, &f.Update, pver) +} + +// FailExpiryTooSoon is returned if the ctlv-expiry is too near, we tell them +// the current channel setting for the outgoing channel. +// +// NOTE: May only be returned by intermediate nodes. +type FailExpiryTooSoon struct { + // Update is used to update information about state of the channel + // which caused the failure. + Update ChannelUpdate +} + +// NewExpiryTooSoon creates new instance of the FailExpiryTooSoon. +func NewExpiryTooSoon(update ChannelUpdate) *FailExpiryTooSoon { + return &FailExpiryTooSoon{ + Update: update, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailExpiryTooSoon) Code() FailCode { + return CodeExpiryTooSoon +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailExpiryTooSoon) Error() string { + return fmt.Sprintf("ExpiryTooSoon(update=%v", spew.Sdump(f.Update)) +} + +// Decode decodes the failure from l stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailExpiryTooSoon) Decode(r io.Reader, pver uint32) error { + var length uint16 + if err := ReadElement(r, &length); err != nil { + return err + } + + f.Update = ChannelUpdate{} + return parseChannelUpdateCompatabilityMode( + bufio.NewReader(r), &f.Update, pver, + ) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailExpiryTooSoon) Encode(w io.Writer, pver uint32) error { + return writeOnionErrorChanUpdate(w, &f.Update, pver) +} + +// FailChannelDisabled is returned if the channel is disabled, we tell them the +// current channel setting for the outgoing channel. +// +// NOTE: May only be returned by intermediate nodes. +type FailChannelDisabled struct { + // Flags least-significant bit must be set to 0 if the creating node + // corresponds to the first node in the previously sent channel + // announcement and 1 otherwise. + Flags uint16 + + // Update is used to update information about state of the channel + // which caused the failure. + Update ChannelUpdate +} + +// NewChannelDisabled creates new instance of the FailChannelDisabled. +func NewChannelDisabled(flags uint16, update ChannelUpdate) *FailChannelDisabled { + return &FailChannelDisabled{ + Flags: flags, + Update: update, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailChannelDisabled) Code() FailCode { + return CodeChannelDisabled +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailChannelDisabled) Error() string { + return fmt.Sprintf("ChannelDisabled(flags=%v, update=%v", f.Flags, + spew.Sdump(f.Update)) +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailChannelDisabled) Decode(r io.Reader, pver uint32) error { + if err := ReadElement(r, &f.Flags); err != nil { + return err + } + + var length uint16 + if err := ReadElement(r, &length); err != nil { + return err + } + + f.Update = ChannelUpdate{} + return parseChannelUpdateCompatabilityMode( + bufio.NewReader(r), &f.Update, pver, + ) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailChannelDisabled) Encode(w io.Writer, pver uint32) error { + if err := WriteElement(w, f.Flags); err != nil { + return err + } + + return writeOnionErrorChanUpdate(w, &f.Update, pver) +} + +// FailFinalIncorrectCltvExpiry is returned if the outgoing_cltv_value does not +// match the ctlv_expiry of the HTLC at the final hop. +// +// NOTE: might be returned by final node only. +type FailFinalIncorrectCltvExpiry struct { + // CltvExpiry is the wrong absolute timeout in blocks, after which + // outgoing HTLC expires. + CltvExpiry uint32 +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailFinalIncorrectCltvExpiry) Error() string { + return fmt.Sprintf("FinalIncorrectCltvExpiry(expiry=%v)", f.CltvExpiry) +} + +// NewFinalIncorrectCltvExpiry creates new instance of the +// FailFinalIncorrectCltvExpiry. +func NewFinalIncorrectCltvExpiry(cltvExpiry uint32) *FailFinalIncorrectCltvExpiry { + return &FailFinalIncorrectCltvExpiry{ + CltvExpiry: cltvExpiry, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailFinalIncorrectCltvExpiry) Code() FailCode { + return CodeFinalIncorrectCltvExpiry +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailFinalIncorrectCltvExpiry) Decode(r io.Reader, pver uint32) error { + return ReadElement(r, &f.CltvExpiry) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailFinalIncorrectCltvExpiry) Encode(w io.Writer, pver uint32) error { + return WriteElement(w, f.CltvExpiry) +} + +// FailFinalIncorrectHtlcAmount is returned if the amt_to_forward is higher +// than incoming_htlc_amt of the HTLC at the final hop. +// +// NOTE: May only be returned by the final node. +type FailFinalIncorrectHtlcAmount struct { + // IncomingHTLCAmount is the wrong forwarded htlc amount. + IncomingHTLCAmount MilliSatoshi +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailFinalIncorrectHtlcAmount) Error() string { + return fmt.Sprintf("FinalIncorrectHtlcAmount(amt=%v)", + f.IncomingHTLCAmount) +} + +// NewFinalIncorrectHtlcAmount creates new instance of the +// FailFinalIncorrectHtlcAmount. +func NewFinalIncorrectHtlcAmount(amount MilliSatoshi) *FailFinalIncorrectHtlcAmount { + return &FailFinalIncorrectHtlcAmount{ + IncomingHTLCAmount: amount, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailFinalIncorrectHtlcAmount) Code() FailCode { + return CodeFinalIncorrectHtlcAmount +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailFinalIncorrectHtlcAmount) Decode(r io.Reader, pver uint32) error { + return ReadElement(r, &f.IncomingHTLCAmount) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *FailFinalIncorrectHtlcAmount) Encode(w io.Writer, pver uint32) error { + return WriteElement(w, f.IncomingHTLCAmount) +} + +// FailExpiryTooFar is returned if the CLTV expiry in the HTLC is too far in the +// future. +// +// NOTE: May be returned by any node in the payment route. +type FailExpiryTooFar struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailExpiryTooFar) Code() FailCode { + return CodeExpiryTooFar +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailExpiryTooFar) Error() string { + return f.Code().String() +} + +// InvalidOnionPayload is returned if the hop could not process the TLV payload +// enclosed in the onion. +type InvalidOnionPayload struct { + // Type is the TLV type that caused the specific failure. + Type uint64 + + // Offset is the byte offset within the payload where the failure + // occurred. + Offset uint16 +} + +// NewInvalidOnionPayload initializes a new InvalidOnionPayload failure. +func NewInvalidOnionPayload(typ uint64, offset uint16) *InvalidOnionPayload { + return &InvalidOnionPayload{ + Type: typ, + Offset: offset, + } +} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *InvalidOnionPayload) Code() FailCode { + return CodeInvalidOnionPayload +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *InvalidOnionPayload) Error() string { + return fmt.Sprintf("%v(type=%v, offset=%d)", + f.Code(), f.Type, f.Offset) +} + +// Decode decodes the failure from bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *InvalidOnionPayload) Decode(r io.Reader, pver uint32) error { + var buf [8]byte + typ, err := tlv.ReadVarInt(r, &buf) + if err != nil { + return err + } + f.Type = typ + + return ReadElements(r, &f.Offset) +} + +// Encode writes the failure in bytes stream. +// +// NOTE: Part of the Serializable interface. +func (f *InvalidOnionPayload) Encode(w io.Writer, pver uint32) error { + var buf [8]byte + if err := tlv.WriteVarInt(w, f.Type, &buf); err != nil { + return err + } + + return WriteElements(w, f.Offset) +} + +// FailMPPTimeout is returned if the complete amount for a multi part payment +// was not received within a reasonable time. +// +// NOTE: May only be returned by the final node in the path. +type FailMPPTimeout struct{} + +// Code returns the failure unique code. +// +// NOTE: Part of the FailureMessage interface. +func (f *FailMPPTimeout) Code() FailCode { + return CodeMPPTimeout +} + +// Returns a human readable string describing the target FailureMessage. +// +// NOTE: Implements the error interface. +func (f *FailMPPTimeout) Error() string { + return f.Code().String() +} + +// DecodeFailure decodes, validates, and parses the lnwire onion failure, for +// the provided protocol version. +func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) { + // First, we'll parse out the encapsulated failure message itself. This + // is a 2 byte length followed by the payload itself. + var failureLength uint16 + if err := ReadElement(r, &failureLength); err != nil { + return nil, fmt.Errorf("unable to read error len: %v", err) + } + if failureLength > FailureMessageLength { + return nil, fmt.Errorf("failure message is too "+ + "long: %v", failureLength) + } + failureData := make([]byte, failureLength) + if _, err := io.ReadFull(r, failureData); err != nil { + return nil, fmt.Errorf("unable to full read payload of "+ + "%v: %v", failureLength, err) + } + + dataReader := bytes.NewReader(failureData) + + return DecodeFailureMessage(dataReader, pver) +} + +// DecodeFailureMessage decodes just the failure message, ignoring any padding +// that may be present at the end. +func DecodeFailureMessage(r io.Reader, pver uint32) (FailureMessage, error) { + // Once we have the failure data, we can obtain the failure code from + // the first two bytes of the buffer. + var codeBytes [2]byte + if _, err := io.ReadFull(r, codeBytes[:]); err != nil { + return nil, fmt.Errorf("unable to read failure code: %v", err) + } + failCode := FailCode(binary.BigEndian.Uint16(codeBytes[:])) + + // Create the empty failure by given code and populate the failure with + // additional data if needed. + failure, err := makeEmptyOnionError(failCode) + if err != nil { + return nil, fmt.Errorf("unable to make empty error: %v", err) + } + + // Finally, if this failure has a payload, then we'll read that now as + // well. + switch f := failure.(type) { + case Serializable: + if err := f.Decode(r, pver); err != nil { + return nil, fmt.Errorf("unable to decode error "+ + "update (type=%T): %v", failure, err) + } + } + + return failure, nil +} + +// EncodeFailure encodes, including the necessary onion failure header +// information. +func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error { + var failureMessageBuffer bytes.Buffer + + err := EncodeFailureMessage(&failureMessageBuffer, failure, pver) + if err != nil { + return err + } + + // The combined size of this message must be below the max allowed + // failure message length. + failureMessage := failureMessageBuffer.Bytes() + if len(failureMessage) > FailureMessageLength { + return fmt.Errorf("failure message exceed max "+ + "available size: %v", len(failureMessage)) + } + + // Finally, we'll add some padding in order to ensure that all failure + // messages are fixed size. + pad := make([]byte, FailureMessageLength-len(failureMessage)) + + return WriteElements(w, + uint16(len(failureMessage)), + failureMessage, + uint16(len(pad)), + pad, + ) +} + +// EncodeFailureMessage encodes just the failure message without adding a length +// and padding the message for the onion protocol. +func EncodeFailureMessage(w io.Writer, failure FailureMessage, pver uint32) error { + // First, we'll write out the error code itself into the failure + // buffer. + var codeBytes [2]byte + code := uint16(failure.Code()) + binary.BigEndian.PutUint16(codeBytes[:], code) + _, err := w.Write(codeBytes[:]) + if err != nil { + return err + } + + // Next, some message have an additional message payload, if this is + // one of those types, then we'll also encode the error payload as + // well. + switch failure := failure.(type) { + case Serializable: + if err := failure.Encode(w, pver); err != nil { + return err + } + } + + return nil +} + +// makeEmptyOnionError creates a new empty onion error of the proper concrete +// type based on the passed failure code. +func makeEmptyOnionError(code FailCode) (FailureMessage, error) { + switch code { + case CodeInvalidRealm: + return &FailInvalidRealm{}, nil + + case CodeTemporaryNodeFailure: + return &FailTemporaryNodeFailure{}, nil + + case CodePermanentNodeFailure: + return &FailPermanentNodeFailure{}, nil + + case CodeRequiredNodeFeatureMissing: + return &FailRequiredNodeFeatureMissing{}, nil + + case CodePermanentChannelFailure: + return &FailPermanentChannelFailure{}, nil + + case CodeRequiredChannelFeatureMissing: + return &FailRequiredChannelFeatureMissing{}, nil + + case CodeUnknownNextPeer: + return &FailUnknownNextPeer{}, nil + + case CodeIncorrectOrUnknownPaymentDetails: + return &FailIncorrectDetails{}, nil + + case CodeIncorrectPaymentAmount: + return &FailIncorrectPaymentAmount{}, nil + + case CodeFinalExpiryTooSoon: + return &FailFinalExpiryTooSoon{}, nil + + case CodeInvalidOnionVersion: + return &FailInvalidOnionVersion{}, nil + + case CodeInvalidOnionHmac: + return &FailInvalidOnionHmac{}, nil + + case CodeInvalidOnionKey: + return &FailInvalidOnionKey{}, nil + + case CodeTemporaryChannelFailure: + return &FailTemporaryChannelFailure{}, nil + + case CodeAmountBelowMinimum: + return &FailAmountBelowMinimum{}, nil + + case CodeFeeInsufficient: + return &FailFeeInsufficient{}, nil + + case CodeIncorrectCltvExpiry: + return &FailIncorrectCltvExpiry{}, nil + + case CodeExpiryTooSoon: + return &FailExpiryTooSoon{}, nil + + case CodeChannelDisabled: + return &FailChannelDisabled{}, nil + + case CodeFinalIncorrectCltvExpiry: + return &FailFinalIncorrectCltvExpiry{}, nil + + case CodeFinalIncorrectHtlcAmount: + return &FailFinalIncorrectHtlcAmount{}, nil + + case CodeExpiryTooFar: + return &FailExpiryTooFar{}, nil + + case CodeInvalidOnionPayload: + return &InvalidOnionPayload{}, nil + + case CodeMPPTimeout: + return &FailMPPTimeout{}, nil + + default: + return nil, errors.Errorf("unknown error code: %v", code) + } +} + +// writeOnionErrorChanUpdate writes out a ChannelUpdate using the onion error +// format. The format is that we first write out the true serialized length of +// the channel update, followed by the serialized channel update itself. +func writeOnionErrorChanUpdate(w io.Writer, chanUpdate *ChannelUpdate, + pver uint32) error { + + // First, we encode the channel update in a temporary buffer in order + // to get the exact serialized size. + var b bytes.Buffer + if err := chanUpdate.Encode(&b, pver); err != nil { + return err + } + + // Now that we know the size, we can write the length out in the main + // writer. + updateLen := b.Len() + if err := WriteElement(w, uint16(updateLen)); err != nil { + return err + } + + // With the length written, we'll then write out the serialized channel + // update. + if _, err := w.Write(b.Bytes()); err != nil { + return err + } + + return nil +} diff --git a/channeldb/migration/lnwire21/open_channel.go b/channeldb/migration/lnwire21/open_channel.go new file mode 100644 index 00000000..a165ef75 --- /dev/null +++ b/channeldb/migration/lnwire21/open_channel.go @@ -0,0 +1,225 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcutil" +) + +// 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 +} + +// 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.HtlcPoint, + o.FirstCommitmentPoint, + o.ChannelFlags, + o.UpfrontShutdownScript, + ) +} + +// 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 { + if 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, + ); err != nil { + return err + } + + // Check for the optional upfront shutdown script field. If it is not there, + // silence the EOF error. + err := ReadElement(r, &o.UpfrontShutdownScript) + if err != nil && err != io.EOF { + return err + } + + 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 +} + +// 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 * 6) + (4 * 1) + (2 * 2) + (33 * 6) + 1 + var length uint32 = 319 // base length + + // Upfront shutdown script max length. + length += 2 + deliveryAddressMaxSize + + return length +} diff --git a/channeldb/migration/lnwire21/ping.go b/channeldb/migration/lnwire21/ping.go new file mode 100644 index 00000000..cf9a83b7 --- /dev/null +++ b/channeldb/migration/lnwire21/ping.go @@ -0,0 +1,67 @@ +package lnwire + +import "io" + +// PingPayload is a set of opaque bytes used to pad out a ping message. +type PingPayload []byte + +// Ping defines a message which is sent by peers periodically to determine if +// the connection is still valid. Each ping message carries the number of bytes +// to pad the pong response with, and also a number of bytes to be ignored at +// the end of the ping message (which is padding). +type Ping struct { + // NumPongBytes is the number of bytes the pong response to this + // message should carry. + NumPongBytes uint16 + + // PaddingBytes is a set of opaque bytes used to pad out this ping + // message. Using this field in conjunction to the one above, it's + // possible for node to generate fake cover traffic. + PaddingBytes PingPayload +} + +// NewPing returns a new Ping message. +func NewPing(numBytes uint16) *Ping { + return &Ping{ + NumPongBytes: numBytes, + } +} + +// A compile time check to ensure Ping implements the lnwire.Message interface. +var _ Message = (*Ping)(nil) + +// Decode deserializes a serialized Ping message stored in the passed io.Reader +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (p *Ping) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &p.NumPongBytes, + &p.PaddingBytes) +} + +// Encode serializes the target Ping into the passed io.Writer observing the +// protocol version specified. +// +// This is part of the lnwire.Message interface. +func (p *Ping) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + p.NumPongBytes, + p.PaddingBytes) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (p *Ping) MsgType() MessageType { + return MsgPing +} + +// MaxPayloadLength returns the maximum allowed payload size for a Ping +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (p Ping) MaxPayloadLength(uint32) uint32 { + return 65532 +} diff --git a/channeldb/migration/lnwire21/pong.go b/channeldb/migration/lnwire21/pong.go new file mode 100644 index 00000000..c3166aaf --- /dev/null +++ b/channeldb/migration/lnwire21/pong.go @@ -0,0 +1,63 @@ +package lnwire + +import "io" + +// PongPayload is a set of opaque bytes sent in response to a ping message. +type PongPayload []byte + +// Pong defines a message which is the direct response to a received Ping +// message. A Pong reply indicates that a connection is still active. The Pong +// reply to a Ping message should contain the nonce carried in the original +// Pong message. +type Pong struct { + // PongBytes is a set of opaque bytes that corresponds to the + // NumPongBytes defined in the ping message that this pong is + // replying to. + PongBytes PongPayload +} + +// NewPong returns a new Pong message. +func NewPong(pongBytes []byte) *Pong { + return &Pong{ + PongBytes: pongBytes, + } +} + +// A compile time check to ensure Pong implements the lnwire.Message interface. +var _ Message = (*Pong)(nil) + +// Decode deserializes a serialized Pong message stored in the passed io.Reader +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (p *Pong) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &p.PongBytes, + ) +} + +// Encode serializes the target Pong into the passed io.Writer observing the +// protocol version specified. +// +// This is part of the lnwire.Message interface. +func (p *Pong) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + p.PongBytes, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (p *Pong) MsgType() MessageType { + return MsgPong +} + +// MaxPayloadLength returns the maximum allowed payload size for a Pong +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (p *Pong) MaxPayloadLength(uint32) uint32 { + return 65532 +} diff --git a/channeldb/migration/lnwire21/query_channel_range.go b/channeldb/migration/lnwire21/query_channel_range.go new file mode 100644 index 00000000..9546fcd3 --- /dev/null +++ b/channeldb/migration/lnwire21/query_channel_range.go @@ -0,0 +1,89 @@ +package lnwire + +import ( + "io" + "math" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// QueryChannelRange is a message sent by a node in order to query the +// receiving node of the set of open channel they know of with short channel +// ID's after the specified block height, capped at the number of blocks beyond +// that block height. This will be used by nodes upon initial connect to +// synchronize their views of the network. +type QueryChannelRange struct { + // ChainHash denotes the target chain that we're trying to synchronize + // channel graph state for. + ChainHash chainhash.Hash + + // FirstBlockHeight is the first block in the query range. The + // responder should send all new short channel IDs from this block + // until this block plus the specified number of blocks. + FirstBlockHeight uint32 + + // NumBlocks is the number of blocks beyond the first block that short + // channel ID's should be sent for. + NumBlocks uint32 +} + +// NewQueryChannelRange creates a new empty QueryChannelRange message. +func NewQueryChannelRange() *QueryChannelRange { + return &QueryChannelRange{} +} + +// A compile time check to ensure QueryChannelRange implements the +// lnwire.Message interface. +var _ Message = (*QueryChannelRange)(nil) + +// Decode deserializes a serialized QueryChannelRange message stored in the +// passed io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (q *QueryChannelRange) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + q.ChainHash[:], + &q.FirstBlockHeight, + &q.NumBlocks, + ) +} + +// Encode serializes the target QueryChannelRange into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (q *QueryChannelRange) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + q.ChainHash[:], + q.FirstBlockHeight, + q.NumBlocks, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (q *QueryChannelRange) MsgType() MessageType { + return MsgQueryChannelRange +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// QueryChannelRange complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (q *QueryChannelRange) MaxPayloadLength(uint32) uint32 { + // 32 + 4 + 4 + return 40 +} + +// LastBlockHeight returns the last block height covered by the range of a +// QueryChannelRange message. +func (q *QueryChannelRange) LastBlockHeight() uint32 { + // Handle overflows by casting to uint64. + lastBlockHeight := uint64(q.FirstBlockHeight) + uint64(q.NumBlocks) - 1 + if lastBlockHeight > math.MaxUint32 { + return math.MaxUint32 + } + return uint32(lastBlockHeight) +} diff --git a/channeldb/migration/lnwire21/query_short_chan_ids.go b/channeldb/migration/lnwire21/query_short_chan_ids.go new file mode 100644 index 00000000..3c2b9948 --- /dev/null +++ b/channeldb/migration/lnwire21/query_short_chan_ids.go @@ -0,0 +1,429 @@ +package lnwire + +import ( + "bytes" + "compress/zlib" + "fmt" + "io" + "sort" + "sync" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// ShortChanIDEncoding is an enum-like type that represents exactly how a set +// of short channel ID's is encoded on the wire. The set of encodings allows us +// to take advantage of the structure of a list of short channel ID's to +// achieving a high degree of compression. +type ShortChanIDEncoding uint8 + +const ( + // EncodingSortedPlain signals that the set of short channel ID's is + // encoded using the regular encoding, in a sorted order. + EncodingSortedPlain ShortChanIDEncoding = 0 + + // EncodingSortedZlib signals that the set of short channel ID's is + // encoded by first sorting the set of channel ID's, as then + // compressing them using zlib. + EncodingSortedZlib ShortChanIDEncoding = 1 +) + +const ( + // maxZlibBufSize is the max number of bytes that we'll accept from a + // zlib decoding instance. We do this in order to limit the total + // amount of memory allocated during a decoding instance. + maxZlibBufSize = 67413630 +) + +// ErrUnsortedSIDs is returned when decoding a QueryShortChannelID request whose +// items were not sorted. +type ErrUnsortedSIDs struct { + prevSID ShortChannelID + curSID ShortChannelID +} + +// Error returns a human-readable description of the error. +func (e ErrUnsortedSIDs) Error() string { + return fmt.Sprintf("current sid: %v isn't greater than last sid: %v", + e.curSID, e.prevSID) +} + +// zlibDecodeMtx is a package level mutex that we'll use in order to ensure +// that we'll only attempt a single zlib decoding instance at a time. This +// allows us to also further bound our memory usage. +var zlibDecodeMtx sync.Mutex + +// ErrUnknownShortChanIDEncoding is a parametrized error that indicates that we +// came across an unknown short channel ID encoding, and therefore were unable +// to continue parsing. +func ErrUnknownShortChanIDEncoding(encoding ShortChanIDEncoding) error { + return fmt.Errorf("unknown short chan id encoding: %v", encoding) +} + +// QueryShortChanIDs is a message that allows the sender to query a set of +// channel announcement and channel update messages that correspond to the set +// of encoded short channel ID's. The encoding of the short channel ID's is +// detailed in the query message ensuring that the receiver knows how to +// properly decode each encode short channel ID which may be encoded using a +// compression format. The receiver should respond with a series of channel +// announcement and channel updates, finally sending a ReplyShortChanIDsEnd +// message. +type QueryShortChanIDs struct { + // ChainHash denotes the target chain that we're querying for the + // channel ID's of. + ChainHash chainhash.Hash + + // EncodingType is a signal to the receiver of the message that + // indicates exactly how the set of short channel ID's that follow have + // been encoded. + EncodingType ShortChanIDEncoding + + // ShortChanIDs is a slice of decoded short channel ID's. + ShortChanIDs []ShortChannelID + + // noSort indicates whether or not to sort the short channel ids before + // writing them out. + // + // NOTE: This should only be used during testing. + noSort bool +} + +// NewQueryShortChanIDs creates a new QueryShortChanIDs message. +func NewQueryShortChanIDs(h chainhash.Hash, e ShortChanIDEncoding, + s []ShortChannelID) *QueryShortChanIDs { + + return &QueryShortChanIDs{ + ChainHash: h, + EncodingType: e, + ShortChanIDs: s, + } +} + +// A compile time check to ensure QueryShortChanIDs implements the +// lnwire.Message interface. +var _ Message = (*QueryShortChanIDs)(nil) + +// Decode deserializes a serialized QueryShortChanIDs message stored in the +// passed io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (q *QueryShortChanIDs) Decode(r io.Reader, pver uint32) error { + err := ReadElements(r, q.ChainHash[:]) + if err != nil { + return err + } + + q.EncodingType, q.ShortChanIDs, err = decodeShortChanIDs(r) + + return err +} + +// decodeShortChanIDs decodes a set of short channel ID's that have been +// encoded. The first byte of the body details how the short chan ID's were +// encoded. We'll use this type to govern exactly how we go about encoding the +// set of short channel ID's. +func decodeShortChanIDs(r io.Reader) (ShortChanIDEncoding, []ShortChannelID, error) { + // First, we'll attempt to read the number of bytes in the body of the + // set of encoded short channel ID's. + var numBytesResp uint16 + err := ReadElements(r, &numBytesResp) + if err != nil { + return 0, nil, err + } + + if numBytesResp == 0 { + return 0, nil, nil + } + + queryBody := make([]byte, numBytesResp) + if _, err := io.ReadFull(r, queryBody); err != nil { + return 0, nil, err + } + + // The first byte is the encoding type, so we'll extract that so we can + // continue our parsing. + encodingType := ShortChanIDEncoding(queryBody[0]) + + // Before continuing, we'll snip off the first byte of the query body + // as that was just the encoding type. + queryBody = queryBody[1:] + + // Otherwise, depending on the encoding type, we'll decode the encode + // short channel ID's in a different manner. + switch encodingType { + + // In this encoding, we'll simply read a sort array of encoded short + // channel ID's from the buffer. + case EncodingSortedPlain: + // If after extracting the encoding type, the number of + // remaining bytes is not a whole multiple of the size of an + // encoded short channel ID (8 bytes), then we'll return a + // parsing error. + if len(queryBody)%8 != 0 { + return 0, nil, fmt.Errorf("whole number of short "+ + "chan ID's cannot be encoded in len=%v", + len(queryBody)) + } + + // As each short channel ID is encoded as 8 bytes, we can + // compute the number of bytes encoded based on the size of the + // query body. + numShortChanIDs := len(queryBody) / 8 + if numShortChanIDs == 0 { + return encodingType, nil, nil + } + + // Finally, we'll read out the exact number of short channel + // ID's to conclude our parsing. + shortChanIDs := make([]ShortChannelID, numShortChanIDs) + bodyReader := bytes.NewReader(queryBody) + var lastChanID ShortChannelID + for i := 0; i < numShortChanIDs; i++ { + if err := ReadElements(bodyReader, &shortChanIDs[i]); err != nil { + return 0, nil, fmt.Errorf("unable to parse "+ + "short chan ID: %v", err) + } + + // We'll ensure that this short chan ID is greater than + // the last one. This is a requirement within the + // encoding, and if violated can aide us in detecting + // malicious payloads. This can only be true starting + // at the second chanID. + cid := shortChanIDs[i] + if i > 0 && cid.ToUint64() <= lastChanID.ToUint64() { + return 0, nil, ErrUnsortedSIDs{lastChanID, cid} + } + lastChanID = cid + } + + return encodingType, shortChanIDs, nil + + // In this encoding, we'll use zlib to decode the compressed payload. + // However, we'll pay attention to ensure that we don't open our selves + // up to a memory exhaustion attack. + case EncodingSortedZlib: + // We'll obtain an ultimately release the zlib decode mutex. + // This guards us against allocating too much memory to decode + // each instance from concurrent peers. + zlibDecodeMtx.Lock() + defer zlibDecodeMtx.Unlock() + + // At this point, if there's no body remaining, then only the encoding + // type was specified, meaning that there're no further bytes to be + // parsed. + if len(queryBody) == 0 { + return encodingType, nil, nil + } + + // Before we start to decode, we'll create a limit reader over + // the current reader. This will ensure that we can control how + // much memory we're allocating during the decoding process. + limitedDecompressor, err := zlib.NewReader(&io.LimitedReader{ + R: bytes.NewReader(queryBody), + N: maxZlibBufSize, + }) + if err != nil { + return 0, nil, fmt.Errorf("unable to create zlib reader: %v", err) + } + + var ( + shortChanIDs []ShortChannelID + lastChanID ShortChannelID + i int + ) + for { + // We'll now attempt to read the next short channel ID + // encoded in the payload. + var cid ShortChannelID + err := ReadElements(limitedDecompressor, &cid) + + switch { + // If we get an EOF error, then that either means we've + // read all that's contained in the buffer, or have hit + // our limit on the number of bytes we'll read. In + // either case, we'll return what we have so far. + case err == io.ErrUnexpectedEOF || err == io.EOF: + return encodingType, shortChanIDs, nil + + // Otherwise, we hit some other sort of error, possibly + // an invalid payload, so we'll exit early with the + // error. + case err != nil: + return 0, nil, fmt.Errorf("unable to "+ + "deflate next short chan "+ + "ID: %v", err) + } + + // We successfully read the next ID, so we'll collect + // that in the set of final ID's to return. + shortChanIDs = append(shortChanIDs, cid) + + // Finally, we'll ensure that this short chan ID is + // greater than the last one. This is a requirement + // within the encoding, and if violated can aide us in + // detecting malicious payloads. This can only be true + // starting at the second chanID. + if i > 0 && cid.ToUint64() <= lastChanID.ToUint64() { + return 0, nil, ErrUnsortedSIDs{lastChanID, cid} + } + + lastChanID = cid + i++ + } + + default: + // If we've been sent an encoding type that we don't know of, + // then we'll return a parsing error as we can't continue if + // we're unable to encode them. + return 0, nil, ErrUnknownShortChanIDEncoding(encodingType) + } +} + +// Encode serializes the target QueryShortChanIDs into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (q *QueryShortChanIDs) Encode(w io.Writer, pver uint32) error { + // First, we'll write out the chain hash. + err := WriteElements(w, q.ChainHash[:]) + if err != nil { + return err + } + + // Base on our encoding type, we'll write out the set of short channel + // ID's. + return encodeShortChanIDs(w, q.EncodingType, q.ShortChanIDs, q.noSort) +} + +// encodeShortChanIDs encodes the passed short channel ID's into the passed +// io.Writer, respecting the specified encoding type. +func encodeShortChanIDs(w io.Writer, encodingType ShortChanIDEncoding, + shortChanIDs []ShortChannelID, noSort bool) error { + + // For both of the current encoding types, the channel ID's are to be + // sorted in place, so we'll do that now. The sorting is applied unless + // we were specifically requested not to for testing purposes. + if !noSort { + sort.Slice(shortChanIDs, func(i, j int) bool { + return shortChanIDs[i].ToUint64() < + shortChanIDs[j].ToUint64() + }) + } + + switch encodingType { + + // In this encoding, we'll simply write a sorted array of encoded short + // channel ID's from the buffer. + case EncodingSortedPlain: + // First, we'll write out the number of bytes of the query + // body. We add 1 as the response will have the encoding type + // prepended to it. + numBytesBody := uint16(len(shortChanIDs)*8) + 1 + if err := WriteElements(w, numBytesBody); err != nil { + return err + } + + // We'll then write out the encoding that that follows the + // actual encoded short channel ID's. + if err := WriteElements(w, encodingType); err != nil { + return err + } + + // Now that we know they're sorted, we can write out each short + // channel ID to the buffer. + for _, chanID := range shortChanIDs { + if err := WriteElements(w, chanID); err != nil { + return fmt.Errorf("unable to write short chan "+ + "ID: %v", err) + } + } + + return nil + + // For this encoding we'll first write out a serialized version of all + // the channel ID's into a buffer, then zlib encode that. The final + // payload is what we'll write out to the passed io.Writer. + // + // TODO(roasbeef): assumes the caller knows the proper chunk size to + // pass to avoid bin-packing here + case EncodingSortedZlib: + // We'll make a new buffer, then wrap that with a zlib writer + // so we can write directly to the buffer and encode in a + // streaming manner. + var buf bytes.Buffer + zlibWriter := zlib.NewWriter(&buf) + + // If we don't have anything at all to write, then we'll write + // an empty payload so we don't include things like the zlib + // header when the remote party is expecting no actual short + // channel IDs. + var compressedPayload []byte + if len(shortChanIDs) > 0 { + // Next, we'll write out all the channel ID's directly + // into the zlib writer, which will do compressing on + // the fly. + for _, chanID := range shortChanIDs { + err := WriteElements(zlibWriter, chanID) + if err != nil { + return fmt.Errorf("unable to write short chan "+ + "ID: %v", err) + } + } + + // Now that we've written all the elements, we'll + // ensure the compressed stream is written to the + // underlying buffer. + if err := zlibWriter.Close(); err != nil { + return fmt.Errorf("unable to finalize "+ + "compression: %v", err) + } + + compressedPayload = buf.Bytes() + } + + // Now that we have all the items compressed, we can compute + // what the total payload size will be. We add one to account + // for the byte to encode the type. + // + // If we don't have any actual bytes to write, then we'll end + // up emitting one byte for the length, followed by the + // encoding type, and nothing more. The spec isn't 100% clear + // in this area, but we do this as this is what most of the + // other implementations do. + numBytesBody := len(compressedPayload) + 1 + + // Finally, we can write out the number of bytes, the + // compression type, and finally the buffer itself. + if err := WriteElements(w, uint16(numBytesBody)); err != nil { + return err + } + if err := WriteElements(w, encodingType); err != nil { + return err + } + + _, err := w.Write(compressedPayload) + return err + + default: + // If we're trying to encode with an encoding type that we + // don't know of, then we'll return a parsing error as we can't + // continue if we're unable to encode them. + return ErrUnknownShortChanIDEncoding(encodingType) + } +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (q *QueryShortChanIDs) MsgType() MessageType { + return MsgQueryShortChanIDs +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// QueryShortChanIDs complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (q *QueryShortChanIDs) MaxPayloadLength(uint32) uint32 { + return MaxMessagePayload +} diff --git a/channeldb/migration/lnwire21/reply_channel_range.go b/channeldb/migration/lnwire21/reply_channel_range.go new file mode 100644 index 00000000..43060602 --- /dev/null +++ b/channeldb/migration/lnwire21/reply_channel_range.go @@ -0,0 +1,90 @@ +package lnwire + +import "io" + +// ReplyChannelRange is the response to the QueryChannelRange message. It +// includes the original query, and the next streaming chunk of encoded short +// channel ID's as the response. We'll also include a byte that indicates if +// this is the last query in the message. +type ReplyChannelRange struct { + // QueryChannelRange is the corresponding query to this response. + QueryChannelRange + + // Complete denotes if this is the conclusion of the set of streaming + // responses to the original query. + Complete uint8 + + // EncodingType is a signal to the receiver of the message that + // indicates exactly how the set of short channel ID's that follow have + // been encoded. + EncodingType ShortChanIDEncoding + + // ShortChanIDs is a slice of decoded short channel ID's. + ShortChanIDs []ShortChannelID + + // noSort indicates whether or not to sort the short channel ids before + // writing them out. + // + // NOTE: This should only be used for testing. + noSort bool +} + +// NewReplyChannelRange creates a new empty ReplyChannelRange message. +func NewReplyChannelRange() *ReplyChannelRange { + return &ReplyChannelRange{} +} + +// A compile time check to ensure ReplyChannelRange implements the +// lnwire.Message interface. +var _ Message = (*ReplyChannelRange)(nil) + +// Decode deserializes a serialized ReplyChannelRange message stored in the +// passed io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *ReplyChannelRange) Decode(r io.Reader, pver uint32) error { + err := c.QueryChannelRange.Decode(r, pver) + if err != nil { + return err + } + + if err := ReadElements(r, &c.Complete); err != nil { + return err + } + + c.EncodingType, c.ShortChanIDs, err = decodeShortChanIDs(r) + + return err +} + +// Encode serializes the target ReplyChannelRange into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *ReplyChannelRange) Encode(w io.Writer, pver uint32) error { + if err := c.QueryChannelRange.Encode(w, pver); err != nil { + return err + } + + if err := WriteElements(w, c.Complete); err != nil { + return err + } + + return encodeShortChanIDs(w, c.EncodingType, c.ShortChanIDs, c.noSort) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *ReplyChannelRange) MsgType() MessageType { + return MsgReplyChannelRange +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// ReplyChannelRange complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *ReplyChannelRange) MaxPayloadLength(uint32) uint32 { + return MaxMessagePayload +} diff --git a/channeldb/migration/lnwire21/reply_short_chan_ids_end.go b/channeldb/migration/lnwire21/reply_short_chan_ids_end.go new file mode 100644 index 00000000..d77aa0b5 --- /dev/null +++ b/channeldb/migration/lnwire21/reply_short_chan_ids_end.go @@ -0,0 +1,74 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +// ReplyShortChanIDsEnd is a message that marks the end of a streaming message +// response to an initial QueryShortChanIDs message. This marks that the +// receiver of the original QueryShortChanIDs for the target chain has either +// sent all adequate responses it knows of, or doesn't know of any short chan +// ID's for the target chain. +type ReplyShortChanIDsEnd struct { + // ChainHash denotes the target chain that we're respond to a short + // chan ID query for. + ChainHash chainhash.Hash + + // Complete will be set to 0 if we don't know of the chain that the + // remote peer sent their query for. Otherwise, we'll set this to 1 in + // order to indicate that we've sent all known responses for the prior + // set of short chan ID's in the corresponding QueryShortChanIDs + // message. + Complete uint8 +} + +// NewReplyShortChanIDsEnd creates a new empty ReplyShortChanIDsEnd message. +func NewReplyShortChanIDsEnd() *ReplyShortChanIDsEnd { + return &ReplyShortChanIDsEnd{} +} + +// A compile time check to ensure ReplyShortChanIDsEnd implements the +// lnwire.Message interface. +var _ Message = (*ReplyShortChanIDsEnd)(nil) + +// Decode deserializes a serialized ReplyShortChanIDsEnd message stored in the +// passed io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *ReplyShortChanIDsEnd) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + c.ChainHash[:], + &c.Complete, + ) +} + +// Encode serializes the target ReplyShortChanIDsEnd into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *ReplyShortChanIDsEnd) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChainHash[:], + c.Complete, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *ReplyShortChanIDsEnd) MsgType() MessageType { + return MsgReplyShortChanIDsEnd +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// ReplyShortChanIDsEnd complete message observing the specified protocol +// version. +// +// This is part of the lnwire.Message interface. +func (c *ReplyShortChanIDsEnd) MaxPayloadLength(uint32) uint32 { + // 32 (chain hash) + 1 (complete) + return 33 +} diff --git a/channeldb/migration/lnwire21/revoke_and_ack.go b/channeldb/migration/lnwire21/revoke_and_ack.go new file mode 100644 index 00000000..0cfa2bc2 --- /dev/null +++ b/channeldb/migration/lnwire21/revoke_and_ack.go @@ -0,0 +1,91 @@ +package lnwire + +import ( + "io" + + "github.com/btcsuite/btcd/btcec" +) + +// RevokeAndAck is sent by either side once a CommitSig message has been +// received, and validated. This message serves to revoke the prior commitment +// transaction, which was the most up to date version until a CommitSig message +// referencing the specified ChannelPoint was received. Additionally, this +// message also piggyback's the next revocation hash that Alice should use when +// constructing the Bob's version of the next commitment transaction (which +// would be done before sending a CommitSig message). This piggybacking allows +// Alice to send the next CommitSig message modifying Bob's commitment +// transaction without first asking for a revocation hash initially. +type RevokeAndAck struct { + // ChanID uniquely identifies to which currently active channel this + // RevokeAndAck applies to. + ChanID ChannelID + + // Revocation is the preimage to the revocation hash of the now prior + // commitment transaction. + Revocation [32]byte + + // NextRevocationKey is the next commitment point which should be used + // for the next commitment transaction the remote peer creates for us. + // This, in conjunction with revocation base point will be used to + // create the proper revocation key used within the commitment + // transaction. + NextRevocationKey *btcec.PublicKey +} + +// NewRevokeAndAck creates a new RevokeAndAck message. +func NewRevokeAndAck() *RevokeAndAck { + return &RevokeAndAck{} +} + +// A compile time check to ensure RevokeAndAck implements the lnwire.Message +// interface. +var _ Message = (*RevokeAndAck)(nil) + +// Decode deserializes a serialized RevokeAndAck message stored in the +// passed io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *RevokeAndAck) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + c.Revocation[:], + &c.NextRevocationKey, + ) +} + +// Encode serializes the target RevokeAndAck into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *RevokeAndAck) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.Revocation[:], + c.NextRevocationKey, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *RevokeAndAck) MsgType() MessageType { + return MsgRevokeAndAck +} + +// MaxPayloadLength returns the maximum allowed payload size for a RevokeAndAck +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *RevokeAndAck) MaxPayloadLength(uint32) uint32 { + // 32 + 32 + 33 + return 97 +} + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of peer.LinkUpdater interface. +func (c *RevokeAndAck) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/channeldb/migration/lnwire21/short_channel_id.go b/channeldb/migration/lnwire21/short_channel_id.go new file mode 100644 index 00000000..b2b980aa --- /dev/null +++ b/channeldb/migration/lnwire21/short_channel_id.go @@ -0,0 +1,48 @@ +package lnwire + +import ( + "fmt" +) + +// ShortChannelID represents the set of data which is needed to retrieve all +// necessary data to validate the channel existence. +type ShortChannelID struct { + // BlockHeight is the height of the block where funding transaction + // located. + // + // NOTE: This field is limited to 3 bytes. + BlockHeight uint32 + + // TxIndex is a position of funding transaction within a block. + // + // NOTE: This field is limited to 3 bytes. + TxIndex uint32 + + // TxPosition indicating transaction output which pays to the channel. + TxPosition uint16 +} + +// NewShortChanIDFromInt returns a new ShortChannelID which is the decoded +// version of the compact channel ID encoded within the uint64. The format of +// the compact channel ID is as follows: 3 bytes for the block height, 3 bytes +// for the transaction index, and 2 bytes for the output index. +func NewShortChanIDFromInt(chanID uint64) ShortChannelID { + return ShortChannelID{ + BlockHeight: uint32(chanID >> 40), + TxIndex: uint32(chanID>>16) & 0xFFFFFF, + TxPosition: uint16(chanID), + } +} + +// ToUint64 converts the ShortChannelID into a compact format encoded within a +// uint64 (8 bytes). +func (c ShortChannelID) ToUint64() uint64 { + // TODO(roasbeef): explicit error on overflow? + return ((uint64(c.BlockHeight) << 40) | (uint64(c.TxIndex) << 16) | + (uint64(c.TxPosition))) +} + +// String generates a human-readable representation of the channel ID. +func (c ShortChannelID) String() string { + return fmt.Sprintf("%d:%d:%d", c.BlockHeight, c.TxIndex, c.TxPosition) +} diff --git a/channeldb/migration/lnwire21/shutdown.go b/channeldb/migration/lnwire21/shutdown.go new file mode 100644 index 00000000..94d10a90 --- /dev/null +++ b/channeldb/migration/lnwire21/shutdown.go @@ -0,0 +1,87 @@ +package lnwire + +import ( + "io" +) + +// Shutdown is sent by either side in order to initiate the cooperative closure +// of a channel. This message is sparse as both sides implicitly have the +// information necessary to construct a transaction that will send the settled +// funds of both parties to the final delivery addresses negotiated during the +// funding workflow. +type Shutdown struct { + // ChannelID serves to identify which channel is to be closed. + ChannelID ChannelID + + // Address is the script to which the channel funds will be paid. + Address DeliveryAddress +} + +// DeliveryAddress is used to communicate the address to which funds from a +// closed channel should be sent. The address can be a p2wsh, p2pkh, p2sh or +// p2wpkh. +type DeliveryAddress []byte + +// deliveryAddressMaxSize is the maximum expected size in bytes of a +// DeliveryAddress based on the types of scripts we know. +// Following are the known scripts and their sizes in bytes. +// - pay to witness script hash: 34 +// - pay to pubkey hash: 25 +// - pay to script hash: 22 +// - pay to witness pubkey hash: 22. +const deliveryAddressMaxSize = 34 + +// NewShutdown creates a new Shutdown message. +func NewShutdown(cid ChannelID, addr DeliveryAddress) *Shutdown { + return &Shutdown{ + ChannelID: cid, + Address: addr, + } +} + +// A compile-time check to ensure Shutdown implements the lnwire.Message +// interface. +var _ Message = (*Shutdown)(nil) + +// Decode deserializes a serialized Shutdown stored in the passed io.Reader +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (s *Shutdown) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, &s.ChannelID, &s.Address) +} + +// Encode serializes the target Shutdown into the passed io.Writer observing +// the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (s *Shutdown) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, s.ChannelID, s.Address) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (s *Shutdown) MsgType() MessageType { + return MsgShutdown +} + +// MaxPayloadLength returns the maximum allowed payload size for this message +// observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (s *Shutdown) MaxPayloadLength(pver uint32) uint32 { + var length uint32 + + // ChannelID - 32bytes + length += 32 + + // Len - 2 bytes + length += 2 + + // ScriptPubKey - maximum delivery address size. + length += deliveryAddressMaxSize + + return length +} diff --git a/channeldb/migration/lnwire21/signature.go b/channeldb/migration/lnwire21/signature.go new file mode 100644 index 00000000..13a2f25c --- /dev/null +++ b/channeldb/migration/lnwire21/signature.go @@ -0,0 +1,129 @@ +package lnwire + +import ( + "fmt" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/input" +) + +// Sig is a fixed-sized ECDSA signature. Unlike Bitcoin, we use fixed sized +// signatures on the wire, instead of DER encoded signatures. This type +// provides several methods to convert to/from a regular Bitcoin DER encoded +// signature (raw bytes and *btcec.Signature). +type Sig [64]byte + +// NewSigFromRawSignature returns a Sig from a Bitcoin raw signature encoded in +// the canonical DER encoding. +func NewSigFromRawSignature(sig []byte) (Sig, error) { + var b Sig + + if len(sig) == 0 { + return b, fmt.Errorf("cannot decode empty signature") + } + + // Extract lengths of R and S. The DER representation is laid out as + // 0x30 0x02 r 0x02 s + // which means the length of R is the 4th byte and the length of S + // is the second byte after R ends. 0x02 signifies a length-prefixed, + // zero-padded, big-endian bigint. 0x30 signifies a DER signature. + // See the Serialize() method for btcec.Signature for details. + rLen := sig[3] + sLen := sig[5+rLen] + + // Check to make sure R and S can both fit into their intended buffers. + // We check S first because these code blocks decrement sLen and rLen + // in the case of a 33-byte 0-padded integer returned from Serialize() + // and rLen is used in calculating array indices for S. We can track + // this with additional variables, but it's more efficient to just + // check S first. + if sLen > 32 { + if (sLen > 33) || (sig[6+rLen] != 0x00) { + return b, fmt.Errorf("S is over 32 bytes long " + + "without padding") + } + sLen-- + copy(b[64-sLen:], sig[7+rLen:]) + } else { + copy(b[64-sLen:], sig[6+rLen:]) + } + + // Do the same for R as we did for S + if rLen > 32 { + if (rLen > 33) || (sig[4] != 0x00) { + return b, fmt.Errorf("R is over 32 bytes long " + + "without padding") + } + rLen-- + copy(b[32-rLen:], sig[5:5+rLen]) + } else { + copy(b[32-rLen:], sig[4:4+rLen]) + } + + return b, nil +} + +// NewSigFromSignature creates a new signature as used on the wire, from an +// existing btcec.Signature. +func NewSigFromSignature(e input.Signature) (Sig, error) { + if e == nil { + return Sig{}, fmt.Errorf("cannot decode empty signature") + } + + // Serialize the signature with all the checks that entails. + return NewSigFromRawSignature(e.Serialize()) +} + +// ToSignature converts the fixed-sized signature to a btcec.Signature objects +// which can be used for signature validation checks. +func (b *Sig) ToSignature() (*btcec.Signature, error) { + // Parse the signature with strict checks. + sigBytes := b.ToSignatureBytes() + sig, err := btcec.ParseDERSignature(sigBytes, btcec.S256()) + if err != nil { + return nil, err + } + + return sig, nil +} + +// ToSignatureBytes serializes the target fixed-sized signature into the raw +// bytes of a DER encoding. +func (b *Sig) ToSignatureBytes() []byte { + // Extract canonically-padded bigint representations from buffer + r := extractCanonicalPadding(b[0:32]) + s := extractCanonicalPadding(b[32:64]) + rLen := uint8(len(r)) + sLen := uint8(len(s)) + + // Create a canonical serialized signature. DER format is: + // 0x30 0x02 r 0x02 s + sigBytes := make([]byte, 6+rLen+sLen) + sigBytes[0] = 0x30 // DER signature magic value + sigBytes[1] = 4 + rLen + sLen // Length of rest of signature + sigBytes[2] = 0x02 // Big integer magic value + sigBytes[3] = rLen // Length of R + sigBytes[rLen+4] = 0x02 // Big integer magic value + sigBytes[rLen+5] = sLen // Length of S + copy(sigBytes[4:], r) // Copy R + copy(sigBytes[rLen+6:], s) // Copy S + + return sigBytes +} + +// extractCanonicalPadding is a utility function to extract the canonical +// padding of a big-endian integer from the wire encoding (a 0-padded +// big-endian integer) such that it passes btcec.canonicalPadding test. +func extractCanonicalPadding(b []byte) []byte { + for i := 0; i < len(b); i++ { + // Found first non-zero byte. + if b[i] > 0 { + // If the MSB is set, we need zero padding. + if b[i]&0x80 == 0x80 { + return append([]byte{0x00}, b[i:]...) + } + return b[i:] + } + } + return []byte{0x00} +} diff --git a/channeldb/migration/lnwire21/update_add_htlc.go b/channeldb/migration/lnwire21/update_add_htlc.go new file mode 100644 index 00000000..028c6320 --- /dev/null +++ b/channeldb/migration/lnwire21/update_add_htlc.go @@ -0,0 +1,119 @@ +package lnwire + +import ( + "io" +) + +// OnionPacketSize is the size of the serialized Sphinx onion packet included +// in each UpdateAddHTLC message. The breakdown of the onion packet is as +// follows: 1-byte version, 33-byte ephemeral public key (for ECDH), 1300-bytes +// of per-hop data, and a 32-byte HMAC over the entire packet. +const OnionPacketSize = 1366 + +// UpdateAddHTLC is the message sent by Alice to Bob when she wishes to add an +// HTLC to his remote commitment transaction. In addition to information +// detailing the value, the ID, expiry, and the onion blob is also included +// which allows Bob to derive the next hop in the route. The HTLC added by this +// message is to be added to the remote node's "pending" HTLC's. A subsequent +// CommitSig message will move the pending HTLC to the newly created commitment +// transaction, marking them as "staged". +type UpdateAddHTLC struct { + // ChanID is the particular active channel that this UpdateAddHTLC is + // bound to. + ChanID ChannelID + + // ID is the identification server for this HTLC. This value is + // explicitly included as it allows nodes to survive single-sided + // restarts. The ID value for this sides starts at zero, and increases + // with each offered HTLC. + ID uint64 + + // Amount is the amount of millisatoshis this HTLC is worth. + Amount MilliSatoshi + + // PaymentHash is the payment hash to be included in the HTLC this + // request creates. The pre-image to this HTLC must be revealed by the + // upstream peer in order to fully settle the HTLC. + PaymentHash [32]byte + + // Expiry is the number of blocks after which this HTLC should expire. + // It is the receiver's duty to ensure that the outgoing HTLC has a + // sufficient expiry value to allow her to redeem the incoming HTLC. + Expiry uint32 + + // OnionBlob is the raw serialized mix header used to route an HTLC in + // a privacy-preserving manner. The mix header is defined currently to + // be parsed as a 4-tuple: (groupElement, routingInfo, headerMAC, + // body). First the receiving node should use the groupElement, and + // its current onion key to derive a shared secret with the source. + // Once the shared secret has been derived, the headerMAC should be + // checked FIRST. Note that the MAC only covers the routingInfo field. + // If the MAC matches, and the shared secret is fresh, then the node + // should strip off a layer of encryption, exposing the next hop to be + // used in the subsequent UpdateAddHTLC message. + OnionBlob [OnionPacketSize]byte +} + +// NewUpdateAddHTLC returns a new empty UpdateAddHTLC message. +func NewUpdateAddHTLC() *UpdateAddHTLC { + return &UpdateAddHTLC{} +} + +// A compile time check to ensure UpdateAddHTLC implements the lnwire.Message +// interface. +var _ Message = (*UpdateAddHTLC)(nil) + +// Decode deserializes a serialized UpdateAddHTLC message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateAddHTLC) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.ID, + &c.Amount, + c.PaymentHash[:], + &c.Expiry, + c.OnionBlob[:], + ) +} + +// Encode serializes the target UpdateAddHTLC into the passed io.Writer observing +// the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *UpdateAddHTLC) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.ID, + c.Amount, + c.PaymentHash[:], + c.Expiry, + c.OnionBlob[:], + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *UpdateAddHTLC) MsgType() MessageType { + return MsgUpdateAddHTLC +} + +// MaxPayloadLength returns the maximum allowed payload size for an UpdateAddHTLC +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateAddHTLC) MaxPayloadLength(uint32) uint32 { + // 1450 + return 32 + 8 + 4 + 8 + 32 + 1366 +} + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of peer.LinkUpdater interface. +func (c *UpdateAddHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/channeldb/migration/lnwire21/update_fail_htlc.go b/channeldb/migration/lnwire21/update_fail_htlc.go new file mode 100644 index 00000000..194f2ecd --- /dev/null +++ b/channeldb/migration/lnwire21/update_fail_htlc.go @@ -0,0 +1,95 @@ +package lnwire + +import ( + "io" +) + +// OpaqueReason is an opaque encrypted byte slice that encodes the exact +// failure reason and additional some supplemental data. The contents of this +// slice can only be decrypted by the sender of the original HTLC. +type OpaqueReason []byte + +// UpdateFailHTLC is sent by Alice to Bob in order to remove a previously added +// HTLC. Upon receipt of an UpdateFailHTLC the HTLC should be removed from the +// next commitment transaction, with the UpdateFailHTLC propagated backwards in +// the route to fully undo the HTLC. +type UpdateFailHTLC struct { + // ChanIDPoint is the particular active channel that this + // UpdateFailHTLC is bound to. + ChanID ChannelID + + // ID references which HTLC on the remote node's commitment transaction + // has timed out. + ID uint64 + + // Reason is an onion-encrypted blob that details why the HTLC was + // failed. This blob is only fully decryptable by the initiator of the + // HTLC message. + Reason OpaqueReason +} + +// A compile time check to ensure UpdateFailHTLC implements the lnwire.Message +// interface. +var _ Message = (*UpdateFailHTLC)(nil) + +// Decode deserializes a serialized UpdateFailHTLC message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailHTLC) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.ID, + &c.Reason, + ) +} + +// Encode serializes the target UpdateFailHTLC into the passed io.Writer observing +// the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailHTLC) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.ID, + c.Reason, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailHTLC) MsgType() MessageType { + return MsgUpdateFailHTLC +} + +// MaxPayloadLength returns the maximum allowed payload size for an UpdateFailHTLC +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailHTLC) MaxPayloadLength(uint32) uint32 { + var length uint32 + + // Length of the ChanID + length += 32 + + // Length of the ID + length += 8 + + // Length of the length opaque reason + length += 2 + + // Length of the Reason + length += 292 + + return length +} + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of peer.LinkUpdater interface. +func (c *UpdateFailHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/channeldb/migration/lnwire21/update_fail_malformed_htlc.go b/channeldb/migration/lnwire21/update_fail_malformed_htlc.go new file mode 100644 index 00000000..39d4b870 --- /dev/null +++ b/channeldb/migration/lnwire21/update_fail_malformed_htlc.go @@ -0,0 +1,83 @@ +package lnwire + +import ( + "crypto/sha256" + "io" +) + +// UpdateFailMalformedHTLC is sent by either the payment forwarder or by +// payment receiver to the payment sender in order to notify it that the onion +// blob can't be parsed. For that reason we send this message instead of +// obfuscate the onion failure. +type UpdateFailMalformedHTLC struct { + // ChanID is the particular active channel that this + // UpdateFailMalformedHTLC is bound to. + ChanID ChannelID + + // ID references which HTLC on the remote node's commitment transaction + // has timed out. + ID uint64 + + // ShaOnionBlob hash of the onion blob on which can't be parsed by the + // node in the payment path. + ShaOnionBlob [sha256.Size]byte + + // FailureCode the exact reason why onion blob haven't been parsed. + FailureCode FailCode +} + +// A compile time check to ensure UpdateFailMalformedHTLC implements the +// lnwire.Message interface. +var _ Message = (*UpdateFailMalformedHTLC)(nil) + +// Decode deserializes a serialized UpdateFailMalformedHTLC message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailMalformedHTLC) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.ID, + c.ShaOnionBlob[:], + &c.FailureCode, + ) +} + +// Encode serializes the target UpdateFailMalformedHTLC into the passed +// io.Writer observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailMalformedHTLC) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.ID, + c.ShaOnionBlob[:], + c.FailureCode, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailMalformedHTLC) MsgType() MessageType { + return MsgUpdateFailMalformedHTLC +} + +// MaxPayloadLength returns the maximum allowed payload size for a +// UpdateFailMalformedHTLC complete message observing the specified protocol +// version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFailMalformedHTLC) MaxPayloadLength(uint32) uint32 { + // 32 + 8 + 32 + 2 + return 74 +} + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of peer.LinkUpdater interface. +func (c *UpdateFailMalformedHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/channeldb/migration/lnwire21/update_fee.go b/channeldb/migration/lnwire21/update_fee.go new file mode 100644 index 00000000..2d27c377 --- /dev/null +++ b/channeldb/migration/lnwire21/update_fee.go @@ -0,0 +1,78 @@ +package lnwire + +import ( + "io" +) + +// UpdateFee is the message the channel initiator sends to the other peer if +// the channel commitment fee needs to be updated. +type UpdateFee struct { + // ChanID is the channel that this UpdateFee is meant for. + ChanID ChannelID + + // FeePerKw is the fee-per-kw on commit transactions that the sender of + // this message wants to use for this channel. + // + // TODO(halseth): make SatPerKWeight when fee estimation is moved to + // own package. Currently this will cause an import cycle. + FeePerKw uint32 +} + +// NewUpdateFee creates a new UpdateFee message. +func NewUpdateFee(chanID ChannelID, feePerKw uint32) *UpdateFee { + return &UpdateFee{ + ChanID: chanID, + FeePerKw: feePerKw, + } +} + +// A compile time check to ensure UpdateFee implements the lnwire.Message +// interface. +var _ Message = (*UpdateFee)(nil) + +// Decode deserializes a serialized UpdateFee message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFee) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.FeePerKw, + ) +} + +// Encode serializes the target UpdateFee into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFee) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.FeePerKw, + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFee) MsgType() MessageType { + return MsgUpdateFee +} + +// MaxPayloadLength returns the maximum allowed payload size for an UpdateFee +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFee) MaxPayloadLength(uint32) uint32 { + // 32 + 4 + return 36 +} + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of peer.LinkUpdater interface. +func (c *UpdateFee) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/channeldb/migration/lnwire21/update_fulfill_htlc.go b/channeldb/migration/lnwire21/update_fulfill_htlc.go new file mode 100644 index 00000000..6c0e6339 --- /dev/null +++ b/channeldb/migration/lnwire21/update_fulfill_htlc.go @@ -0,0 +1,88 @@ +package lnwire + +import ( + "io" +) + +// UpdateFulfillHTLC is sent by Alice to Bob when she wishes to settle a +// particular HTLC referenced by its HTLCKey within a specific active channel +// referenced by ChannelPoint. A subsequent CommitSig message will be sent by +// Alice to "lock-in" the removal of the specified HTLC, possible containing a +// batch signature covering several settled HTLC's. +type UpdateFulfillHTLC struct { + // ChanID references an active channel which holds the HTLC to be + // settled. + ChanID ChannelID + + // ID denotes the exact HTLC stage within the receiving node's + // commitment transaction to be removed. + ID uint64 + + // PaymentPreimage is the R-value preimage required to fully settle an + // HTLC. + PaymentPreimage [32]byte +} + +// NewUpdateFulfillHTLC returns a new empty UpdateFulfillHTLC. +func NewUpdateFulfillHTLC(chanID ChannelID, id uint64, + preimage [32]byte) *UpdateFulfillHTLC { + + return &UpdateFulfillHTLC{ + ChanID: chanID, + ID: id, + PaymentPreimage: preimage, + } +} + +// A compile time check to ensure UpdateFulfillHTLC implements the lnwire.Message +// interface. +var _ Message = (*UpdateFulfillHTLC)(nil) + +// Decode deserializes a serialized UpdateFulfillHTLC message stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFulfillHTLC) Decode(r io.Reader, pver uint32) error { + return ReadElements(r, + &c.ChanID, + &c.ID, + c.PaymentPreimage[:], + ) +} + +// Encode serializes the target UpdateFulfillHTLC into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFulfillHTLC) Encode(w io.Writer, pver uint32) error { + return WriteElements(w, + c.ChanID, + c.ID, + c.PaymentPreimage[:], + ) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFulfillHTLC) MsgType() MessageType { + return MsgUpdateFulfillHTLC +} + +// MaxPayloadLength returns the maximum allowed payload size for an UpdateFulfillHTLC +// complete message observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (c *UpdateFulfillHTLC) MaxPayloadLength(uint32) uint32 { + // 32 + 8 + 32 + return 72 +} + +// TargetChanID returns the channel id of the link for which this message is +// intended. +// +// NOTE: Part of peer.LinkUpdater interface. +func (c *UpdateFulfillHTLC) TargetChanID() ChannelID { + return c.ChanID +} diff --git a/channeldb/migration12/invoices.go b/channeldb/migration12/invoices.go index 0b83fe1f..6b83518f 100644 --- a/channeldb/migration12/invoices.go +++ b/channeldb/migration12/invoices.go @@ -7,8 +7,8 @@ import ( "time" "github.com/btcsuite/btcd/wire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/lntypes" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/tlv" ) diff --git a/channeldb/migration12/migration.go b/channeldb/migration12/migration.go index 66f988de..2ec9e354 100644 --- a/channeldb/migration12/migration.go +++ b/channeldb/migration12/migration.go @@ -4,7 +4,7 @@ import ( "bytes" "github.com/lightningnetwork/lnd/channeldb/kvdb" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) var emptyFeatures = lnwire.NewFeatureVector(nil, nil) diff --git a/channeldb/migration_01_to_11/channel.go b/channeldb/migration_01_to_11/channel.go index e67c0c69..2abdfd28 100644 --- a/channeldb/migration_01_to_11/channel.go +++ b/channeldb/migration_01_to_11/channel.go @@ -12,8 +12,8 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/keychain" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/shachain" ) diff --git a/channeldb/migration_01_to_11/channel_test.go b/channeldb/migration_01_to_11/channel_test.go index 1380828e..7e3ba6e0 100644 --- a/channeldb/migration_01_to_11/channel_test.go +++ b/channeldb/migration_01_to_11/channel_test.go @@ -11,8 +11,8 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" _ "github.com/btcsuite/btcwallet/walletdb/bdb" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/keychain" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/shachain" ) diff --git a/channeldb/migration_01_to_11/codec.go b/channeldb/migration_01_to_11/codec.go index 1727c8c9..6ee6f608 100644 --- a/channeldb/migration_01_to_11/codec.go +++ b/channeldb/migration_01_to_11/codec.go @@ -10,8 +10,8 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/keychain" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/shachain" ) diff --git a/channeldb/migration_01_to_11/graph.go b/channeldb/migration_01_to_11/graph.go index c7e78e74..9caa6ad8 100644 --- a/channeldb/migration_01_to_11/graph.go +++ b/channeldb/migration_01_to_11/graph.go @@ -14,7 +14,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/channeldb/kvdb" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) var ( diff --git a/channeldb/migration_01_to_11/graph_test.go b/channeldb/migration_01_to_11/graph_test.go index dc21fccf..dc42ba20 100644 --- a/channeldb/migration_01_to_11/graph_test.go +++ b/channeldb/migration_01_to_11/graph_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/btcsuite/btcd/btcec" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) var ( diff --git a/channeldb/migration_01_to_11/invoices.go b/channeldb/migration_01_to_11/invoices.go index ceb21a33..b60008ee 100644 --- a/channeldb/migration_01_to_11/invoices.go +++ b/channeldb/migration_01_to_11/invoices.go @@ -9,8 +9,8 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb/kvdb" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/lntypes" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/tlv" ) diff --git a/channeldb/migration_01_to_11/migration_09_legacy_serialization.go b/channeldb/migration_01_to_11/migration_09_legacy_serialization.go index fda08226..461e983b 100644 --- a/channeldb/migration_01_to_11/migration_09_legacy_serialization.go +++ b/channeldb/migration_01_to_11/migration_09_legacy_serialization.go @@ -8,8 +8,8 @@ import ( "sort" "github.com/lightningnetwork/lnd/channeldb/kvdb" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/lntypes" - "github.com/lightningnetwork/lnd/lnwire" ) var ( diff --git a/channeldb/migration_01_to_11/migration_11_invoices.go b/channeldb/migration_01_to_11/migration_11_invoices.go index 7cb9ea88..cec7784e 100644 --- a/channeldb/migration_01_to_11/migration_11_invoices.go +++ b/channeldb/migration_01_to_11/migration_11_invoices.go @@ -9,8 +9,8 @@ import ( bitcoinCfg "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb/kvdb" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11/zpay32" - "github.com/lightningnetwork/lnd/lnwire" litecoinCfg "github.com/ltcsuite/ltcd/chaincfg" ) diff --git a/channeldb/migration_01_to_11/migrations.go b/channeldb/migration_01_to_11/migrations.go index 35be510e..5232628d 100644 --- a/channeldb/migration_01_to_11/migrations.go +++ b/channeldb/migration_01_to_11/migrations.go @@ -8,7 +8,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/lightningnetwork/lnd/channeldb/kvdb" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) // MigrateNodeAndEdgeUpdateIndex is a migration function that will update the diff --git a/channeldb/migration_01_to_11/migrations_test.go b/channeldb/migration_01_to_11/migrations_test.go index 3677c90b..c0e57ec0 100644 --- a/channeldb/migration_01_to_11/migrations_test.go +++ b/channeldb/migration_01_to_11/migrations_test.go @@ -14,8 +14,8 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/channeldb/kvdb" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/lntypes" - "github.com/lightningnetwork/lnd/lnwire" ) // TestPaymentStatusesMigration checks that already completed payments will have diff --git a/channeldb/migration_01_to_11/payments.go b/channeldb/migration_01_to_11/payments.go index e44be003..2ccb8bca 100644 --- a/channeldb/migration_01_to_11/payments.go +++ b/channeldb/migration_01_to_11/payments.go @@ -12,8 +12,8 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb/kvdb" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/lntypes" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/tlv" ) diff --git a/channeldb/migration_01_to_11/payments_test.go b/channeldb/migration_01_to_11/payments_test.go index c5584079..17f7a59a 100644 --- a/channeldb/migration_01_to_11/payments_test.go +++ b/channeldb/migration_01_to_11/payments_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/btcsuite/btcd/btcec" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) var ( diff --git a/channeldb/migration_01_to_11/route.go b/channeldb/migration_01_to_11/route.go index 1dbfff60..2b43eaad 100644 --- a/channeldb/migration_01_to_11/route.go +++ b/channeldb/migration_01_to_11/route.go @@ -11,7 +11,7 @@ import ( "github.com/btcsuite/btcd/btcec" sphinx "github.com/lightningnetwork/lightning-onion" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/tlv" ) diff --git a/channeldb/migration_01_to_11/zpay32/amountunits.go b/channeldb/migration_01_to_11/zpay32/amountunits.go index f53f3ff0..0cc1fcdb 100644 --- a/channeldb/migration_01_to_11/zpay32/amountunits.go +++ b/channeldb/migration_01_to_11/zpay32/amountunits.go @@ -4,7 +4,7 @@ import ( "fmt" "strconv" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) var ( diff --git a/channeldb/migration_01_to_11/zpay32/decode.go b/channeldb/migration_01_to_11/zpay32/decode.go index 07929b45..0803cc9b 100644 --- a/channeldb/migration_01_to_11/zpay32/decode.go +++ b/channeldb/migration_01_to_11/zpay32/decode.go @@ -13,7 +13,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/bech32" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) // Decode parses the provided encoded invoice and returns a decoded Invoice if diff --git a/channeldb/migration_01_to_11/zpay32/invoice.go b/channeldb/migration_01_to_11/zpay32/invoice.go index dbb991e6..83718c9b 100644 --- a/channeldb/migration_01_to_11/zpay32/invoice.go +++ b/channeldb/migration_01_to_11/zpay32/invoice.go @@ -8,7 +8,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" - "github.com/lightningnetwork/lnd/lnwire" + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) const (