channeldb/channel: methods for marking borked+dataloss commitPoint in db
This commit is contained in:
parent
ea6aca26a5
commit
6cdf0e2d6e
@ -51,6 +51,10 @@ var (
|
|||||||
// preimage producer and their preimage store.
|
// preimage producer and their preimage store.
|
||||||
revocationStateKey = []byte("revocation-state-key")
|
revocationStateKey = []byte("revocation-state-key")
|
||||||
|
|
||||||
|
// dataLossCommitPointKey stores the commitment point received from the
|
||||||
|
// remote peer during a channel sync in case we have lost channel state.
|
||||||
|
dataLossCommitPointKey = []byte("data-loss-commit-point-key")
|
||||||
|
|
||||||
// commitDiffKey stores the current pending commitment state we've
|
// commitDiffKey stores the current pending commitment state we've
|
||||||
// extended to the remote party (if any). Each time we propose a new
|
// extended to the remote party (if any). Each time we propose a new
|
||||||
// state, we store the information necessary to reconstruct this state
|
// state, we store the information necessary to reconstruct this state
|
||||||
@ -97,6 +101,10 @@ var (
|
|||||||
// decoded because the byte slice is of an invalid length.
|
// decoded because the byte slice is of an invalid length.
|
||||||
ErrInvalidCircuitKeyLen = fmt.Errorf(
|
ErrInvalidCircuitKeyLen = fmt.Errorf(
|
||||||
"length of serialized circuit key must be 16 bytes")
|
"length of serialized circuit key must be 16 bytes")
|
||||||
|
|
||||||
|
// ErrNoCommitPoint is returned when no data loss commit point is found
|
||||||
|
// in the database.
|
||||||
|
ErrNoCommitPoint = fmt.Errorf("no commit point 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
|
||||||
@ -285,8 +293,8 @@ type ChannelCommitment struct {
|
|||||||
// * lets just walk through
|
// * lets just walk through
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChannelStatus is used to indicate whether an OpenChannel is in the default
|
// ChannelStatus is a bit vector used to indicate whether an OpenChannel is in
|
||||||
// usable state, or a state where it shouldn't be used.
|
// the default usable state, or a state where it shouldn't be used.
|
||||||
type ChannelStatus uint8
|
type ChannelStatus uint8
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -300,7 +308,14 @@ var (
|
|||||||
|
|
||||||
// CommitmentBroadcasted indicates that a commitment for this channel
|
// CommitmentBroadcasted indicates that a commitment for this channel
|
||||||
// has been broadcasted.
|
// has been broadcasted.
|
||||||
CommitmentBroadcasted ChannelStatus = 2
|
CommitmentBroadcasted ChannelStatus = 1 << 1
|
||||||
|
|
||||||
|
// LocalDataLoss 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.
|
||||||
|
LocalDataLoss ChannelStatus = 1 << 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// String returns a human-readable representation of the ChannelStatus.
|
// String returns a human-readable representation of the ChannelStatus.
|
||||||
@ -312,8 +327,10 @@ func (c ChannelStatus) String() string {
|
|||||||
return "Borked"
|
return "Borked"
|
||||||
case CommitmentBroadcasted:
|
case CommitmentBroadcasted:
|
||||||
return "CommitmentBroadcasted"
|
return "CommitmentBroadcasted"
|
||||||
|
case LocalDataLoss:
|
||||||
|
return "LocalDataLoss"
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return fmt.Sprintf("Unknown(%08b)", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,6 +696,85 @@ func (c *OpenChannel) MarkAsOpen(openLoc lnwire.ShortChannelID) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDataLoss marks sets the channel status to LocalDataLoss and stores the
|
||||||
|
// passed commitPoint for use to retrieve funds in case the remote force closes
|
||||||
|
// the channel.
|
||||||
|
func (c *OpenChannel) MarkDataLoss(commitPoint *btcec.PublicKey) error {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
var status ChannelStatus
|
||||||
|
if err := c.Db.Update(func(tx *bolt.Tx) error {
|
||||||
|
chanBucket, err := updateChanBucket(
|
||||||
|
tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := fetchOpenChannel(chanBucket, &c.FundingOutpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add status LocalDataLoss to the existing bitvector found in
|
||||||
|
// the DB.
|
||||||
|
status = channel.chanStatus | LocalDataLoss
|
||||||
|
channel.chanStatus = status
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := WriteElement(&b, commitPoint); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = chanBucket.Put(dataLossCommitPointKey, b.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return putOpenChannel(chanBucket, channel)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the in-memory representation to keep it in sync with the DB.
|
||||||
|
c.chanStatus = status
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataLossCommitPoint retrieves the stored commit point set during
|
||||||
|
// MarkDataLoss. If not found ErrNoCommitPoint is returned.
|
||||||
|
func (c *OpenChannel) DataLossCommitPoint() (*btcec.PublicKey, error) {
|
||||||
|
var commitPoint *btcec.PublicKey
|
||||||
|
|
||||||
|
err := c.Db.View(func(tx *bolt.Tx) error {
|
||||||
|
chanBucket, err := readChanBucket(tx, c.IdentityPub,
|
||||||
|
&c.FundingOutpoint, c.ChainHash)
|
||||||
|
if err == ErrNoActiveChannels || err == ErrNoChanDBExists {
|
||||||
|
return ErrNoCommitPoint
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := chanBucket.Get(dataLossCommitPointKey)
|
||||||
|
if bs == nil {
|
||||||
|
return ErrNoCommitPoint
|
||||||
|
}
|
||||||
|
r := bytes.NewReader(bs)
|
||||||
|
if err := ReadElements(r, &commitPoint); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return commitPoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
// MarkBorked marks the event when the channel as reached an irreconcilable
|
// MarkBorked marks the event when the channel as reached an irreconcilable
|
||||||
// state, such as a channel breach or state desynchronization. Borked channels
|
// state, such as a channel breach or state desynchronization. Borked channels
|
||||||
// should never be added to the switch.
|
// should never be added to the switch.
|
||||||
@ -713,6 +809,8 @@ func (c *OpenChannel) putChanStatus(status ChannelStatus) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add this status to the existing bitvector found in the DB.
|
||||||
|
status = channel.chanStatus | status
|
||||||
channel.chanStatus = status
|
channel.chanStatus = status
|
||||||
|
|
||||||
return putOpenChannel(chanBucket, channel)
|
return putOpenChannel(chanBucket, channel)
|
||||||
|
Loading…
Reference in New Issue
Block a user