Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lncli command / RPC for manually setting channel state #5033

Merged
merged 14 commits into from Mar 10, 2021

Conversation

robot-dreams
Copy link
Contributor

Currently, there's no mechanism for manually setting the network state of a given channel. This PR adds an RPC endpoint to the routing sub-server, as well as a corresponding lncli command, so that users can manually update channel state.

Note that such updates only the channel state that's broadcast over the network (i.e. whether or not the lnwire.ChanUpdateDisabled flag is set). In particular, disabling a channel does NOT close it.

This change also interacts with the pre-existing mechanism for automtically enabling / disabling channels (e.g. when a peer disconnects or reconnects):

  • If a user manually disables a channel, then subsequent automatic requests to re-enable the channel will be ignored. The user has to manually re-enable the channel, or use the lncli setchannelstatus command to set the state back to auto.
  • If a user manually enables a channel, then subsequent automatic requests to re-enable the channel will be respected. Such requests usually arise from a channel being closed or a peer going offline; in these cases, we do not want to clutter the network with false information that the channel is still enabled.

Sample behavior:

$ <shut down peer>

[DBG] NANN: Marking channel(242...:0) pending-inactive
...
[INF] NANN: Announcing channel(242...:0) disabled [detected]

$ <restart peer>

[INF] NANN: Announcing channel(242...:0) enabled

$ lncli setchannelstatus --funding_txid=242... --output_index=0 --action=disable

[DBG] RRPC: SetChannelStatus called for channel(242...:0) with action DISABLE
[INF] NANN: Announcing channel(242...:0) disabled [requested]

$ <restart peer>

[INF] PEER: Channel(242...:0) was manually disabled, ignoring automatic enable request

Fixes: #4543

Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great first-time contribution!

I've done an initial pass of the diff, but plan to do another to really grok some of the state machine transition modifications. I think we can also test the return to auto management by closing a channel in the itest to ensure that triggers a disable to be sent.

contractcourt/chain_arbitrator.go Outdated Show resolved Hide resolved
netann/chan_status_manager.go Show resolved Hide resolved
netann/chan_status_manager.go Outdated Show resolved Hide resolved
netann/chan_status_manager.go Outdated Show resolved Hide resolved
netann/chan_status_manager.go Show resolved Hide resolved
lnrpc/routerrpc/router.proto Outdated Show resolved Hide resolved
lnrpc/rpc_utils.go Show resolved Hide resolved
lntest/itest/lnd_test.go Outdated Show resolved Hide resolved
lntest/itest/lnd_test.go Show resolved Hide resolved
peer/brontide.go Outdated Show resolved Hide resolved
@robot-dreams
Copy link
Contributor Author

Thanks for taking a look! I've hopefully addressed your initial feedback.

Updating the itest according to your suggestions did reveal one additional subtlety though: the updatechanstatus commands only updates the policy on our end, not on the peer's end. Is this what we want, or should we re-think the approach to account for the peer's policy as well?

@robot-dreams
Copy link
Contributor Author

Actually I think there might be a blocking issue here. Converting to draft until I confirm it's fixed...

@robot-dreams robot-dreams marked this pull request as draft February 18, 2021 22:41
@robot-dreams
Copy link
Contributor Author

OK, my main concern was around the following issue.

Say Alice/Bob have a channel and Alice/Charlie have a channel. If we disable the Alice/Bob channel from Alice's end but then immediately send a payment Charlie -> Bob (i.e. before Alice broadcasts the ChannelUpdate message) then Charlie's attempt to route the payment via Charlie -> Alice -> Bob will still succeed.

Per discussion with @Roasbeef , we can proceed with the current PR and address the "eventual consistency" concern as a follow-up.

@robot-dreams robot-dreams marked this pull request as ready for review February 19, 2021 05:28
Copy link
Contributor

@cfromknecht cfromknecht left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robot-dreams great work on this PR, I know a lot of people will be excited to have this feature! A+ commit structure as well, very easy to follow the changes

Say Alice/Bob have a channel and Alice/Charlie have a channel. If we disable the Alice/Bob channel from Alice's end but then immediately send a payment Charlie -> Bob (i.e. before Alice broadcasts the ChannelUpdate message) then Charlie's attempt to route the payment via Charlie -> Alice -> Bob will still succeed.

Per discussion with @Roasbeef , we can proceed with the current PR and address the "eventual consistency" concern as a follow-up.

Good observation here! Indeed we don't honor this in the switch currently, there have been some discussions in the past as to whether we treat the disable bit as more of a network signaling (aka you shouldn't try this channel) vs actually enforcing it. I can imagine cases where each mode might be useful, it could be worthwhile to explore adding a configuration-level toggle whether one wants to enforce "strict disables" or not.

I'd say this PR looks just about merge-ready, only a few nits from me. I really like the approach of adding the ability to return the status management back to auto, makes the API very clean 👍

switch curState.Status {

// Channel is already disabled, nothing to do.
case ChanStatusDisabled:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this imply the entry for outpoint wasn't being cleaned up on channel close?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entry was getting cleaned up for a cooperative close, since the channel would've started out in ChanStatusEnabled so we don't hit this case.

However, it was not getting cleaned up if the channel was already in ChanStatusDisabled (e.g. peer went offline for a while) and you do a force close.

More specifically (with extra debug logging for removing the channel from the map):

Before this PR

cooperative close:

[INF] NANN: Announcing channel(...) disabled [requested]
[DBG] NANN: Removing channel(...) from map

peer goes down + force close disabled channel:

[INF] NANN: Announcing channel(...) disabled [detected]
>>> force close doesn't remove channel from map

After this PR

cooperative close:

[INF] NANN: Announcing channel(...) disabled [requested]
[DBG] NANN: Removing channel(...) from map

peer goes down + force close disabled channel:

[INF] NANN: Announcing channel(...) disabled [detected]
[DBG] NANN: Removing channel(...) from map

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool, great catch! Always good to make ensure we clean up after ourselves.

peer/brontide.go Show resolved Hide resolved
rpcserver.go Outdated Show resolved Hide resolved
lnrpc/routerrpc/router_backend.go Outdated Show resolved Hide resolved
@robot-dreams
Copy link
Contributor Author

Thanks for the encouraging review and the helpful context!

Add a new boolean parameter without changing any existing
functionality. The parameter will be used to indicate
whether a request to update a channel's status was made
manually by a user (currently always false).
Add new value for ChanStatus without changing any existing
functionality. The new value indicates that a user manually
requested disabling a channel.
Add boolean parameter for test functions without changing any
existing functionality. All current tests set manual = false, but
Future tests can set manual = true to test manual requests to
update channel state.
If a channel was manually disabled, subsequent automatic / background
requests to update that channel's state will be ignored. A RequestAuto
call restores automatic / background state management and indicates
that such requests should no longer be ignored.
Update router.proto and rest-annotations.yaml, recompile protos,
add a stub implementation to routerrpc.Server.
Allow router RPC requests to call into the ChanStatusManager to
manually update channel state.
This refactor-only change makes the GetChanPointFundingTxid helper
function available from sub-systems outside of the root lnd package.
Update UpdateChanStatus stub implementation to call into exposed
ChanStatusManager methods in RouterBackend.
The updatechanstatus command calls into the UpdateChanStatus RPC
in the router server.
Copy link
Contributor

@cfromknecht cfromknecht left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🔥

// update is propagated.
sendReq(alice, chanPoint, routerrpc.ChanStatusAction_DISABLE)
expectedPolicy.Disabled = true
waitForChannelUpdate(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neutrino integration test failed on this line with:

=== RUN   TestLightningNetworkDaemon/18-of-72/neutrino/update_channel_status
    test_harness.go:88: Failed: (update channel status): exited with error: 
        *errors.errorString did not receive channel update
        /home/travis/gopath/src/github.com/lightningnetwork/lnd/lntest/itest/lnd_test.go:1814 (0xe7afb2)
        	waitForChannelUpdate: t.Fatalf("did not receive channel update")
        /home/travis/gopath/src/github.com/lightningnetwork/lnd/lntest/itest/lnd_test.go:5344 (0xe8ec6f)
        	testUpdateChanStatus: waitForChannelUpdate(
        /home/travis/gopath/src/github.com/lightningnetwork/lnd/lntest/itest/test_harness.go:112 (0xe4c3ee)
        	(*harnessTest).RunTestCase: testCase.test(h.lndHarness, h)
        /home/travis/gopath/src/github.com/lightningnetwork/lnd/lntest/itest/lnd_test.go:14885 (0xeef005)
        	TestLightningNetworkDaemon.func4: ht.RunTestCase(testCase)
        /home/travis/.gimme/versions/go1.15.7.linux.amd64/src/testing/testing.go:1123 (0x51c2ef)
        	tRunner: fn(t)
        /home/travis/.gimme/versions/go1.15.7.linux.amd64/src/runtime/asm_amd64.s:1374 (0x46f821)
        	goexit: BYTE	$0x90	// NOP

I think this related to another issue ( #4866) however, since the test passes locally for me. I think it's safe to ignore this for now and revisit once the other issue is fixed. I restarted the itest and it passed 👍

@cfromknecht cfromknecht added channel management The management of the nodes channels discovery Peer and route discovery / whisper protocol related issues/PRs labels Mar 1, 2021
@cfromknecht cfromknecht added rpc Related to the RPC interface v0.13 labels Mar 1, 2021
@Roasbeef Roasbeef added this to the 0.13.0 milestone Mar 10, 2021
@Roasbeef Roasbeef added this to In progress in v0.13.0-beta via automation Mar 10, 2021
v0.13.0-beta automation moved this from In progress to Reviewer approved Mar 10, 2021
Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🧨

@Roasbeef Roasbeef merged commit 65b0bbc into lightningnetwork:master Mar 10, 2021
v0.13.0-beta automation moved this from Reviewer approved to Done Mar 10, 2021
@robot-dreams robot-dreams deleted the set-channel-status branch March 10, 2021 07:07
@dskvr
Copy link

dskvr commented Jun 9, 2023

The road to figure out how to update a channel status lands here, but the command has changed. So anyone looking

setchannelstatus -> updatechanstatus ... same arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
channel management The management of the nodes channels discovery Peer and route discovery / whisper protocol related issues/PRs rpc Related to the RPC interface v0.13
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

rpc: add new external API for manual channel enable/disable
4 participants