channeldb/channel: add property ChanStatus in place of IsBorked to OpenChannel

This commit changes the bool `IsBorked` in OpenChannel to a `ChanStatus`
struct, of type ChannelStatus. This is used to indicated that a channel
that is technically still open, is either borked, or has had a
commitment broadcasted, but is not confirmed on-chain yet.

The ChannelStatus type has the value 1 for the status Borked, meaning it
is backwards compatible with the old database format.
This commit is contained in:
Johan T. Halseth 2018-03-27 13:57:57 +02:00
parent d2d87758f7
commit b7bb53a8b8
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
2 changed files with 71 additions and 20 deletions

@ -285,6 +285,38 @@ type ChannelCommitment struct {
// * lets just walk through // * lets just walk through
} }
// ChannelStatus is 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 (
// Default is the normal state of an open channel.
Default ChannelStatus = 0
// Borked 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.
Borked ChannelStatus = 1
// CommitmentBroadcasted indicates that a commitment for this channel
// has been broadcasted.
CommitmentBroadcasted ChannelStatus = 2
)
// String returns a human-readable representation of the ChannelStatus.
func (c ChannelStatus) String() string {
switch c {
case Default:
return "Default"
case Borked:
return "Borked"
case CommitmentBroadcasted:
return "CommitmentBroadcasted"
default:
return "Unknown"
}
}
// OpenChannel encapsulates the persistent and dynamic state of an open channel // OpenChannel encapsulates the persistent and dynamic state of an open channel
// with a remote node. An open channel supports several options for on-disk // with a remote node. An open channel supports several options for on-disk
// serialization depending on the exact context. Full (upon channel creation) // serialization depending on the exact context. Full (upon channel creation)
@ -322,10 +354,9 @@ type OpenChannel struct {
// negotiate fees, or close the channel. // negotiate fees, or close the channel.
IsInitiator bool IsInitiator bool
// IsBorked indicates that the channel has entered an irreconcilable // ChanStatus is the current status of this channel. If it is not in
// state, triggered by a state desynchronization or channel breach. // the state Default, it should not be used for forwarding payments.
// Channels in this state should never be added to the htlc switch. ChanStatus ChannelStatus
IsBorked bool
// FundingBroadcastHeight is the height in which the funding // FundingBroadcastHeight is the height in which the funding
// transaction was broadcast. This value can be used by higher level // transaction was broadcast. This value can be used by higher level
@ -571,6 +602,20 @@ func (c *OpenChannel) MarkBorked() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
return c.putChanStatus(Borked)
}
// MarkCommitmentBroadcasted marks the channel as a commitment transaction has
// been broadcast, either our own or the remote, and we should watch the chain
// for it to confirm before taking any further action.
func (c *OpenChannel) MarkCommitmentBroadcasted() error {
c.Lock()
defer c.Unlock()
return c.putChanStatus(CommitmentBroadcasted)
}
func (c *OpenChannel) putChanStatus(status ChannelStatus) error {
if err := c.Db.Update(func(tx *bolt.Tx) error { if err := c.Db.Update(func(tx *bolt.Tx) error {
chanBucket, err := updateChanBucket(tx, c.IdentityPub, chanBucket, err := updateChanBucket(tx, c.IdentityPub,
&c.FundingOutpoint, c.ChainHash) &c.FundingOutpoint, c.ChainHash)
@ -583,14 +628,15 @@ func (c *OpenChannel) MarkBorked() error {
return err return err
} }
channel.IsBorked = true channel.ChanStatus = status
return putOpenChannel(chanBucket, channel) return putOpenChannel(chanBucket, channel)
}); err != nil { }); err != nil {
return err return err
} }
c.IsBorked = true // Update the in-memory representation to keep it in sync with the DB.
c.ChanStatus = status
return nil return nil
} }
@ -1478,8 +1524,8 @@ func (c *OpenChannel) FindPreviousState(updateNum uint64) (*ChannelCommitment, e
} }
// ClosureType is an enum like structure that details exactly _how_ a channel // ClosureType is an enum like structure that details exactly _how_ a channel
// was closed. Three closure types are currently possible: cooperative, force, // was closed. Three closure types are currently possible: none, cooperative,
// and breach. // local force close, remote force close, and (remote) breach.
type ClosureType uint8 type ClosureType uint8
const ( const (
@ -1487,21 +1533,25 @@ const (
// cooperatively. This means that both channel peers were online and // cooperatively. This means that both channel peers were online and
// signed a new transaction paying out the settled balance of the // signed a new transaction paying out the settled balance of the
// contract. // contract.
CooperativeClose ClosureType = iota CooperativeClose ClosureType = 0
// ForceClose indicates that one peer unilaterally broadcast their // LocalForceClose indicates that we have unilaterally broadcast our
// current commitment state on-chain. // current commitment state on-chain.
ForceClose LocalForceClose ClosureType = 1
// BreachClose indicates that one peer attempted to broadcast a prior // RemoteForceClose indicates that the remote peer has unilaterally
// _revoked_ channel state. // broadcast their current commitment state on-chain.
BreachClose RemoteForceClose ClosureType = 4
// BreachClose indicates that the remote peer attempted to broadcast a
// prior _revoked_ channel state.
BreachClose ClosureType = 2
// FundingCanceled indicates that the channel never was fully opened // FundingCanceled indicates that the channel never was fully opened
// before it was marked as closed in the database. This can happen if // before it was marked as closed in the database. This can happen if
// we or the remote fail at some point during the opening workflow, or // we or the remote fail at some point during the opening workflow, or
// we timeout waiting for the funding transaction to be confirmed. // we timeout waiting for the funding transaction to be confirmed.
FundingCanceled FundingCanceled ClosureType = 3
) )
// ChannelCloseSummary contains the final state of a channel at the point it // ChannelCloseSummary contains the final state of a channel at the point it
@ -1549,8 +1599,9 @@ type ChannelCloseSummary struct {
// outstanding outgoing HTLC's at the time of channel closure. // outstanding outgoing HTLC's at the time of channel closure.
TimeLockedBalance btcutil.Amount TimeLockedBalance btcutil.Amount
// CloseType details exactly _how_ the channel was closed. Three // CloseType details exactly _how_ the channel was closed. Five closure
// closure types are possible: cooperative, force, and breach. // types are possible: cooperative, local force, remote force, breach
// and funding canceled.
CloseType ClosureType CloseType ClosureType
// IsPending indicates whether this channel is in the 'pending close' // IsPending indicates whether this channel is in the 'pending close'
@ -1804,7 +1855,7 @@ func putChanInfo(chanBucket *bolt.Bucket, channel *OpenChannel) error {
if err := writeElements(&w, if err := writeElements(&w,
channel.ChanType, channel.ChainHash, channel.FundingOutpoint, channel.ChanType, channel.ChainHash, channel.FundingOutpoint,
channel.ShortChanID, channel.IsPending, channel.IsInitiator, channel.ShortChanID, channel.IsPending, channel.IsInitiator,
channel.IsBorked, channel.FundingBroadcastHeight, channel.ChanStatus, channel.FundingBroadcastHeight,
channel.NumConfsRequired, channel.ChannelFlags, channel.NumConfsRequired, channel.ChannelFlags,
channel.IdentityPub, channel.Capacity, channel.TotalMSatSent, channel.IdentityPub, channel.Capacity, channel.TotalMSatSent,
channel.TotalMSatReceived, channel.TotalMSatReceived,
@ -1912,7 +1963,7 @@ func fetchChanInfo(chanBucket *bolt.Bucket, channel *OpenChannel) error {
if err := readElements(r, if err := readElements(r,
&channel.ChanType, &channel.ChainHash, &channel.FundingOutpoint, &channel.ChanType, &channel.ChainHash, &channel.FundingOutpoint,
&channel.ShortChanID, &channel.IsPending, &channel.IsInitiator, &channel.ShortChanID, &channel.IsPending, &channel.IsInitiator,
&channel.IsBorked, &channel.FundingBroadcastHeight, &channel.ChanStatus, &channel.FundingBroadcastHeight,
&channel.NumConfsRequired, &channel.ChannelFlags, &channel.NumConfsRequired, &channel.ChannelFlags,
&channel.IdentityPub, &channel.Capacity, &channel.TotalMSatSent, &channel.IdentityPub, &channel.Capacity, &channel.TotalMSatSent,
&channel.TotalMSatReceived, &channel.TotalMSatReceived,

@ -4754,7 +4754,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
RemotePub: chanState.IdentityPub, RemotePub: chanState.IdentityPub,
Capacity: chanState.Capacity, Capacity: chanState.Capacity,
SettledBalance: localBalance, SettledBalance: localBalance,
CloseType: channeldb.ForceClose, CloseType: channeldb.RemoteForceClose,
IsPending: true, IsPending: true,
} }