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.
|
||||
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
|
||||
// extended to the remote party (if any). Each time we propose a new
|
||||
// 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.
|
||||
ErrInvalidCircuitKeyLen = fmt.Errorf(
|
||||
"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
|
||||
@ -285,8 +293,8 @@ type ChannelCommitment struct {
|
||||
// * 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.
|
||||
// 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 (
|
||||
@ -300,7 +308,14 @@ var (
|
||||
|
||||
// CommitmentBroadcasted indicates that a commitment for this channel
|
||||
// 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.
|
||||
@ -312,8 +327,10 @@ func (c ChannelStatus) String() string {
|
||||
return "Borked"
|
||||
case CommitmentBroadcasted:
|
||||
return "CommitmentBroadcasted"
|
||||
case LocalDataLoss:
|
||||
return "LocalDataLoss"
|
||||
default:
|
||||
return "Unknown"
|
||||
return fmt.Sprintf("Unknown(%08b)", c)
|
||||
}
|
||||
}
|
||||
|
||||
@ -679,6 +696,85 @@ func (c *OpenChannel) MarkAsOpen(openLoc lnwire.ShortChannelID) error {
|
||||
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
|
||||
// state, such as a channel breach or state desynchronization. Borked channels
|
||||
// should never be added to the switch.
|
||||
@ -713,6 +809,8 @@ func (c *OpenChannel) putChanStatus(status ChannelStatus) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add this status to the existing bitvector found in the DB.
|
||||
status = channel.chanStatus | status
|
||||
channel.chanStatus = status
|
||||
|
||||
return putOpenChannel(chanBucket, channel)
|
||||
|
Loading…
Reference in New Issue
Block a user