Merge branch 'refresh-chan-id'

This commit is contained in:
Olaoluwa Osuntokun 2019-11-27 15:21:42 -06:00
commit d59aba35a0
3 changed files with 118 additions and 12 deletions

@ -594,13 +594,16 @@ func (c *OpenChannel) hasChanStatus(status ChannelStatus) bool {
return c.chanStatus&status == status return c.chanStatus&status == status
} }
// RefreshShortChanID updates the in-memory short channel ID using the latest // RefreshShortChanID updates the in-memory channel state using the latest
// value observed on disk. // value observed on disk.
//
// TODO: the name of this function should be changed to reflect the fact that
// it is not only refreshing the short channel id but all the channel state.
// maybe Refresh/Reload?
func (c *OpenChannel) RefreshShortChanID() error { func (c *OpenChannel) RefreshShortChanID() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
var sid lnwire.ShortChannelID
err := c.Db.View(func(tx *bbolt.Tx) error { err := c.Db.View(func(tx *bbolt.Tx) error {
chanBucket, err := fetchChanBucket( chanBucket, err := fetchChanBucket(
tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash, tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
@ -609,22 +612,18 @@ func (c *OpenChannel) RefreshShortChanID() error {
return err return err
} }
channel, err := fetchOpenChannel(chanBucket, &c.FundingOutpoint) // We'll re-populating the in-memory channel with the info
if err != nil { // fetched from disk.
return err if err := fetchChanInfo(chanBucket, c); err != nil {
return fmt.Errorf("unable to fetch chan info: %v", err)
} }
sid = channel.ShortChannelID
return nil return nil
}) })
if err != nil { if err != nil {
return err return err
} }
c.ShortChannelID = sid
c.Packager = NewChannelPackager(sid)
return nil return nil
} }

@ -939,8 +939,8 @@ func TestFetchWaitingCloseChannels(t *testing.T) {
} }
// TestRefreshShortChanID asserts that RefreshShortChanID updates the in-memory // TestRefreshShortChanID asserts that RefreshShortChanID updates the in-memory
// short channel ID of another OpenChannel to reflect a preceding call to // state of another OpenChannel to reflect a preceding call to MarkOpen on a
// MarkOpen on a different OpenChannel. // different OpenChannel.
func TestRefreshShortChanID(t *testing.T) { func TestRefreshShortChanID(t *testing.T) {
t.Parallel() t.Parallel()
@ -1038,4 +1038,10 @@ func TestRefreshShortChanID(t *testing.T) {
"got %v", chanOpenLoc, "got %v", chanOpenLoc,
pendingChannel.Packager.(*ChannelPackager).source) pendingChannel.Packager.(*ChannelPackager).source)
} }
// Check to ensure that this channel is no longer pending and this field
// is up to date.
if pendingChannel.IsPending {
t.Fatalf("channel pending state wasn't updated: want false got true")
}
} }

@ -1219,6 +1219,103 @@ func testUnconfirmedChannelFunding(net *lntest.NetworkHarness, t *harnessTest) {
closeChannelAndAssert(ctxt, t, net, carol, chanPoint, false) closeChannelAndAssert(ctxt, t, net, carol, chanPoint, false)
} }
// testPaymentFollowingChannelOpen tests that the channel transition from
// 'pending' to 'open' state does not cause any inconsistencies within other
// subsystems trying to udpate the channel state in the db. We follow this
// transition with a payment that updates the commitment state and verify that
// the pending state is up to date.
func testPaymentFollowingChannelOpen(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background()
const paymentAmt = btcutil.Amount(100)
channelCapacity := btcutil.Amount(paymentAmt * 1000)
// We first establish a channel between Alice and Bob.
ctxt, cancel := context.WithTimeout(ctxb, channelOpenTimeout)
defer cancel()
pendingUpdate, err := net.OpenPendingChannel(
ctxt, net.Alice, net.Bob, channelCapacity, 0,
)
if err != nil {
t.Fatalf("unable to open channel: %v", err)
}
// At this point, the channel's funding transaction will have been
// broadcast, but not confirmed. Alice and Bob's nodes
// should reflect this when queried via RPC.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
assertNumOpenChannelsPending(ctxt, t, net.Alice, net.Bob, 1)
// We are restarting Bob's node to let the link be created for the
// pending channel.
if err := net.RestartNode(net.Bob, nil); err != nil {
t.Fatalf("Bob restart failed: %v", err)
}
// We ensure that Bob reconnets to Alice.
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
if err := net.EnsureConnected(ctxt, net.Bob, net.Alice); err != nil {
t.Fatalf("peers unable to reconnect after restart: %v", err)
}
// We mine one block for the channel to be confirmed.
_ = mineBlocks(t, net, 6, 1)[0]
// We verify that the chanel is open from both nodes point of view.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
assertNumOpenChannelsPending(ctxt, t, net.Alice, net.Bob, 0)
// With the channel open, we'll create invoices for Bob that Alice will
// pay to in order to advance the state of the channel.
bobPayReqs, _, _, err := createPayReqs(
net.Bob, paymentAmt, 1,
)
if err != nil {
t.Fatalf("unable to create pay reqs: %v", err)
}
// Send payment to Bob so there a chanel update to disk will be
// executed.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
_, err = net.Alice.SendPaymentSync(
ctxt,
&lnrpc.SendRequest{
PaymentRequest: bobPayReqs[0],
},
)
if err != nil {
t.Fatalf("unable to create payment stream for alice: %v", err)
}
// At this point we want to make sure the channel is opened and not
// pending.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
res, err := net.Bob.ListChannels(ctxt, &lnrpc.ListChannelsRequest{})
if err != nil {
t.Fatalf("unable to list bob channels: %v", err)
}
if len(res.Channels) == 0 {
t.Fatalf("bob list of channels is empty")
}
// Finally, immediately close the channel. This function will also
// block until the channel is closed and will additionally assert the
// relevant channel closing post conditions.
chanPoint := &lnrpc.ChannelPoint{
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
FundingTxidBytes: pendingUpdate.Txid,
},
OutputIndex: pendingUpdate.OutputIndex,
}
ctxt, cancel = context.WithTimeout(ctxb, channelCloseTimeout)
defer cancel()
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
}
// txStr returns the string representation of the channel's funding transaction. // txStr returns the string representation of the channel's funding transaction.
func txStr(chanPoint *lnrpc.ChannelPoint) string { func txStr(chanPoint *lnrpc.ChannelPoint) string {
fundingTxID, err := lnd.GetChanPointFundingTxid(chanPoint) fundingTxID, err := lnd.GetChanPointFundingTxid(chanPoint)
@ -14955,6 +15052,10 @@ var testsCases = []*testCase{
name: "macaroon authentication", name: "macaroon authentication",
test: testMacaroonAuthentication, test: testMacaroonAuthentication,
}, },
{
name: "immediate payment after channel opened",
test: testPaymentFollowingChannelOpen,
},
} }
// TestLightningNetworkDaemon performs a series of integration tests amongst a // TestLightningNetworkDaemon performs a series of integration tests amongst a