752 lines
27 KiB
Go
752 lines
27 KiB
Go
package migration_01_to_11
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/btcsuite/btcutil"
|
|
"github.com/lightningnetwork/lnd/keychain"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
"github.com/lightningnetwork/lnd/shachain"
|
|
)
|
|
|
|
var (
|
|
// closedChannelBucket stores summarization information concerning
|
|
// previously open, but now closed channels.
|
|
closedChannelBucket = []byte("closed-chan-bucket")
|
|
|
|
// openChanBucket stores all the currently open channels. This bucket
|
|
// has a second, nested bucket which is keyed by a node's ID. Within
|
|
// that node ID bucket, all attributes required to track, update, and
|
|
// close a channel are stored.
|
|
//
|
|
// openChan -> nodeID -> chanPoint
|
|
//
|
|
// TODO(roasbeef): flesh out comment
|
|
openChannelBucket = []byte("open-chan-bucket")
|
|
)
|
|
|
|
// ChannelType is an enum-like type that describes one of several possible
|
|
// channel types. Each open channel is associated with a particular type as the
|
|
// channel type may determine how higher level operations are conducted such as
|
|
// fee negotiation, channel closing, the format of HTLCs, etc.
|
|
// TODO(roasbeef): split up per-chain?
|
|
type ChannelType uint8
|
|
|
|
const (
|
|
// NOTE: iota isn't used here for this enum needs to be stable
|
|
// long-term as it will be persisted to the database.
|
|
|
|
// SingleFunder represents a channel wherein one party solely funds the
|
|
// entire capacity of the channel.
|
|
SingleFunder ChannelType = 0
|
|
)
|
|
|
|
// ChannelConstraints represents a set of constraints meant to allow a node to
|
|
// limit their exposure, enact flow control and ensure that all HTLCs are
|
|
// economically relevant. This struct will be mirrored for both sides of the
|
|
// channel, as each side will enforce various constraints that MUST be adhered
|
|
// to for the life time of the channel. The parameters for each of these
|
|
// constraints are static for the duration of the channel, meaning the channel
|
|
// must be torn down for them to change.
|
|
type ChannelConstraints struct {
|
|
// DustLimit is the threshold (in satoshis) below which any outputs
|
|
// should be trimmed. When an output is trimmed, it isn't materialized
|
|
// as an actual output, but is instead burned to miner's fees.
|
|
DustLimit btcutil.Amount
|
|
|
|
// ChanReserve is an absolute reservation on the channel for the
|
|
// owner of this set of constraints. This means that the current
|
|
// settled balance for this node CANNOT dip below the reservation
|
|
// amount. This acts as a defense against costless attacks when
|
|
// either side no longer has any skin in the game.
|
|
ChanReserve btcutil.Amount
|
|
|
|
// MaxPendingAmount is the maximum pending HTLC value that the
|
|
// owner of these constraints can offer the remote node at a
|
|
// particular time.
|
|
MaxPendingAmount lnwire.MilliSatoshi
|
|
|
|
// MinHTLC is the minimum HTLC value that the owner of these
|
|
// constraints can offer the remote node. If any HTLCs below this
|
|
// amount are offered, then the HTLC will be rejected. This, in
|
|
// tandem with the dust limit allows a node to regulate the
|
|
// smallest HTLC that it deems economically relevant.
|
|
MinHTLC lnwire.MilliSatoshi
|
|
|
|
// MaxAcceptedHtlcs is the maximum number of HTLCs that the owner of
|
|
// this set of constraints can offer the remote node. This allows each
|
|
// node to limit their over all exposure to HTLCs that may need to be
|
|
// acted upon in the case of a unilateral channel closure or a contract
|
|
// breach.
|
|
MaxAcceptedHtlcs uint16
|
|
|
|
// CsvDelay is the relative time lock delay expressed in blocks. Any
|
|
// settled outputs that pay to the owner of this channel configuration
|
|
// MUST ensure that the delay branch uses this value as the relative
|
|
// time lock. Similarly, any HTLC's offered by this node should use
|
|
// this value as well.
|
|
CsvDelay uint16
|
|
}
|
|
|
|
// ChannelConfig is a struct that houses the various configuration opens for
|
|
// channels. Each side maintains an instance of this configuration file as it
|
|
// governs: how the funding and commitment transaction to be created, the
|
|
// nature of HTLC's allotted, the keys to be used for delivery, and relative
|
|
// time lock parameters.
|
|
type ChannelConfig struct {
|
|
// ChannelConstraints is the set of constraints that must be upheld for
|
|
// the duration of the channel for the owner of this channel
|
|
// configuration. Constraints govern a number of flow control related
|
|
// parameters, also including the smallest HTLC that will be accepted
|
|
// by a participant.
|
|
ChannelConstraints
|
|
|
|
// MultiSigKey is the key to be used within the 2-of-2 output script
|
|
// for the owner of this channel config.
|
|
MultiSigKey keychain.KeyDescriptor
|
|
|
|
// RevocationBasePoint is the base public key to be used when deriving
|
|
// revocation keys for the remote node's commitment transaction. This
|
|
// will be combined along with a per commitment secret to derive a
|
|
// unique revocation key for each state.
|
|
RevocationBasePoint keychain.KeyDescriptor
|
|
|
|
// PaymentBasePoint is the base public key to be used when deriving
|
|
// the key used within the non-delayed pay-to-self output on the
|
|
// commitment transaction for a node. This will be combined with a
|
|
// tweak derived from the per-commitment point to ensure unique keys
|
|
// for each commitment transaction.
|
|
PaymentBasePoint keychain.KeyDescriptor
|
|
|
|
// DelayBasePoint is the base public key to be used when deriving the
|
|
// key used within the delayed pay-to-self output on the commitment
|
|
// transaction for a node. This will be combined with a tweak derived
|
|
// from the per-commitment point to ensure unique keys for each
|
|
// commitment transaction.
|
|
DelayBasePoint keychain.KeyDescriptor
|
|
|
|
// HtlcBasePoint is the base public key to be used when deriving the
|
|
// local HTLC key. The derived key (combined with the tweak derived
|
|
// from the per-commitment point) is used within the "to self" clause
|
|
// within any HTLC output scripts.
|
|
HtlcBasePoint keychain.KeyDescriptor
|
|
}
|
|
|
|
// ChannelCommitment is a snapshot of the commitment state at a particular
|
|
// point in the commitment chain. With each state transition, a snapshot of the
|
|
// current state along with all non-settled HTLCs are recorded. These snapshots
|
|
// detail the state of the _remote_ party's commitment at a particular state
|
|
// number. For ourselves (the local node) we ONLY store our most recent
|
|
// (unrevoked) state for safety purposes.
|
|
type ChannelCommitment struct {
|
|
// CommitHeight is the update number that this ChannelDelta represents
|
|
// the total number of commitment updates to this point. This can be
|
|
// viewed as sort of a "commitment height" as this number is
|
|
// monotonically increasing.
|
|
CommitHeight uint64
|
|
|
|
// LocalLogIndex is the cumulative log index index of the local node at
|
|
// this point in the commitment chain. This value will be incremented
|
|
// for each _update_ added to the local update log.
|
|
LocalLogIndex uint64
|
|
|
|
// LocalHtlcIndex is the current local running HTLC index. This value
|
|
// will be incremented for each outgoing HTLC the local node offers.
|
|
LocalHtlcIndex uint64
|
|
|
|
// RemoteLogIndex is the cumulative log index index of the remote node
|
|
// at this point in the commitment chain. This value will be
|
|
// incremented for each _update_ added to the remote update log.
|
|
RemoteLogIndex uint64
|
|
|
|
// RemoteHtlcIndex is the current remote running HTLC index. This value
|
|
// will be incremented for each outgoing HTLC the remote node offers.
|
|
RemoteHtlcIndex uint64
|
|
|
|
// LocalBalance is the current available settled balance within the
|
|
// channel directly spendable by us.
|
|
LocalBalance lnwire.MilliSatoshi
|
|
|
|
// RemoteBalance is the current available settled balance within the
|
|
// channel directly spendable by the remote node.
|
|
RemoteBalance lnwire.MilliSatoshi
|
|
|
|
// CommitFee is the amount calculated to be paid in fees for the
|
|
// current set of commitment transactions. The fee amount is persisted
|
|
// with the channel in order to allow the fee amount to be removed and
|
|
// recalculated with each channel state update, including updates that
|
|
// happen after a system restart.
|
|
CommitFee btcutil.Amount
|
|
|
|
// FeePerKw is the min satoshis/kilo-weight that should be paid within
|
|
// the commitment transaction for the entire duration of the channel's
|
|
// lifetime. This field may be updated during normal operation of the
|
|
// channel as on-chain conditions change.
|
|
//
|
|
// TODO(halseth): make this SatPerKWeight. Cannot be done atm because
|
|
// this will cause the import cycle lnwallet<->channeldb. Fee
|
|
// estimation stuff should be in its own package.
|
|
FeePerKw btcutil.Amount
|
|
|
|
// CommitTx is the latest version of the commitment state, broadcast
|
|
// able by us.
|
|
CommitTx *wire.MsgTx
|
|
|
|
// CommitSig is one half of the signature required to fully complete
|
|
// the script for the commitment transaction above. This is the
|
|
// signature signed by the remote party for our version of the
|
|
// commitment transactions.
|
|
CommitSig []byte
|
|
|
|
// Htlcs is the set of HTLC's that are pending at this particular
|
|
// commitment height.
|
|
Htlcs []HTLC
|
|
|
|
// TODO(roasbeef): pending commit pointer?
|
|
// * lets just walk through
|
|
}
|
|
|
|
// ChannelStatus is a bit vector used to indicate whether an OpenChannel is in
|
|
// the default usable state, or a state where it shouldn't be used.
|
|
type ChannelStatus uint8
|
|
|
|
var (
|
|
// ChanStatusDefault is the normal state of an open channel.
|
|
ChanStatusDefault ChannelStatus
|
|
|
|
// ChanStatusBorked indicates that the channel has entered an
|
|
// irreconcilable state, triggered by a state desynchronization or
|
|
// channel breach. Channels in this state should never be added to the
|
|
// htlc switch.
|
|
ChanStatusBorked ChannelStatus = 1
|
|
|
|
// ChanStatusCommitBroadcasted indicates that a commitment for this
|
|
// channel has been broadcasted.
|
|
ChanStatusCommitBroadcasted ChannelStatus = 1 << 1
|
|
|
|
// ChanStatusLocalDataLoss indicates that we have lost channel state
|
|
// for this channel, and broadcasting our latest commitment might be
|
|
// considered a breach.
|
|
//
|
|
// TODO(halseh): actually enforce that we are not force closing such a
|
|
// channel.
|
|
ChanStatusLocalDataLoss ChannelStatus = 1 << 2
|
|
|
|
// ChanStatusRestored is a status flag that signals that the channel
|
|
// has been restored, and doesn't have all the fields a typical channel
|
|
// will have.
|
|
ChanStatusRestored ChannelStatus = 1 << 3
|
|
)
|
|
|
|
// chanStatusStrings maps a ChannelStatus to a human friendly string that
|
|
// describes that status.
|
|
var chanStatusStrings = map[ChannelStatus]string{
|
|
ChanStatusDefault: "ChanStatusDefault",
|
|
ChanStatusBorked: "ChanStatusBorked",
|
|
ChanStatusCommitBroadcasted: "ChanStatusCommitBroadcasted",
|
|
ChanStatusLocalDataLoss: "ChanStatusLocalDataLoss",
|
|
ChanStatusRestored: "ChanStatusRestored",
|
|
}
|
|
|
|
// orderedChanStatusFlags is an in-order list of all that channel status flags.
|
|
var orderedChanStatusFlags = []ChannelStatus{
|
|
ChanStatusDefault,
|
|
ChanStatusBorked,
|
|
ChanStatusCommitBroadcasted,
|
|
ChanStatusLocalDataLoss,
|
|
ChanStatusRestored,
|
|
}
|
|
|
|
// String returns a human-readable representation of the ChannelStatus.
|
|
func (c ChannelStatus) String() string {
|
|
// If no flags are set, then this is the default case.
|
|
if c == 0 {
|
|
return chanStatusStrings[ChanStatusDefault]
|
|
}
|
|
|
|
// Add individual bit flags.
|
|
statusStr := ""
|
|
for _, flag := range orderedChanStatusFlags {
|
|
if c&flag == flag {
|
|
statusStr += chanStatusStrings[flag] + "|"
|
|
c -= flag
|
|
}
|
|
}
|
|
|
|
// Remove anything to the right of the final bar, including it as well.
|
|
statusStr = strings.TrimRight(statusStr, "|")
|
|
|
|
// Add any remaining flags which aren't accounted for as hex.
|
|
if c != 0 {
|
|
statusStr += "|0x" + strconv.FormatUint(uint64(c), 16)
|
|
}
|
|
|
|
// If this was purely an unknown flag, then remove the extra bar at the
|
|
// start of the string.
|
|
statusStr = strings.TrimLeft(statusStr, "|")
|
|
|
|
return statusStr
|
|
}
|
|
|
|
// OpenChannel encapsulates the persistent and dynamic state of an open channel
|
|
// with a remote node. An open channel supports several options for on-disk
|
|
// serialization depending on the exact context. Full (upon channel creation)
|
|
// state commitments, and partial (due to a commitment update) writes are
|
|
// supported. Each partial write due to a state update appends the new update
|
|
// to an on-disk log, which can then subsequently be queried in order to
|
|
// "time-travel" to a prior state.
|
|
type OpenChannel struct {
|
|
// ChanType denotes which type of channel this is.
|
|
ChanType ChannelType
|
|
|
|
// ChainHash is a hash which represents the blockchain that this
|
|
// channel will be opened within. This value is typically the genesis
|
|
// hash. In the case that the original chain went through a contentious
|
|
// hard-fork, then this value will be tweaked using the unique fork
|
|
// point on each branch.
|
|
ChainHash chainhash.Hash
|
|
|
|
// FundingOutpoint is the outpoint of the final funding transaction.
|
|
// This value uniquely and globally identifies the channel within the
|
|
// target blockchain as specified by the chain hash parameter.
|
|
FundingOutpoint wire.OutPoint
|
|
|
|
// ShortChannelID encodes the exact location in the chain in which the
|
|
// channel was initially confirmed. This includes: the block height,
|
|
// transaction index, and the output within the target transaction.
|
|
ShortChannelID lnwire.ShortChannelID
|
|
|
|
// IsPending indicates whether a channel's funding transaction has been
|
|
// confirmed.
|
|
IsPending bool
|
|
|
|
// IsInitiator is a bool which indicates if we were the original
|
|
// initiator for the channel. This value may affect how higher levels
|
|
// negotiate fees, or close the channel.
|
|
IsInitiator bool
|
|
|
|
// FundingBroadcastHeight is the height in which the funding
|
|
// transaction was broadcast. This value can be used by higher level
|
|
// sub-systems to determine if a channel is stale and/or should have
|
|
// been confirmed before a certain height.
|
|
FundingBroadcastHeight uint32
|
|
|
|
// NumConfsRequired is the number of confirmations a channel's funding
|
|
// transaction must have received in order to be considered available
|
|
// for normal transactional use.
|
|
NumConfsRequired uint16
|
|
|
|
// ChannelFlags holds the flags that were sent as part of the
|
|
// open_channel message.
|
|
ChannelFlags lnwire.FundingFlag
|
|
|
|
// IdentityPub is the identity public key of the remote node this
|
|
// channel has been established with.
|
|
IdentityPub *btcec.PublicKey
|
|
|
|
// Capacity is the total capacity of this channel.
|
|
Capacity btcutil.Amount
|
|
|
|
// TotalMSatSent is the total number of milli-satoshis we've sent
|
|
// within this channel.
|
|
TotalMSatSent lnwire.MilliSatoshi
|
|
|
|
// TotalMSatReceived is the total number of milli-satoshis we've
|
|
// received within this channel.
|
|
TotalMSatReceived lnwire.MilliSatoshi
|
|
|
|
// LocalChanCfg is the channel configuration for the local node.
|
|
LocalChanCfg ChannelConfig
|
|
|
|
// RemoteChanCfg is the channel configuration for the remote node.
|
|
RemoteChanCfg ChannelConfig
|
|
|
|
// LocalCommitment is the current local commitment state for the local
|
|
// party. This is stored distinct from the state of the remote party
|
|
// as there are certain asymmetric parameters which affect the
|
|
// structure of each commitment.
|
|
LocalCommitment ChannelCommitment
|
|
|
|
// RemoteCommitment is the current remote commitment state for the
|
|
// remote party. This is stored distinct from the state of the local
|
|
// party as there are certain asymmetric parameters which affect the
|
|
// structure of each commitment.
|
|
RemoteCommitment ChannelCommitment
|
|
|
|
// RemoteCurrentRevocation is the current revocation for their
|
|
// commitment transaction. However, since this the derived public key,
|
|
// we don't yet have the private key so we aren't yet able to verify
|
|
// that it's actually in the hash chain.
|
|
RemoteCurrentRevocation *btcec.PublicKey
|
|
|
|
// RemoteNextRevocation is the revocation key to be used for the *next*
|
|
// commitment transaction we create for the local node. Within the
|
|
// specification, this value is referred to as the
|
|
// per-commitment-point.
|
|
RemoteNextRevocation *btcec.PublicKey
|
|
|
|
// RevocationProducer is used to generate the revocation in such a way
|
|
// that remote side might store it efficiently and have the ability to
|
|
// restore the revocation by index if needed. Current implementation of
|
|
// secret producer is shachain producer.
|
|
RevocationProducer shachain.Producer
|
|
|
|
// RevocationStore is used to efficiently store the revocations for
|
|
// previous channels states sent to us by remote side. Current
|
|
// implementation of secret store is shachain store.
|
|
RevocationStore shachain.Store
|
|
|
|
// FundingTxn is the transaction containing this channel's funding
|
|
// outpoint. Upon restarts, this txn will be rebroadcast if the channel
|
|
// is found to be pending.
|
|
//
|
|
// NOTE: This value will only be populated for single-funder channels
|
|
// for which we are the initiator.
|
|
FundingTxn *wire.MsgTx
|
|
|
|
// TODO(roasbeef): eww
|
|
Db *DB
|
|
|
|
// TODO(roasbeef): just need to store local and remote HTLC's?
|
|
|
|
sync.RWMutex
|
|
}
|
|
|
|
// ShortChanID returns the current ShortChannelID of this channel.
|
|
func (c *OpenChannel) ShortChanID() lnwire.ShortChannelID {
|
|
c.RLock()
|
|
defer c.RUnlock()
|
|
|
|
return c.ShortChannelID
|
|
}
|
|
|
|
// HTLC is the on-disk representation of a hash time-locked contract. HTLCs are
|
|
// contained within ChannelDeltas which encode the current state of the
|
|
// commitment between state updates.
|
|
//
|
|
// TODO(roasbeef): save space by using smaller ints at tail end?
|
|
type HTLC struct {
|
|
// Signature is the signature for the second level covenant transaction
|
|
// for this HTLC. The second level transaction is a timeout tx in the
|
|
// case that this is an outgoing HTLC, and a success tx in the case
|
|
// that this is an incoming HTLC.
|
|
//
|
|
// TODO(roasbeef): make [64]byte instead?
|
|
Signature []byte
|
|
|
|
// RHash is the payment hash of the HTLC.
|
|
RHash [32]byte
|
|
|
|
// Amt is the amount of milli-satoshis this HTLC escrows.
|
|
Amt lnwire.MilliSatoshi
|
|
|
|
// RefundTimeout is the absolute timeout on the HTLC that the sender
|
|
// must wait before reclaiming the funds in limbo.
|
|
RefundTimeout uint32
|
|
|
|
// OutputIndex is the output index for this particular HTLC output
|
|
// within the commitment transaction.
|
|
OutputIndex int32
|
|
|
|
// Incoming denotes whether we're the receiver or the sender of this
|
|
// HTLC.
|
|
Incoming bool
|
|
|
|
// OnionBlob is an opaque blob which is used to complete multi-hop
|
|
// routing.
|
|
OnionBlob []byte
|
|
|
|
// HtlcIndex is the HTLC counter index of this active, outstanding
|
|
// HTLC. This differs from the LogIndex, as the HtlcIndex is only
|
|
// incremented for each offered HTLC, while they LogIndex is
|
|
// incremented for each update (includes settle+fail).
|
|
HtlcIndex uint64
|
|
|
|
// LogIndex is the cumulative log index of this HTLC. This differs
|
|
// from the HtlcIndex as this will be incremented for each new log
|
|
// update added.
|
|
LogIndex uint64
|
|
}
|
|
|
|
// CircuitKey is used by a channel to uniquely identify the HTLCs it receives
|
|
// from the switch, and is used to purge our in-memory state of HTLCs that have
|
|
// already been processed by a link. Two list of CircuitKeys are included in
|
|
// each CommitDiff to allow a link to determine which in-memory htlcs directed
|
|
// the opening and closing of circuits in the switch's circuit map.
|
|
type CircuitKey struct {
|
|
// ChanID is the short chanid indicating the HTLC's origin.
|
|
//
|
|
// NOTE: It is fine for this value to be blank, as this indicates a
|
|
// locally-sourced payment.
|
|
ChanID lnwire.ShortChannelID
|
|
|
|
// HtlcID is the unique htlc index predominately assigned by links,
|
|
// though can also be assigned by switch in the case of locally-sourced
|
|
// payments.
|
|
HtlcID uint64
|
|
}
|
|
|
|
// String returns a string representation of the CircuitKey.
|
|
func (k CircuitKey) String() string {
|
|
return fmt.Sprintf("(Chan ID=%s, HTLC ID=%d)", k.ChanID, k.HtlcID)
|
|
}
|
|
|
|
// ClosureType is an enum like structure that details exactly _how_ a channel
|
|
// was closed. Three closure types are currently possible: none, cooperative,
|
|
// local force close, remote force close, and (remote) breach.
|
|
type ClosureType uint8
|
|
|
|
const (
|
|
// RemoteForceClose indicates that the remote peer has unilaterally
|
|
// broadcast their current commitment state on-chain.
|
|
RemoteForceClose ClosureType = 4
|
|
)
|
|
|
|
// ChannelCloseSummary contains the final state of a channel at the point it
|
|
// was closed. Once a channel is closed, all the information pertaining to that
|
|
// channel within the openChannelBucket is deleted, and a compact summary is
|
|
// put in place instead.
|
|
type ChannelCloseSummary struct {
|
|
// ChanPoint is the outpoint for this channel's funding transaction,
|
|
// and is used as a unique identifier for the channel.
|
|
ChanPoint wire.OutPoint
|
|
|
|
// ShortChanID encodes the exact location in the chain in which the
|
|
// channel was initially confirmed. This includes: the block height,
|
|
// transaction index, and the output within the target transaction.
|
|
ShortChanID lnwire.ShortChannelID
|
|
|
|
// ChainHash is the hash of the genesis block that this channel resides
|
|
// within.
|
|
ChainHash chainhash.Hash
|
|
|
|
// ClosingTXID is the txid of the transaction which ultimately closed
|
|
// this channel.
|
|
ClosingTXID chainhash.Hash
|
|
|
|
// RemotePub is the public key of the remote peer that we formerly had
|
|
// a channel with.
|
|
RemotePub *btcec.PublicKey
|
|
|
|
// Capacity was the total capacity of the channel.
|
|
Capacity btcutil.Amount
|
|
|
|
// CloseHeight is the height at which the funding transaction was
|
|
// spent.
|
|
CloseHeight uint32
|
|
|
|
// SettledBalance is our total balance settled balance at the time of
|
|
// channel closure. This _does not_ include the sum of any outputs that
|
|
// have been time-locked as a result of the unilateral channel closure.
|
|
SettledBalance btcutil.Amount
|
|
|
|
// TimeLockedBalance is the sum of all the time-locked outputs at the
|
|
// time of channel closure. If we triggered the force closure of this
|
|
// channel, then this value will be non-zero if our settled output is
|
|
// above the dust limit. If we were on the receiving side of a channel
|
|
// force closure, then this value will be non-zero if we had any
|
|
// outstanding outgoing HTLC's at the time of channel closure.
|
|
TimeLockedBalance btcutil.Amount
|
|
|
|
// CloseType details exactly _how_ the channel was closed. Five closure
|
|
// types are possible: cooperative, local force, remote force, breach
|
|
// and funding canceled.
|
|
CloseType ClosureType
|
|
|
|
// IsPending indicates whether this channel is in the 'pending close'
|
|
// state, which means the channel closing transaction has been
|
|
// confirmed, but not yet been fully resolved. In the case of a channel
|
|
// that has been cooperatively closed, it will go straight into the
|
|
// fully resolved state as soon as the closing transaction has been
|
|
// confirmed. However, for channels that have been force closed, they'll
|
|
// stay marked as "pending" until _all_ the pending funds have been
|
|
// swept.
|
|
IsPending bool
|
|
|
|
// RemoteCurrentRevocation is the current revocation for their
|
|
// commitment transaction. However, since this is the derived public key,
|
|
// we don't yet have the private key so we aren't yet able to verify
|
|
// that it's actually in the hash chain.
|
|
RemoteCurrentRevocation *btcec.PublicKey
|
|
|
|
// RemoteNextRevocation is the revocation key to be used for the *next*
|
|
// commitment transaction we create for the local node. Within the
|
|
// specification, this value is referred to as the
|
|
// per-commitment-point.
|
|
RemoteNextRevocation *btcec.PublicKey
|
|
|
|
// LocalChanCfg is the channel configuration for the local node.
|
|
LocalChanConfig ChannelConfig
|
|
|
|
// LastChanSyncMsg is the ChannelReestablish message for this channel
|
|
// for the state at the point where it was closed.
|
|
LastChanSyncMsg *lnwire.ChannelReestablish
|
|
}
|
|
|
|
func serializeChannelCloseSummary(w io.Writer, cs *ChannelCloseSummary) error {
|
|
err := WriteElements(w,
|
|
cs.ChanPoint, cs.ShortChanID, cs.ChainHash, cs.ClosingTXID,
|
|
cs.CloseHeight, cs.RemotePub, cs.Capacity, cs.SettledBalance,
|
|
cs.TimeLockedBalance, cs.CloseType, cs.IsPending,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// If this is a close channel summary created before the addition of
|
|
// the new fields, then we can exit here.
|
|
if cs.RemoteCurrentRevocation == nil {
|
|
return WriteElements(w, false)
|
|
}
|
|
|
|
// If fields are present, write boolean to indicate this, and continue.
|
|
if err := WriteElements(w, true); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := WriteElements(w, cs.RemoteCurrentRevocation); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := writeChanConfig(w, &cs.LocalChanConfig); err != nil {
|
|
return err
|
|
}
|
|
|
|
// The RemoteNextRevocation field is optional, as it's possible for a
|
|
// channel to be closed before we learn of the next unrevoked
|
|
// revocation point for the remote party. Write a boolen indicating
|
|
// whether this field is present or not.
|
|
if err := WriteElements(w, cs.RemoteNextRevocation != nil); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Write the field, if present.
|
|
if cs.RemoteNextRevocation != nil {
|
|
if err = WriteElements(w, cs.RemoteNextRevocation); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Write whether the channel sync message is present.
|
|
if err := WriteElements(w, cs.LastChanSyncMsg != nil); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Write the channel sync message, if present.
|
|
if cs.LastChanSyncMsg != nil {
|
|
if err := WriteElements(w, cs.LastChanSyncMsg); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func deserializeCloseChannelSummary(r io.Reader) (*ChannelCloseSummary, error) {
|
|
c := &ChannelCloseSummary{}
|
|
|
|
err := ReadElements(r,
|
|
&c.ChanPoint, &c.ShortChanID, &c.ChainHash, &c.ClosingTXID,
|
|
&c.CloseHeight, &c.RemotePub, &c.Capacity, &c.SettledBalance,
|
|
&c.TimeLockedBalance, &c.CloseType, &c.IsPending,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// We'll now check to see if the channel close summary was encoded with
|
|
// any of the additional optional fields.
|
|
var hasNewFields bool
|
|
err = ReadElements(r, &hasNewFields)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If fields are not present, we can return.
|
|
if !hasNewFields {
|
|
return c, nil
|
|
}
|
|
|
|
// Otherwise read the new fields.
|
|
if err := ReadElements(r, &c.RemoteCurrentRevocation); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := readChanConfig(r, &c.LocalChanConfig); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Finally, we'll attempt to read the next unrevoked commitment point
|
|
// for the remote party. If we closed the channel before receiving a
|
|
// funding locked message then this might not be present. A boolean
|
|
// indicating whether the field is present will come first.
|
|
var hasRemoteNextRevocation bool
|
|
err = ReadElements(r, &hasRemoteNextRevocation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If this field was written, read it.
|
|
if hasRemoteNextRevocation {
|
|
err = ReadElements(r, &c.RemoteNextRevocation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Check if we have a channel sync message to read.
|
|
var hasChanSyncMsg bool
|
|
err = ReadElements(r, &hasChanSyncMsg)
|
|
if err == io.EOF {
|
|
return c, nil
|
|
} else if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If a chan sync message is present, read it.
|
|
if hasChanSyncMsg {
|
|
// We must pass in reference to a lnwire.Message for the codec
|
|
// to support it.
|
|
var msg lnwire.Message
|
|
if err := ReadElements(r, &msg); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chanSync, ok := msg.(*lnwire.ChannelReestablish)
|
|
if !ok {
|
|
return nil, errors.New("unable cast db Message to " +
|
|
"ChannelReestablish")
|
|
}
|
|
c.LastChanSyncMsg = chanSync
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
func writeChanConfig(b io.Writer, c *ChannelConfig) error {
|
|
return WriteElements(b,
|
|
c.DustLimit, c.MaxPendingAmount, c.ChanReserve, c.MinHTLC,
|
|
c.MaxAcceptedHtlcs, c.CsvDelay, c.MultiSigKey,
|
|
c.RevocationBasePoint, c.PaymentBasePoint, c.DelayBasePoint,
|
|
c.HtlcBasePoint,
|
|
)
|
|
}
|
|
|
|
func readChanConfig(b io.Reader, c *ChannelConfig) error {
|
|
return ReadElements(b,
|
|
&c.DustLimit, &c.MaxPendingAmount, &c.ChanReserve,
|
|
&c.MinHTLC, &c.MaxAcceptedHtlcs, &c.CsvDelay,
|
|
&c.MultiSigKey, &c.RevocationBasePoint,
|
|
&c.PaymentBasePoint, &c.DelayBasePoint,
|
|
&c.HtlcBasePoint,
|
|
)
|
|
}
|