-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Allow remote signer to run without chain backend #6006
Allow remote signer to run without chain backend #6006
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a high level pass. Very necessary change as the remote signers can now live in a "cold" environment without running a bitcoin node. Thanks for the effort!
9277f62
to
2fd6507
Compare
302ce8b
to
e6a54da
Compare
59b1cbc
to
aa9aa45
Compare
One question I was pondering: Should we add a new itest mode where every node in the itest gets its own remote signer? Since we don't need a chain backend anymore it should be doable. That would certainly increase the test coverage of the signing. But I'm not sure if that warrants the extra time spent on it (and also the new itest GitHub slot that would be taken up by it). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass looks good! Will take a more detailed look at tests + RPCKeyRing
in next look.
Could be an easier solution to just add a single itest case with 1x remote signer and open channel/ transact close? Will be a bit of additional wiring on the harness for single use but I think that'll give us good enough coverage? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! I'll need to get more familiar with the hd wallet implemented in lnwallet
to understand the scope change. Meanwhile, have questions re unit tests and the 256 key families init.
Should we add a new itest mode where every node in the itest gets its own remote signer?
Then I guess we would need to visit every test to validate the expected behavior of the remote signer?
aa9aa45
to
0f268b5
Compare
Not sure I understand what you mean. Isn't this what's already been done in the |
0f268b5
to
20b1e75
Compare
Yeah ofc, forgot we had that! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed to the best of my ability + tested locally (np2wkh/ p2wkh + channel open).
I haven't done much wallet work, so can't be confident that I'd pick up any subtle bugs, so you might want to pick up another reviewer with more domain knowledge.
One thing I did notice while testing is that watch-only
won't shut down if signer
is down. Could use Criticalf
if signing fails, or add a health check if we're running with remote signer.
20b1e75
to
f7a86d1
Compare
With the remote signing instance now not needing to know anything about addresses or current derivation indices, we don't need to forward any such calls to that instance and can simplify the RPCKeyRing considerably.
This fixes lightninglabs/loop#437 by adding all accounts that are used in liquidity products such as Loop or Pool. Since both of these products use key families below 255, we can get by with that number. The alternative to creating way too many accounts (which increases the default wallet size by ~250kB) would be to hard code the exact accounts used by Loop (99) and Pool (210). But that sounds like a bad idea given that there could always be more accounts being added to those (or other) products. By making sure the first 255 accounts exist, we have a lot more flexibility in those products for choosing key families.
To enable converting an existing wallet with private key material into a watch-only wallet on first startup with remote signing enabled, we add a new flag. Since the conversion is a destructive process, this shouldn't happen automatically just because remote signing is enabled.
50d8164
to
5282c9a
Compare
I added an itest for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM🥳 The added itest is very helpful as now I just treat the itest as example usages for all the endpoints. Again very nice job!!
"purging all private key material") | ||
|
||
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey) | ||
err = b.wallet.Manager.ConvertToWatchingOnly(ns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. With this commit I guess we can now turn a non-watch-only node into a watch-only node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🐊
Great touch with the new flag to migrate the wallet to a watch only version, this'll make it much easier to production systems to retroactively adopt the remote signer architecture.
It's a nice step forward to be able to isolate the key material in a minimal lnd instance, but what's your thought on adding policy controls to prevent a hacker from using the signing instance in an unlimited way? If there are no limits, it's almost as if the hacker owns the keys themselves I'd think. The current remote signing API is low-level and I am not sure if it is possible to add useful limits. The lightning signer project for example works on higher level: https://gitlab.com/lightning-signer/rust-lightning-signer/-/blob/master/lightning-signer-server/src/server/remotesigner.proto |
This'll take place at a higher level. With the current architecture, it just so happens that the The purpose of the lower level API was always to enable additional verification at a higher level. Check out this old lnd ML post on the roadmap we've been following here: https://groups.google.com/a/lightning.engineering/g/lnd/c/3rF65UxvDtM/m/ktDLAGtlAQAJ. |
I understand that you can have another grpc service with the same interface that acts as the remote signer. What I am wondering is what needs to be added to that interface in order to implement more advanced signing policies. For example an hourly limit on the total amount of all htlcs offered on a particular channel. I don't see this mentioned in the ML post. If I understand it correctly, you are suggesting to extend the Also from the lightning-signer project, this is an interesting list of potential policies: https://gitlab.com/lightning-signer/docs/-/blob/master/policy-controls.md Have you considered implementing the (outgoing) lightning-signer interface in lnd so that that remote signing service can be used as is? |
Yeah exactly. The policy logic needs to have essentially a mirrored view of the commitment state, this information can be passed over in the You may want to chat w/ the Voltage team, last I heard they're working on some draft code to start to implement policies in the way I've outlined above. The upside with the way
Last I checked their repo, they have an adapter for One difference with the lower level vs the higher level approach is that the higher level approach makes more assumptions w.r.t how the protocol looks today. For example see this call: |
Still, I wonder if the high-level approach with many different calls is genuinely different from lnd's low-level API with metadata in sign descriptors. Won't you end up packing the same data that lightning-signer has in function arguments into the metadata? It would be nice if at least some code is usable across implementations, but it seems that, unfortunately, the work that the lightning-signer team has done needs to be replicated in full based on |
IIRC, their high-level API was essentially a mirror of the main signing/wallet interface that LDK used internally, so I'd just chalk that up to path dependence, as that was the first implementation they worked on, and also where they initially received their funding.
It depends, maybe more data can be inferred as w/e hypothetical implementation by Voltage can use more of the existing
It's feasible that someone can just make an API bridge that takes our lower level messages, and annotates them properly for the |
With this PR, we started to define some custom PSBT tags, like the stuff needed to do the private key operations to send for revocation keys. Continuing down this line, an alternative path could be to use more custom tags to provide the extra annotation information. This can be passed via functional arguments to the main signing interface, or by having the caller set the additional new fields in the (I think we can move this convo to a new issue at this point?) |
Just a quick note after reading the above. We've been heads-down working on a beta release and also upstreaming changes to C-Lightning for integration. C-L is pretty close to LDK for signer architecture and API, so it was the low-hanging fruit. But we're definitely interested in moving the LND integration forward. I do have some concerns about the metadata approach. For one, I feel that approach is less "type safe", there seem to be more opportunities for breakage compared to an API that can be checked at compile-time. Another issue is that new calls are required for a validating signer. For example, the signer needs to see that the counterparty signed the current tx and revoked the old one, otherwise the state didn't really move forward. Providing these pieces of information requires new calls that are not actual signing operation. Also doesn't seem to fit the PSBT paradigm. About Finally, I want to mention that we are renaming the project to Validating Lightning Signer (VLS). |
Created new issue where we can continue the discussion: #6243 |
@devrandom replying here, but we can move to the issue afterwards
It would be no less type safe, Go is a typed language, as a protos. VLS uses protos already, and this would basically just be proto translation.
That's correct, from an implementation perspective, this could take the form of db action hooks, or ofc we can just shove everything into a fake signing operation ;). If you look at in from another perspective, with the way the protocol works, we can't actually sign again until the remote party revokes their commitment (we don't have the revocation point needed to make a new state otherwise). As a result, the existence of that next revocation point (which can be validated) may be sufficient to validate that a state transition actually happened.
Yep that's unavoidable, but in the |
Depends on btcsuite/btcwallet#781.This fixes/finishes the remote signing in that it makes it no longer required for the signing instance to have its own chain backend. Therefore all address synchronization issues are removed as well, the signing instance can now be completely offline (except for the incoming RPC connection).
Additionally, only the
signrpc
interface needs to be implemented by the remote signer.Fixes #5243
Fixes #5321
Fixes lightninglabs/loop#437