channeldb/migration: copy current lnwire to migration dir
To avoid code changing underneath the static migrations, we copy the lnwire dependency in its current form into the migration directory. Ideally the migrations doesn't depend on any code that might change, this takes us a step closer.
This commit is contained in:
parent
c6a8816043
commit
7569cca19b
@ -8,6 +8,7 @@ run:
|
|||||||
|
|
||||||
skip-dirs:
|
skip-dirs:
|
||||||
- channeldb/migration_01_to_11
|
- channeldb/migration_01_to_11
|
||||||
|
- channeldb/migration/lnwire21
|
||||||
|
|
||||||
build-tags:
|
build-tags:
|
||||||
- autopilotrpc
|
- autopilotrpc
|
||||||
|
182
channeldb/migration/lnwire21/accept_channel.go
Normal file
182
channeldb/migration/lnwire21/accept_channel.go
Normal file
@ -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
|
||||||
|
}
|
108
channeldb/migration/lnwire21/announcement_signatures.go
Normal file
108
channeldb/migration/lnwire21/announcement_signatures.go
Normal file
@ -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
|
||||||
|
}
|
160
channeldb/migration/lnwire21/channel_announcement.go
Normal file
160
channeldb/migration/lnwire21/channel_announcement.go
Normal file
@ -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
|
||||||
|
}
|
91
channeldb/migration/lnwire21/channel_id.go
Normal file
91
channeldb/migration/lnwire21/channel_id.go
Normal file
@ -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
|
||||||
|
}
|
166
channeldb/migration/lnwire21/channel_reestablish.go
Normal file
166
channeldb/migration/lnwire21/channel_reestablish.go
Normal file
@ -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
|
||||||
|
}
|
258
channeldb/migration/lnwire21/channel_update.go
Normal file
258
channeldb/migration/lnwire21/channel_update.go
Normal file
@ -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
|
||||||
|
}
|
88
channeldb/migration/lnwire21/closing_signed.go
Normal file
88
channeldb/migration/lnwire21/closing_signed.go
Normal file
@ -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
|
||||||
|
}
|
95
channeldb/migration/lnwire21/commit_sig.go
Normal file
95
channeldb/migration/lnwire21/commit_sig.go
Normal file
@ -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
|
||||||
|
}
|
139
channeldb/migration/lnwire21/error.go
Normal file
139
channeldb/migration/lnwire21/error.go
Normal file
@ -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
|
||||||
|
}
|
482
channeldb/migration/lnwire21/features.go
Normal file
482
channeldb/migration/lnwire21/features.go
Normal file
@ -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)
|
||||||
|
}
|
66
channeldb/migration/lnwire21/funding_created.go
Normal file
66
channeldb/migration/lnwire21/funding_created.go
Normal file
@ -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
|
||||||
|
}
|
83
channeldb/migration/lnwire21/funding_locked.go
Normal file
83
channeldb/migration/lnwire21/funding_locked.go
Normal file
@ -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
|
||||||
|
}
|
55
channeldb/migration/lnwire21/funding_signed.go
Normal file
55
channeldb/migration/lnwire21/funding_signed.go
Normal file
@ -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
|
||||||
|
}
|
80
channeldb/migration/lnwire21/gossip_timestamp_range.go
Normal file
80
channeldb/migration/lnwire21/gossip_timestamp_range.go
Normal file
@ -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
|
||||||
|
}
|
73
channeldb/migration/lnwire21/init_message.go
Normal file
73
channeldb/migration/lnwire21/init_message.go
Normal file
@ -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
|
||||||
|
}
|
845
channeldb/migration/lnwire21/lnwire.go
Normal file
845
channeldb/migration/lnwire21/lnwire.go
Normal file
@ -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
|
||||||
|
}
|
296
channeldb/migration/lnwire21/message.go
Normal file
296
channeldb/migration/lnwire21/message.go
Normal file
@ -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 "<unknown>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
51
channeldb/migration/lnwire21/msat.go
Normal file
51
channeldb/migration/lnwire21/msat.go
Normal file
@ -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?
|
54
channeldb/migration/lnwire21/netaddress.go
Normal file
54
channeldb/migration/lnwire21/netaddress.go
Normal file
@ -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: <pubkey>@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()
|
||||||
|
}
|
192
channeldb/migration/lnwire21/node_announcement.go
Normal file
192
channeldb/migration/lnwire21/node_announcement.go
Normal file
@ -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
|
||||||
|
}
|
1428
channeldb/migration/lnwire21/onion_error.go
Normal file
1428
channeldb/migration/lnwire21/onion_error.go
Normal file
@ -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 "<unknown>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
225
channeldb/migration/lnwire21/open_channel.go
Normal file
225
channeldb/migration/lnwire21/open_channel.go
Normal file
@ -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
|
||||||
|
}
|
67
channeldb/migration/lnwire21/ping.go
Normal file
67
channeldb/migration/lnwire21/ping.go
Normal file
@ -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
|
||||||
|
}
|
63
channeldb/migration/lnwire21/pong.go
Normal file
63
channeldb/migration/lnwire21/pong.go
Normal file
@ -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
|
||||||
|
}
|
89
channeldb/migration/lnwire21/query_channel_range.go
Normal file
89
channeldb/migration/lnwire21/query_channel_range.go
Normal file
@ -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)
|
||||||
|
}
|
429
channeldb/migration/lnwire21/query_short_chan_ids.go
Normal file
429
channeldb/migration/lnwire21/query_short_chan_ids.go
Normal file
@ -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
|
||||||
|
}
|
90
channeldb/migration/lnwire21/reply_channel_range.go
Normal file
90
channeldb/migration/lnwire21/reply_channel_range.go
Normal file
@ -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
|
||||||
|
}
|
74
channeldb/migration/lnwire21/reply_short_chan_ids_end.go
Normal file
74
channeldb/migration/lnwire21/reply_short_chan_ids_end.go
Normal file
@ -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
|
||||||
|
}
|
91
channeldb/migration/lnwire21/revoke_and_ack.go
Normal file
91
channeldb/migration/lnwire21/revoke_and_ack.go
Normal file
@ -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
|
||||||
|
}
|
48
channeldb/migration/lnwire21/short_channel_id.go
Normal file
48
channeldb/migration/lnwire21/short_channel_id.go
Normal file
@ -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)
|
||||||
|
}
|
87
channeldb/migration/lnwire21/shutdown.go
Normal file
87
channeldb/migration/lnwire21/shutdown.go
Normal file
@ -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
|
||||||
|
}
|
129
channeldb/migration/lnwire21/signature.go
Normal file
129
channeldb/migration/lnwire21/signature.go
Normal file
@ -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 <length> 0x02 <length r> r 0x02 <length s> 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 <length> 0x02 <length r> r 0x02 <length s> 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}
|
||||||
|
}
|
119
channeldb/migration/lnwire21/update_add_htlc.go
Normal file
119
channeldb/migration/lnwire21/update_add_htlc.go
Normal file
@ -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
|
||||||
|
}
|
95
channeldb/migration/lnwire21/update_fail_htlc.go
Normal file
95
channeldb/migration/lnwire21/update_fail_htlc.go
Normal file
@ -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
|
||||||
|
}
|
83
channeldb/migration/lnwire21/update_fail_malformed_htlc.go
Normal file
83
channeldb/migration/lnwire21/update_fail_malformed_htlc.go
Normal file
@ -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
|
||||||
|
}
|
78
channeldb/migration/lnwire21/update_fee.go
Normal file
78
channeldb/migration/lnwire21/update_fee.go
Normal file
@ -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
|
||||||
|
}
|
88
channeldb/migration/lnwire21/update_fulfill_htlc.go
Normal file
88
channeldb/migration/lnwire21/update_fulfill_htlc.go
Normal file
@ -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
|
||||||
|
}
|
@ -7,8 +7,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"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)
|
var emptyFeatures = lnwire.NewFeatureVector(nil, nil)
|
||||||
|
@ -12,8 +12,8 @@ import (
|
|||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
|
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
bitcoinCfg "github.com/btcsuite/btcd/chaincfg"
|
bitcoinCfg "github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"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/channeldb/migration_01_to_11/zpay32"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
litecoinCfg "github.com/ltcsuite/ltcd/chaincfg"
|
litecoinCfg "github.com/ltcsuite/ltcd/chaincfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"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
|
// MigrateNodeAndEdgeUpdateIndex is a migration function that will update the
|
||||||
|
@ -14,8 +14,8 @@ import (
|
|||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestPaymentStatusesMigration checks that already completed payments will have
|
// TestPaymentStatusesMigration checks that already completed payments will have
|
||||||
|
@ -12,8 +12,8 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
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/record"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/btcsuite/btcutil/bech32"
|
"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
|
// Decode parses the provided encoded invoice and returns a decoded Invoice if
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
Loading…
Reference in New Issue
Block a user