659 lines
25 KiB
Go
659 lines
25 KiB
Go
|
package common
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
|
"io"
|
||
|
|
||
|
"github.com/btcsuite/btcd/btcec"
|
||
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||
|
"github.com/btcsuite/btcd/wire"
|
||
|
"github.com/btcsuite/btcutil"
|
||
|
lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
|
||
|
"github.com/lightningnetwork/lnd/keychain"
|
||
|
)
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
// 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.
|
||
|
//
|
||
|
// NOTE: This is the balance *after* subtracting any commitment fee,
|
||
|
// AND anchor output values.
|
||
|
LocalBalance lnwire.MilliSatoshi
|
||
|
|
||
|
// RemoteBalance is the current available settled balance within the
|
||
|
// channel directly spendable by the remote node.
|
||
|
//
|
||
|
// NOTE: This is the balance *after* subtracting any commitment fee,
|
||
|
// AND anchor output values.
|
||
|
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
|
||
|
}
|
||
|
|
||
|
// LogUpdate represents a pending update to the remote commitment chain. The
|
||
|
// log update may be an add, fail, or settle entry. We maintain this data in
|
||
|
// order to be able to properly retransmit our proposed
|
||
|
// state if necessary.
|
||
|
type LogUpdate struct {
|
||
|
// LogIndex is the log index of this proposed commitment update entry.
|
||
|
LogIndex uint64
|
||
|
|
||
|
// UpdateMsg is the update message that was included within the our
|
||
|
// local update log. The LogIndex value denotes the log index of this
|
||
|
// update which will be used when restoring our local update log if
|
||
|
// we're left with a dangling update on restart.
|
||
|
UpdateMsg lnwire.Message
|
||
|
}
|
||
|
|
||
|
// AddRef is used to identify a particular Add in a FwdPkg. The short channel ID
|
||
|
// is assumed to be that of the packager.
|
||
|
type AddRef struct {
|
||
|
// Height is the remote commitment height that locked in the Add.
|
||
|
Height uint64
|
||
|
|
||
|
// Index is the index of the Add within the fwd pkg's Adds.
|
||
|
//
|
||
|
// NOTE: This index is static over the lifetime of a forwarding package.
|
||
|
Index uint16
|
||
|
}
|
||
|
|
||
|
// SettleFailRef is used to locate a Settle/Fail in another channel's FwdPkg. A
|
||
|
// channel does not remove its own Settle/Fail htlcs, so the source is provided
|
||
|
// to locate a db bucket belonging to another channel.
|
||
|
type SettleFailRef struct {
|
||
|
// Source identifies the outgoing link that locked in the settle or
|
||
|
// fail. This is then used by the *incoming* link to find the settle
|
||
|
// fail in another link's forwarding packages.
|
||
|
Source lnwire.ShortChannelID
|
||
|
|
||
|
// Height is the remote commitment height that locked in this
|
||
|
// Settle/Fail.
|
||
|
Height uint64
|
||
|
|
||
|
// Index is the index of the Add with the fwd pkg's SettleFails.
|
||
|
//
|
||
|
// NOTE: This index is static over the lifetime of a forwarding package.
|
||
|
Index uint16
|
||
|
}
|
||
|
|
||
|
// CommitDiff represents the delta needed to apply the state transition between
|
||
|
// two subsequent commitment states. Given state N and state N+1, one is able
|
||
|
// to apply the set of messages contained within the CommitDiff to N to arrive
|
||
|
// at state N+1. Each time a new commitment is extended, we'll write a new
|
||
|
// commitment (along with the full commitment state) to disk so we can
|
||
|
// re-transmit the state in the case of a connection loss or message drop.
|
||
|
type CommitDiff struct {
|
||
|
// ChannelCommitment is the full commitment state that one would arrive
|
||
|
// at by applying the set of messages contained in the UpdateDiff to
|
||
|
// the prior accepted commitment.
|
||
|
Commitment ChannelCommitment
|
||
|
|
||
|
// LogUpdates is the set of messages sent prior to the commitment state
|
||
|
// transition in question. Upon reconnection, if we detect that they
|
||
|
// don't have the commitment, then we re-send this along with the
|
||
|
// proper signature.
|
||
|
LogUpdates []LogUpdate
|
||
|
|
||
|
// CommitSig is the exact CommitSig message that should be sent after
|
||
|
// the set of LogUpdates above has been retransmitted. The signatures
|
||
|
// within this message should properly cover the new commitment state
|
||
|
// and also the HTLC's within the new commitment state.
|
||
|
CommitSig *lnwire.CommitSig
|
||
|
|
||
|
// OpenedCircuitKeys is a set of unique identifiers for any downstream
|
||
|
// Add packets included in this commitment txn. After a restart, this
|
||
|
// set of htlcs is acked from the link's incoming mailbox to ensure
|
||
|
// there isn't an attempt to re-add them to this commitment txn.
|
||
|
OpenedCircuitKeys []CircuitKey
|
||
|
|
||
|
// ClosedCircuitKeys records the unique identifiers for any settle/fail
|
||
|
// packets that were resolved by this commitment txn. After a restart,
|
||
|
// this is used to ensure those circuits are removed from the circuit
|
||
|
// map, and the downstream packets in the link's mailbox are removed.
|
||
|
ClosedCircuitKeys []CircuitKey
|
||
|
|
||
|
// AddAcks specifies the locations (commit height, pkg index) of any
|
||
|
// Adds that were failed/settled in this commit diff. This will ack
|
||
|
// entries in *this* channel's forwarding packages.
|
||
|
//
|
||
|
// NOTE: This value is not serialized, it is used to atomically mark the
|
||
|
// resolution of adds, such that they will not be reprocessed after a
|
||
|
// restart.
|
||
|
AddAcks []AddRef
|
||
|
|
||
|
// SettleFailAcks specifies the locations (chan id, commit height, pkg
|
||
|
// index) of any Settles or Fails that were locked into this commit
|
||
|
// diff, and originate from *another* channel, i.e. the outgoing link.
|
||
|
//
|
||
|
// NOTE: This value is not serialized, it is used to atomically acks
|
||
|
// settles and fails from the forwarding packages of other channels,
|
||
|
// such that they will not be reforwarded internally after a restart.
|
||
|
SettleFailAcks []SettleFailRef
|
||
|
}
|
||
|
|
||
|
// NetworkResult is the raw result received from the network after a payment
|
||
|
// attempt has been made. Since the switch doesn't always have the necessary
|
||
|
// data to decode the raw message, we store it together with some meta data,
|
||
|
// and decode it when the router query for the final result.
|
||
|
type NetworkResult struct {
|
||
|
// Msg is the received result. This should be of type UpdateFulfillHTLC
|
||
|
// or UpdateFailHTLC.
|
||
|
Msg lnwire.Message
|
||
|
|
||
|
// unencrypted indicates whether the failure encoded in the message is
|
||
|
// unencrypted, and hence doesn't need to be decrypted.
|
||
|
Unencrypted bool
|
||
|
|
||
|
// IsResolution indicates whether this is a resolution message, in
|
||
|
// which the failure reason might not be included.
|
||
|
IsResolution bool
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
// FwdState is an enum used to describe the lifecycle of a FwdPkg.
|
||
|
type FwdState byte
|
||
|
|
||
|
const (
|
||
|
// FwdStateLockedIn is the starting state for all forwarding packages.
|
||
|
// Packages in this state have not yet committed to the exact set of
|
||
|
// Adds to forward to the switch.
|
||
|
FwdStateLockedIn FwdState = iota
|
||
|
|
||
|
// FwdStateProcessed marks the state in which all Adds have been
|
||
|
// locally processed and the forwarding decision to the switch has been
|
||
|
// persisted.
|
||
|
FwdStateProcessed
|
||
|
|
||
|
// FwdStateCompleted signals that all Adds have been acked, and that all
|
||
|
// settles and fails have been delivered to their sources. Packages in
|
||
|
// this state can be removed permanently.
|
||
|
FwdStateCompleted
|
||
|
)
|
||
|
|
||
|
// PkgFilter is used to compactly represent a particular subset of the Adds in a
|
||
|
// forwarding package. Each filter is represented as a simple, statically-sized
|
||
|
// bitvector, where the elements are intended to be the indices of the Adds as
|
||
|
// they are written in the FwdPkg.
|
||
|
type PkgFilter struct {
|
||
|
count uint16
|
||
|
filter []byte
|
||
|
}
|
||
|
|
||
|
// NewPkgFilter initializes an empty PkgFilter supporting `count` elements.
|
||
|
func NewPkgFilter(count uint16) *PkgFilter {
|
||
|
// We add 7 to ensure that the integer division yields properly rounded
|
||
|
// values.
|
||
|
filterLen := (count + 7) / 8
|
||
|
|
||
|
return &PkgFilter{
|
||
|
count: count,
|
||
|
filter: make([]byte, filterLen),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Count returns the number of elements represented by this PkgFilter.
|
||
|
func (f *PkgFilter) Count() uint16 {
|
||
|
return f.count
|
||
|
}
|
||
|
|
||
|
// Set marks the `i`-th element as included by this filter.
|
||
|
// NOTE: It is assumed that i is always less than count.
|
||
|
func (f *PkgFilter) Set(i uint16) {
|
||
|
byt := i / 8
|
||
|
bit := i % 8
|
||
|
|
||
|
// Set the i-th bit in the filter.
|
||
|
// TODO(conner): ignore if > count to prevent panic?
|
||
|
f.filter[byt] |= byte(1 << (7 - bit))
|
||
|
}
|
||
|
|
||
|
// Contains queries the filter for membership of index `i`.
|
||
|
// NOTE: It is assumed that i is always less than count.
|
||
|
func (f *PkgFilter) Contains(i uint16) bool {
|
||
|
byt := i / 8
|
||
|
bit := i % 8
|
||
|
|
||
|
// Read the i-th bit in the filter.
|
||
|
// TODO(conner): ignore if > count to prevent panic?
|
||
|
return f.filter[byt]&(1<<(7-bit)) != 0
|
||
|
}
|
||
|
|
||
|
// Equal checks two PkgFilters for equality.
|
||
|
func (f *PkgFilter) Equal(f2 *PkgFilter) bool {
|
||
|
if f == f2 {
|
||
|
return true
|
||
|
}
|
||
|
if f.count != f2.count {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return bytes.Equal(f.filter, f2.filter)
|
||
|
}
|
||
|
|
||
|
// IsFull returns true if every element in the filter has been Set, and false
|
||
|
// otherwise.
|
||
|
func (f *PkgFilter) IsFull() bool {
|
||
|
// Batch validate bytes that are fully used.
|
||
|
for i := uint16(0); i < f.count/8; i++ {
|
||
|
if f.filter[i] != 0xFF {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If the count is not a multiple of 8, check that the filter contains
|
||
|
// all remaining bits.
|
||
|
rem := f.count % 8
|
||
|
for idx := f.count - rem; idx < f.count; idx++ {
|
||
|
if !f.Contains(idx) {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// Size returns number of bytes produced when the PkgFilter is serialized.
|
||
|
func (f *PkgFilter) Size() uint16 {
|
||
|
// 2 bytes for uint16 `count`, then round up number of bytes required to
|
||
|
// represent `count` bits.
|
||
|
return 2 + (f.count+7)/8
|
||
|
}
|
||
|
|
||
|
// Encode writes the filter to the provided io.Writer.
|
||
|
func (f *PkgFilter) Encode(w io.Writer) error {
|
||
|
if err := binary.Write(w, binary.BigEndian, f.count); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
_, err := w.Write(f.filter)
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Decode reads the filter from the provided io.Reader.
|
||
|
func (f *PkgFilter) Decode(r io.Reader) error {
|
||
|
if err := binary.Read(r, binary.BigEndian, &f.count); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
f.filter = make([]byte, f.Size()-2)
|
||
|
_, err := io.ReadFull(r, f.filter)
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// FwdPkg records all adds, settles, and fails that were locked in as a result
|
||
|
// of the remote peer sending us a revocation. Each package is identified by
|
||
|
// the short chanid and remote commitment height corresponding to the revocation
|
||
|
// that locked in the HTLCs. For everything except a locally initiated payment,
|
||
|
// settles and fails in a forwarding package must have a corresponding Add in
|
||
|
// another package, and can be removed individually once the source link has
|
||
|
// received the fail/settle.
|
||
|
//
|
||
|
// Adds cannot be removed, as we need to present the same batch of Adds to
|
||
|
// properly handle replay protection. Instead, we use a PkgFilter to mark that
|
||
|
// we have finished processing a particular Add. A FwdPkg should only be deleted
|
||
|
// after the AckFilter is full and all settles and fails have been persistently
|
||
|
// removed.
|
||
|
type FwdPkg struct {
|
||
|
// Source identifies the channel that wrote this forwarding package.
|
||
|
Source lnwire.ShortChannelID
|
||
|
|
||
|
// Height is the height of the remote commitment chain that locked in
|
||
|
// this forwarding package.
|
||
|
Height uint64
|
||
|
|
||
|
// State signals the persistent condition of the package and directs how
|
||
|
// to reprocess the package in the event of failures.
|
||
|
State FwdState
|
||
|
|
||
|
// Adds contains all add messages which need to be processed and
|
||
|
// forwarded to the switch. Adds does not change over the life of a
|
||
|
// forwarding package.
|
||
|
Adds []LogUpdate
|
||
|
|
||
|
// FwdFilter is a filter containing the indices of all Adds that were
|
||
|
// forwarded to the switch.
|
||
|
FwdFilter *PkgFilter
|
||
|
|
||
|
// AckFilter is a filter containing the indices of all Adds for which
|
||
|
// the source has received a settle or fail and is reflected in the next
|
||
|
// commitment txn. A package should not be removed until IsFull()
|
||
|
// returns true.
|
||
|
AckFilter *PkgFilter
|
||
|
|
||
|
// SettleFails contains all settle and fail messages that should be
|
||
|
// forwarded to the switch.
|
||
|
SettleFails []LogUpdate
|
||
|
|
||
|
// SettleFailFilter is a filter containing the indices of all Settle or
|
||
|
// Fails originating in this package that have been received and locked
|
||
|
// into the incoming link's commitment state.
|
||
|
SettleFailFilter *PkgFilter
|
||
|
}
|
||
|
|
||
|
// NewFwdPkg initializes a new forwarding package in FwdStateLockedIn. This
|
||
|
// should be used to create a package at the time we receive a revocation.
|
||
|
func NewFwdPkg(source lnwire.ShortChannelID, height uint64,
|
||
|
addUpdates, settleFailUpdates []LogUpdate) *FwdPkg {
|
||
|
|
||
|
nAddUpdates := uint16(len(addUpdates))
|
||
|
nSettleFailUpdates := uint16(len(settleFailUpdates))
|
||
|
|
||
|
return &FwdPkg{
|
||
|
Source: source,
|
||
|
Height: height,
|
||
|
State: FwdStateLockedIn,
|
||
|
Adds: addUpdates,
|
||
|
FwdFilter: NewPkgFilter(nAddUpdates),
|
||
|
AckFilter: NewPkgFilter(nAddUpdates),
|
||
|
SettleFails: settleFailUpdates,
|
||
|
SettleFailFilter: NewPkgFilter(nSettleFailUpdates),
|
||
|
}
|
||
|
}
|