Skip to content

Commit

Permalink
Merge 7bc9eb9 into 9320760
Browse files Browse the repository at this point in the history
  • Loading branch information
wpaulino committed Jul 12, 2018
2 parents 9320760 + 7bc9eb9 commit 2e786fc
Show file tree
Hide file tree
Showing 10 changed files with 692 additions and 464 deletions.
14 changes: 14 additions & 0 deletions chancloser.go
Expand Up @@ -78,6 +78,10 @@ type chanCloseCfg struct {
// broadcastTx broadcasts the passed transaction to the network.
broadcastTx func(*wire.MsgTx) error

// disableChannel disables a channel, resulting in it not being able to
// forward payments.
disableChannel func(wire.OutPoint) error

// quit is a channel that should be sent upon in the occasion the state
// machine should cease all progress and shutdown.
quit chan struct{}
Expand Down Expand Up @@ -436,6 +440,16 @@ func (c *channelCloser) ProcessCloseMsg(msg lnwire.Message) ([]lnwire.Message, b
return nil, false, err
}

// We'll attempt to disable the channel in the background to
// avoid blocking due to sending the update message to all
// active peers.
go func() {
if err := c.cfg.disableChannel(c.chanPoint); err != nil {
peerLog.Errorf("Unable to disable channel %v on "+
"close: %v", c.chanPoint, err)
}
}()

// Finally, we'll transition to the closeFinished state, and
// also return the final close signed message we sent.
// Additionally, we return true for the second argument to
Expand Down
14 changes: 14 additions & 0 deletions contractcourt/chain_arbitrator.go
Expand Up @@ -122,6 +122,10 @@ type ChainArbitratorConfig struct {

// ChainIO allows us to query the state of the current main chain.
ChainIO lnwallet.BlockChainIO

// DisableChannel disables a channel, resulting in it not being able to
// forward payments.
DisableChannel func(wire.OutPoint) error
}

// ChainArbitrator is a sub-system that oversees the on-chain resolution of all
Expand Down Expand Up @@ -667,6 +671,16 @@ func (c *ChainArbitrator) ForceCloseContract(chanPoint wire.OutPoint) (*wire.Msg
return nil, fmt.Errorf("ChainArbitrator shutting down")
}

// We'll attempt to disable the channel in the background to
// avoid blocking due to sending the update message to all
// active peers.
go func() {
if err := c.cfg.DisableChannel(chanPoint); err != nil {
log.Errorf("Unable to disable channel %v on "+
"close: %v", chanPoint, err)
}
}()

return closeTx, nil
}

Expand Down
160 changes: 123 additions & 37 deletions lnd_test.go
Expand Up @@ -806,6 +806,9 @@ func checkChannelPolicy(policy, expectedPolicy *lnrpc.RoutingPolicy) error {
expectedPolicy.TimeLockDelta,
policy.TimeLockDelta)
}
if policy.Disabled != expectedPolicy.Disabled {
return errors.New("edge should be disabled but isn't")
}

return nil
}
Expand Down Expand Up @@ -2809,7 +2812,7 @@ func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode,

// Wait for listener node to receive the channel update from node.
ctxt, _ = context.WithTimeout(ctxb, timeout)
listenerUpdates, aQuit := subscribeGraphNotifications(t, ctxt,
listenerUpdates, aQuit := subscribeGraphNotifications(t, ctxt,
listenerNode)
defer close(aQuit)

Expand Down Expand Up @@ -2980,8 +2983,8 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {

time.Sleep(time.Millisecond * 50)

// Set the fee policies of the Alice -> Bob and the Dave -> Alice
// channel edges to relatively large non default values. This makes it
// Set the fee policies of the Alice -> Bob and the Dave -> Alice
// channel edges to relatively large non default values. This makes it
// possible to pick up more subtle fee calculation errors.
updateChannelPolicy(t, net.Alice, chanPointAlice, 1000, 100000,
144, carol)
Expand Down Expand Up @@ -3017,10 +3020,10 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
assertAmountPaid(t, ctxb, "Alice(local) => Bob(remote)", net.Alice,
aliceFundPoint, expectedAmountPaidAtoB, int64(0))

// To forward a payment of 1000 sat, Alice is charging a fee of
// To forward a payment of 1000 sat, Alice is charging a fee of
// 1 sat + 10% = 101 sat.
const expectedFeeAlice = 5 * 101

// Dave needs to pay what Alice pays plus Alice's fee.
expectedAmountPaidDtoA := expectedAmountPaidAtoB + expectedFeeAlice

Expand All @@ -3029,7 +3032,7 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
assertAmountPaid(t, ctxb, "Dave(local) => Alice(remote)", dave,
daveFundPoint, expectedAmountPaidDtoA, int64(0))

// To forward a payment of 1101 sat, Dave is charging a fee of
// To forward a payment of 1101 sat, Dave is charging a fee of
// 5 sat + 15% = 170.15 sat. This is rounded down in rpcserver to 170.
const expectedFeeDave = 5 * 170

Expand Down Expand Up @@ -6232,39 +6235,48 @@ func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest)
ctxt, _ = context.WithTimeout(context.Background(), timeout)
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)

// Similar to the case above, we should receive another notification
// detailing the channel closure.
select {
case graphUpdate := <-graphUpdates:
if len(graphUpdate.ClosedChans) != 1 {
t.Fatalf("expected a single update, instead "+
"have %v", len(graphUpdate.ClosedChans))
}
// Now that the channel has been closed, we should receive a
// notification indicating so.
out:
for {
select {
case graphUpdate := <-graphUpdates:
if len(graphUpdate.ClosedChans) != 1 {
continue
}

closedChan := graphUpdate.ClosedChans[0]
if closedChan.ClosedHeight != uint32(blockHeight+1) {
t.Fatalf("close heights of channel mismatch: expected "+
"%v, got %v", blockHeight+1, closedChan.ClosedHeight)
}
chanPointTxid, err := getChanPointFundingTxid(chanPoint)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
closedChanTxid, err := getChanPointFundingTxid(closedChan.ChanPoint)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
if !bytes.Equal(closedChanTxid, chanPointTxid) {
t.Fatalf("channel point hash mismatch: expected %v, "+
"got %v", chanPointTxid, closedChanTxid)
}
if closedChan.ChanPoint.OutputIndex != chanPoint.OutputIndex {
t.Fatalf("output index mismatch: expected %v, got %v",
chanPoint.OutputIndex, closedChan.ChanPoint)
closedChan := graphUpdate.ClosedChans[0]
if closedChan.ClosedHeight != uint32(blockHeight+1) {
t.Fatalf("close heights of channel mismatch: "+
"expected %v, got %v", blockHeight+1,
closedChan.ClosedHeight)
}
chanPointTxid, err := getChanPointFundingTxid(chanPoint)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
closedChanTxid, err := getChanPointFundingTxid(
closedChan.ChanPoint,
)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
if !bytes.Equal(closedChanTxid, chanPointTxid) {
t.Fatalf("channel point hash mismatch: "+
"expected %v, got %v", chanPointTxid,
closedChanTxid)
}
if closedChan.ChanPoint.OutputIndex != chanPoint.OutputIndex {
t.Fatalf("output index mismatch: expected %v, "+
"got %v", chanPoint.OutputIndex,
closedChan.ChanPoint)
}

break out
case <-time.After(time.Second * 10):
t.Fatalf("notification for channel closure not " +
"sent")
}
case <-time.After(time.Second * 10):
t.Fatalf("notification for channel closure not " +
"sent")
}

// For the final portion of the test, we'll ensure that once a new node
Expand Down Expand Up @@ -10145,6 +10157,76 @@ func testRouteFeeCutoff(net *lntest.NetworkHarness, t *harnessTest) {
}
}

// testSendUpdateDisableChannel ensures that a channel update with the disable
// flag set is sent once a channel has been either unilaterally or cooperatively
// closed.
func testSendUpdateDisableChannel(net *lntest.NetworkHarness, t *harnessTest) {
const (
chanAmt = 100000
timeout = 10 * time.Second
)

// Open a channel between Alice and Bob and Alice and Carol. These will
// be closed later on in order to trigger channel update messages
// marking the channels as disabled.
ctxb := context.Background()
ctxt, _ := context.WithTimeout(ctxb, timeout)
chanPointAliceBob := openChannelAndAssert(
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
)

carol, err := net.NewNode("Carol", nil)
if err != nil {
t.Fatalf("unable to create carol's node: %v", err)
}
defer shutdownAndAssert(net, t, carol)
if err := net.ConnectNodes(ctxb, net.Alice, carol); err != nil {
t.Fatalf("unable to connect alice to carol: %v", err)
}
ctxt, _ = context.WithTimeout(ctxb, timeout)
chanPointAliceCarol := openChannelAndAssert(
ctxt, t, net, net.Alice, carol, chanAmt, 0, false,
)

// Launch a node for Dave which will connect to Bob in order to receive
// graph updates from. This will ensure that the channel updates are
// propagated throughout the network.
dave, err := net.NewNode("Dave", nil)
if err != nil {
t.Fatalf("unable to create dave's node: %v", err)
}
defer shutdownAndAssert(net, t, dave)
if err := net.ConnectNodes(ctxb, net.Bob, dave); err != nil {
t.Fatalf("unable to connect bob to dave: %v", err)
}

daveUpdates, quit := subscribeGraphNotifications(t, ctxb, net.Alice)
defer close(quit)

// We should expect to see a channel update with the default routing
// policy, except that it should indicate the channel is disabled.
expectedPolicy := &lnrpc.RoutingPolicy{
FeeBaseMsat: int64(defaultBitcoinBaseFeeMSat),
FeeRateMilliMsat: int64(defaultBitcoinFeeRate),
TimeLockDelta: defaultBitcoinTimeLockDelta,
Disabled: true,
}

// Close Alice's channels with Bob and Carol cooperatively and
// unilaterally respectively.
ctxt, _ = context.WithTimeout(ctxb, timeout)
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAliceBob, false)
ctxt, _ = context.WithTimeout(ctxb, timeout)
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAliceCarol, true)

// Now that the channels have been closed, we should receive an update
// marking each as disabled.
waitForChannelUpdate(
t, daveUpdates, net.Alice.PubKeyStr, expectedPolicy,
chanPointAliceBob, chanPointAliceCarol,
)
}

type testCase struct {
name string
test func(net *lntest.NetworkHarness, t *harnessTest)
Expand Down Expand Up @@ -10340,6 +10422,10 @@ var testsCases = []*testCase{
name: "route fee cutoff",
test: testRouteFeeCutoff,
},
{
name: "send update disable channel",
test: testSendUpdateDisableChannel,
},
}

// TestLightningNetworkDaemon performs a series of integration tests amongst a
Expand Down

0 comments on commit 2e786fc

Please sign in to comment.