channeldb+lnwallet: make ChanSyncMsg method on OpenChannel

This commit is contained in:
Johan T. Halseth 2019-09-06 13:14:38 +02:00
parent 0122dda88a
commit eb1b84c0b4
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
5 changed files with 106 additions and 110 deletions

@ -16,6 +16,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/coreos/bbolt"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/shachain"
@ -810,6 +811,85 @@ func (c *OpenChannel) MarkBorked() error {
return c.putChanStatus(ChanStatusBorked)
}
// ChanSyncMsg returns the ChannelReestablish message that should be sent upon
// reconnection with the remote peer that we're maintaining this channel with.
// The information contained within this message is necessary to re-sync our
// commitment chains in the case of a last or only partially processed message.
// When the remote party receiver this message one of three things may happen:
//
// 1. We're fully synced and no messages need to be sent.
// 2. We didn't get the last CommitSig message they sent, to they'll re-send
// it.
// 3. We didn't get the last RevokeAndAck message they sent, so they'll
// re-send it.
//
// The isRestoredChan bool indicates if we need to craft a chan sync message
// for a channel that's been restored. If this is a restored channel, then
// we'll modify our typical chan sync message to ensure they force close even
// if we're on the very first state.
func (c *OpenChannel) ChanSyncMsg(
isRestoredChan bool) (*lnwire.ChannelReestablish, error) {
c.Lock()
defer c.Unlock()
// The remote commitment height that we'll send in the
// ChannelReestablish message is our current commitment height plus
// one. If the receiver thinks that our commitment height is actually
// *equal* to this value, then they'll re-send the last commitment that
// they sent but we never fully processed.
localHeight := c.LocalCommitment.CommitHeight
nextLocalCommitHeight := localHeight + 1
// The second value we'll send is the height of the remote commitment
// from our PoV. If the receiver thinks that their height is actually
// *one plus* this value, then they'll re-send their last revocation.
remoteChainTipHeight := c.RemoteCommitment.CommitHeight
// If this channel has undergone a commitment update, then in order to
// prove to the remote party our knowledge of their prior commitment
// state, we'll also send over the last commitment secret that the
// remote party sent.
var lastCommitSecret [32]byte
if remoteChainTipHeight != 0 {
remoteSecret, err := c.RevocationStore.LookUp(
remoteChainTipHeight - 1,
)
if err != nil {
return nil, err
}
lastCommitSecret = [32]byte(*remoteSecret)
}
// Additionally, we'll send over the current unrevoked commitment on
// our local commitment transaction.
currentCommitSecret, err := c.RevocationProducer.AtIndex(
localHeight,
)
if err != nil {
return nil, err
}
// If we've restored this channel, then we'll purposefully give them an
// invalid LocalUnrevokedCommitPoint so they'll force close the channel
// allowing us to sweep our funds.
if isRestoredChan {
currentCommitSecret[0] ^= 1
}
return &lnwire.ChannelReestablish{
ChanID: lnwire.NewChanIDFromOutPoint(
&c.FundingOutpoint,
),
NextLocalCommitHeight: nextLocalCommitHeight,
RemoteCommitTailHeight: remoteChainTipHeight,
LastRemoteCommitSecret: lastCommitSecret,
LocalUnrevokedCommitPoint: input.ComputeCommitmentPoint(
currentCommitSecret[:],
),
}, nil
}
// isBorked returns true if the channel has been marked as borked in the
// database. This requires an existing database transaction to already be
// active.

@ -731,8 +731,7 @@ func (c *chainWatcher) dispatchCooperativeClose(commitSpend *chainntnfs.SpendDet
}
// Attempt to add a channel sync message to the close summary.
chanSync, err := lnwallet.ChanSyncMsg(
c.cfg.chanState,
chanSync, err := c.cfg.chanState.ChanSyncMsg(
c.cfg.chanState.HasChanStatus(channeldb.ChanStatusRestored),
)
if err != nil {
@ -811,8 +810,7 @@ func (c *chainWatcher) dispatchLocalForceClose(
}
// Attempt to add a channel sync message to the close summary.
chanSync, err := lnwallet.ChanSyncMsg(
c.cfg.chanState,
chanSync, err := c.cfg.chanState.ChanSyncMsg(
c.cfg.chanState.HasChanStatus(channeldb.ChanStatusRestored),
)
if err != nil {
@ -998,8 +996,7 @@ func (c *chainWatcher) dispatchContractBreach(spendEvent *chainntnfs.SpendDetail
}
// Attempt to add a channel sync message to the close summary.
chanSync, err := lnwallet.ChanSyncMsg(
c.cfg.chanState,
chanSync, err := c.cfg.chanState.ChanSyncMsg(
c.cfg.chanState.HasChanStatus(channeldb.ChanStatusRestored),
)
if err != nil {

@ -609,8 +609,7 @@ func (l *channelLink) syncChanStates() error {
// side. Based on this message, the remote party will decide if they
// need to retransmit any data or not.
chanState := l.channel.State()
localChanSyncMsg, err := lnwallet.ChanSyncMsg(
chanState,
localChanSyncMsg, err := chanState.ChanSyncMsg(
chanState.HasChanStatus(channeldb.ChanStatusRestored),
)
if err != nil {

@ -3527,85 +3527,6 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
return updates, openedCircuits, closedCircuits, nil
}
// ChanSyncMsg returns the ChannelReestablish message that should be sent upon
// reconnection with the remote peer that we're maintaining this channel with.
// The information contained within this message is necessary to re-sync our
// commitment chains in the case of a last or only partially processed message.
// When the remote party receiver this message one of three things may happen:
//
// 1. We're fully synced and no messages need to be sent.
// 2. We didn't get the last CommitSig message they sent, to they'll re-send
// it.
// 3. We didn't get the last RevokeAndAck message they sent, so they'll
// re-send it.
//
// The isRestoredChan bool indicates if we need to craft a chan sync message
// for a channel that's been restored. If this is a restored channel, then
// we'll modify our typical chan sync message to ensure they force close even
// if we're on the very first state.
func ChanSyncMsg(c *channeldb.OpenChannel,
isRestoredChan bool) (*lnwire.ChannelReestablish, error) {
c.Lock()
defer c.Unlock()
// The remote commitment height that we'll send in the
// ChannelReestablish message is our current commitment height plus
// one. If the receiver thinks that our commitment height is actually
// *equal* to this value, then they'll re-send the last commitment that
// they sent but we never fully processed.
localHeight := c.LocalCommitment.CommitHeight
nextLocalCommitHeight := localHeight + 1
// The second value we'll send is the height of the remote commitment
// from our PoV. If the receiver thinks that their height is actually
// *one plus* this value, then they'll re-send their last revocation.
remoteChainTipHeight := c.RemoteCommitment.CommitHeight
// If this channel has undergone a commitment update, then in order to
// prove to the remote party our knowledge of their prior commitment
// state, we'll also send over the last commitment secret that the
// remote party sent.
var lastCommitSecret [32]byte
if remoteChainTipHeight != 0 {
remoteSecret, err := c.RevocationStore.LookUp(
remoteChainTipHeight - 1,
)
if err != nil {
return nil, err
}
lastCommitSecret = [32]byte(*remoteSecret)
}
// Additionally, we'll send over the current unrevoked commitment on
// our local commitment transaction.
currentCommitSecret, err := c.RevocationProducer.AtIndex(
localHeight,
)
if err != nil {
return nil, err
}
// If we've restored this channel, then we'll purposefully give them an
// invalid LocalUnrevokedCommitPoint so they'll force close the channel
// allowing us to sweep our funds.
if isRestoredChan {
currentCommitSecret[0] ^= 1
}
return &lnwire.ChannelReestablish{
ChanID: lnwire.NewChanIDFromOutPoint(
&c.FundingOutpoint,
),
NextLocalCommitHeight: nextLocalCommitHeight,
RemoteCommitTailHeight: remoteChainTipHeight,
LastRemoteCommitSecret: lastCommitSecret,
LocalUnrevokedCommitPoint: input.ComputeCommitmentPoint(
currentCommitSecret[:],
),
}, nil
}
// computeView takes the given htlcView, and calculates the balances, filtered
// view (settling unsettled HTLCs), commitment weight and feePerKw, after
// applying the HTLCs to the latest commitment. The returned balances are the
@ -5187,8 +5108,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
}
// Attempt to add a channel sync message to the close summary.
chanSync, err := ChanSyncMsg(
chanState,
chanSync, err := chanState.ChanSyncMsg(
chanState.HasChanStatus(channeldb.ChanStatusRestored),
)
if err != nil {

@ -2530,7 +2530,7 @@ func assertNoChanSyncNeeded(t *testing.T, aliceChannel *LightningChannel,
_, _, line, _ := runtime.Caller(1)
aliceChanSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
aliceChanSyncMsg, err := aliceChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("line #%v: unable to produce chan sync msg: %v",
line, err)
@ -2545,7 +2545,7 @@ func assertNoChanSyncNeeded(t *testing.T, aliceChannel *LightningChannel,
"instead wants to send: %v", line, spew.Sdump(bobMsgsToSend))
}
bobChanSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobChanSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("line #%v: unable to produce chan sync msg: %v",
line, err)
@ -2778,11 +2778,11 @@ func TestChanSyncOweCommitment(t *testing.T) {
// Bob doesn't get this message so upon reconnection, they need to
// synchronize. Alice should conclude that she owes Bob a commitment,
// while Bob should think he's properly synchronized.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
aliceSyncMsg, err := aliceChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3092,11 +3092,11 @@ func TestChanSyncOweRevocation(t *testing.T) {
// If we fetch the channel sync messages at this state, then Alice
// should report that she owes Bob a revocation message, while Bob
// thinks they're fully in sync.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
aliceSyncMsg, err := aliceChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3261,11 +3261,11 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) {
// If we now attempt to resync, then Alice should conclude that she
// doesn't need any further updates, while Bob concludes that he needs
// to re-send both his revocation and commit sig message.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
aliceSyncMsg, err := aliceChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3472,11 +3472,11 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) {
// Now if we attempt to synchronize states at this point, Alice should
// detect that she owes nothing, while Bob should re-send both his
// RevokeAndAck as well as his commitment message.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
aliceSyncMsg, err := aliceChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3677,11 +3677,11 @@ func TestChanSyncFailure(t *testing.T) {
assertLocalDataLoss := func(aliceOld *LightningChannel) {
t.Helper()
aliceSyncMsg, err := ChanSyncMsg(aliceOld.channelState, false)
aliceSyncMsg, err := aliceOld.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3755,7 +3755,7 @@ func TestChanSyncFailure(t *testing.T) {
// If we remove the recovery options from Bob's message, Alice cannot
// tell if she lost state, since Bob might be lying. She still should
// be able to detect that chains cannot be synced.
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3769,7 +3769,7 @@ func TestChanSyncFailure(t *testing.T) {
// If Bob lies about the NextLocalCommitHeight, making it greater than
// what Alice expect, she cannot tell for sure whether she lost state,
// but should detect the desync.
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err = bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3782,7 +3782,7 @@ func TestChanSyncFailure(t *testing.T) {
// If Bob's NextLocalCommitHeight is lower than what Alice expects, Bob
// probably lost state.
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err = bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3795,7 +3795,7 @@ func TestChanSyncFailure(t *testing.T) {
// If Alice and Bob's states are in sync, but Bob is sending the wrong
// LocalUnrevokedCommitPoint, Alice should detect this.
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err = bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3824,7 +3824,7 @@ func TestChanSyncFailure(t *testing.T) {
// when there's a pending remote commit.
halfAdvance()
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err = bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3912,11 +3912,11 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
// Bob doesn't get this message so upon reconnection, they need to
// synchronize. Alice should conclude that she owes Bob a commitment,
// while Bob should think he's properly synchronized.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
aliceSyncMsg, err := aliceChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
bobSyncMsg, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -4361,11 +4361,11 @@ func TestChanSyncInvalidLastSecret(t *testing.T) {
}
// Next, we'll produce the ChanSync messages for both parties.
aliceChanSync, err := ChanSyncMsg(aliceChannel.channelState, false)
aliceChanSync, err := aliceChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to generate chan sync msg: %v", err)
}
bobChanSync, err := ChanSyncMsg(bobChannel.channelState, false)
bobChanSync, err := bobChannel.channelState.ChanSyncMsg(false)
if err != nil {
t.Fatalf("unable to generate chan sync msg: %v", err)
}