channeldb: restructure the OpenChannel struct to use two ChannelCommitments

In this commit, we restructure the OpenChannel struct to used two
distinct ChannelCommitments: one for the remote party, and one for the
local party. With this, we now partition the local state and the remote
state. Previously, we weren’t properly tracking the state of the remote
party. As a result, there were certain classes of failures we were
unable to properly recover from. With this separation, we can now
handle them, and the OpenChannel struct is slimmer and more
understandable.
This commit is contained in:
Olaoluwa Osuntokun 2017-11-09 19:54:31 -08:00
parent 4bc317fbbe
commit fb8ff256d8
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

@ -3,7 +3,6 @@ package channeldb
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"net" "net"
@ -19,89 +18,73 @@ import (
) )
var ( var (
// openChanBucket stores all the currently open channels. This bucket
// has a second, nested bucket which is keyed by a node's ID. Additionally,
// at the base level of this bucket several prefixed keys are stored which
// house channel metadata such as total satoshis sent, number of updates
// etc. These fields are stored at this top level rather than within a
// node's channel bucket in order to facilitate sequential prefix scans
// to gather stats such as total satoshis received.
openChannelBucket = []byte("ocb")
// chanIDBucket is a third-level bucket stored within a node's ID bucket
// in the open channel bucket. The resolution path looks something like:
// ocb -> nodeID -> cib. This bucket contains a series of keys with no
// values, these keys are the channel ID's of all the active channels
// we currently have with a specified nodeID. This bucket acts as an
// additional indexing allowing random access and sequential scans over
// active channels.
chanIDBucket = []byte("cib")
// commitDiffBucket...
commitDiffBucket = []byte("cdb")
// closedChannelBucket stores summarization information concerning // closedChannelBucket stores summarization information concerning
// previously open, but now closed channels. // previously open, but now closed channels.
closedChannelBucket = []byte("ccb") closedChannelBucket = []byte("closed-chan-bucket")
// channelLogBucket is dedicated for storing the necessary delta state // openChanBucket stores all the currently open channels. This bucket
// between channel updates required to re-construct a past state in // has a second, nested bucket which is keyed by a node's ID. Within
// order to punish a counterparty attempting a non-cooperative channel // that node ID bucket, all attributes required to track, update, and
// closure. A channel log bucket is created for each node and is nested // close a channel are stored.
// within a node's ID bucket. //
channelLogBucket = []byte("clb") // openChan -> nodeID -> chanPoint
//
// TODO(roasbeef): flesh out comment
openChannelBucket = []byte("open-chan-bucket")
// identityKey is the key for storing this node's current LD identity // chanInfoKey can be accessed within the bucket for a channel
// key. // (identified by it's chanPoint). This key stores all the static
identityKey = []byte("idk") // information for a channel which is decided at the end of the
// funding flow.
chanInfoKey = []byte("chan-info-key")
// The following prefixes are stored at the base level within the // chanCommitmentKey can be accessed within the sub-bucket for a
// openChannelBucket. In order to retrieve a particular field for an // particular channel. This key stores the up to date commitment state
// active, or historic channel, append the channels ID to the prefix: // for a particular channel party. Appending a 0 to the end of this key
// key = prefix || chanID. Storing certain fields at the top level // indicates it's the commitment for the local party, and appending a 1
// using a prefix scheme serves two purposes: first to facilitate // to the end of this key indicates it's the commitment for the remote
// sequential prefix scans, and second to eliminate write amplification // party.
// caused by serializing/deserializing the *entire* struct with each chanCommitmentKey = []byte("chan-commitment-key")
// update.
chanCapacityPrefix = []byte("ccp")
selfBalancePrefix = []byte("sbp")
theirBalancePrefix = []byte("tbp")
minFeePerKwPrefix = []byte("mfp")
chanConfigPrefix = []byte("chan-config")
updatePrefix = []byte("uup")
ourIndexPrefix = []byte("tip")
theirIndexPrefix = []byte("oip")
satSentPrefix = []byte("ssp")
satReceivedPrefix = []byte("srp")
commitFeePrefix = []byte("cfp")
isPendingPrefix = []byte("pdg")
confInfoPrefix = []byte("conf-info")
// chanIDKey stores the node, and channelID for an active channel.
chanIDKey = []byte("cik")
// commitKeys stores both commitment keys (ours, and theirs) for an
// active channel. Our private key is stored in an encrypted format
// using channeldb's currently registered cryptoSystem.
commitKeys = []byte("ckk")
// commitTxnsKey stores the full version of both current, non-revoked
// commitment transactions in addition to the csvDelay for both.
commitTxnsKey = []byte("ctk")
// currentHtlcKey stores the set of fully locked-in HTLCs on our latest
// commitment state.
currentHtlcKey = []byte("chk")
// fundingTxnKey stores the funding output, the multi-sig keys used in
// the funding output, and further information detailing if the
// transaction is "open", or not and how many confirmations required
// until it's considered open.
fundingTxnKey = []byte("fsk")
// revocationStateKey stores their current revocation hash, our // revocationStateKey stores their current revocation hash, our
// preimage producer and their preimage store. // preimage producer and their preimage store.
revocationStateKey = []byte("esk") revocationStateKey = []byte("revocation-state-key")
// commitDiffKey stores the current pending commitment state we've
// extended to the remote party (if any). Each time we propose a new
// state, we store the information necessary to reconstruct this state
// from the prior commitment. This allows us to resync the remote party
// to their expected state in the case of message loss.
//
// TODO(roasbeef): rename to commit chain?
commitDiffKey = []byte("commit-diff-key")
// revocationLogBucket is dedicated for storing the necessary delta
// state between channel updates required to re-construct a past state
// in order to punish a counterparty attempting a non-cooperative
// channel closure. This key should be accessed from within the
// sub-bucket of a target channel, identified by its channel point.
revocationLogBucket = []byte("revocation-log-key")
)
var (
// ErrNoCommitmentsFound is returned when a channel has not set
// commitment states.
ErrNoCommitmentsFound = fmt.Errorf("no commitments found")
// ErrNoChanInfoFound is returned when a particular channel does not
// have any channels state.
ErrNoChanInfoFound = fmt.Errorf("no chan info found")
// ErrNoRevocationsFound is returned when revocation state for a
// particular channel cannot be found.
ErrNoRevocationsFound = fmt.Errorf("no revocations found")
// ErrNoPendingCommit is returned when there is not a pending
// commitment for a remote party. A new commitment is written to disk
// each time we write a new state in order to be properly fault
// tolerant.
ErrNoPendingCommit = fmt.Errorf("no pending commits found")
) )
// ChannelType is an enum-like type that describes one of several possible // ChannelType is an enum-like type that describes one of several possible
@ -133,7 +116,7 @@ const (
// constraints is static for the duration of the channel, meaning the channel // constraints is static for the duration of the channel, meaning the channel
// must be teared down for them to change. // must be teared down for them to change.
type ChannelConstraints struct { type ChannelConstraints struct {
// DustLimit is the threhsold (in satoshis) below which any outputs // DustLimit is the threshold (in satoshis) below which any outputs
// should be trimmed. When an output is trimmed, it isn't materialized // should be trimmed. When an output is trimmed, it isn't materialized
// as an actual output, but is instead burned to miner's fees. // as an actual output, but is instead burned to miner's fees.
DustLimit btcutil.Amount DustLimit btcutil.Amount
@ -148,9 +131,6 @@ type ChannelConstraints struct {
// this node CANNOT dip below the reservation amount. This acts as a // this node CANNOT dip below the reservation amount. This acts as a
// defense against costless attacks when either side no longer has any // defense against costless attacks when either side no longer has any
// skin in the game. // skin in the game.
//
// TODO(roasbeef): need to swap above, i tell them what reserve, then
// other way around
ChanReserve btcutil.Amount ChanReserve btcutil.Amount
// MinHTLC is the minimum HTLC accepted for a direction of the channel. // MinHTLC is the minimum HTLC accepted for a direction of the channel.
@ -174,7 +154,7 @@ type ChannelConstraints struct {
// time lock parameters. // time lock parameters.
type ChannelConfig struct { type ChannelConfig struct {
// ChannelConstraints is the set of constraints that must be upheld for // ChannelConstraints is the set of constraints that must be upheld for
// the duration of the channel for ths owner of this channel // the duration of the channel for the owner of this channel
// configuration. Constraints govern a number of flow control related // configuration. Constraints govern a number of flow control related
// parameters, also including the smallest HTLC that will be accepted // parameters, also including the smallest HTLC that will be accepted
// by a participant. // by a participant.
@ -325,54 +305,43 @@ type OpenChannel struct {
// been confirmed before a certain height. // been confirmed before a certain height.
FundingBroadcastHeight uint32 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
// IdentityPub is the identity public key of the remote node this // IdentityPub is the identity public key of the remote node this
// channel has been established with. // channel has been established with.
IdentityPub *btcec.PublicKey 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 is the channel configuration for the local node.
LocalChanCfg ChannelConfig LocalChanCfg ChannelConfig
// RemoteChanCfg is the channel configuration for the remote node. // RemoteChanCfg is the channel configuration for the remote node.
RemoteChanCfg ChannelConfig RemoteChanCfg ChannelConfig
// FeePerKw is the min satoshis/kilo-weight that should be paid within // LocalCommitment is the current local commitment state for the local
// the commitment transaction for the entire duration of the channel's // party. This is stored distinct from the state of of the remote party
// lifetime. This field may be updated during normal operation of the // as there are certain asymmetric parameters which affect the
// channel as on-chain conditions change. // structure of each commitment.
FeePerKw btcutil.Amount LocalCommitment ChannelCommitment
// Capacity is the total capacity of this channel. // RemoteCommitment is the current remote commitment state for the
Capacity btcutil.Amount // remote party. This is stored distinct from the state of of the local
// party as there are certain asymmetric parameters which affect the
// LocalBalance is the current available settled balance within the // structure of each commitment.
// channel directly spendable by us. RemoteCommitment ChannelCommitment
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
// CommitKey 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
// 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
// RemoteCurrentRevocation is the current revocation for their // RemoteCurrentRevocation is the current revocation for their
// commitment transaction. However, since this the derived public key, // commitment transaction. However, since this the derived public key,
@ -397,41 +366,6 @@ type OpenChannel struct {
// implementation of secret store is shachain store. // implementation of secret store is shachain store.
RevocationStore shachain.Store RevocationStore shachain.Store
// NumUpdates is the total number of updates conducted within this
// channel.
NumUpdates uint64
// OurMessageIndex...
OurMessageIndex uint64
// TheirMessageIndex...
TheirMessageIndex uint64
// OurMessageIndex...
OurAckedIndex uint64
// TheirMessageIndex...
TheirAckedIndex uint64
// TotalSatoshisSent is the total number of satoshis we've sent within
// this channel.
TotalSatoshisSent uint64
// 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
// Htlcs is the list of active, uncleared HTLCs currently pending
// within the channel.
Htlcs []*HTLC
// LastUpdates...
LastUpdates lnwire.Message
// TODO(roasbeef): eww // TODO(roasbeef): eww
Db *DB Db *DB