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
Modernize the RPC server. #337
Conversation
I'm still working on finishing the new rpc methods but I feel the rest of this code is mature enough now for others to check out. |
The old RPC code will be hard to review. Off the top of my head, here are the major changes made:
|
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` | ||
Create bool `long:"create" description:"Create the wallet if it does not exist"` | ||
CreateTemp bool `long:"createtemp" description:"Create a temporary simulation wallet (pass=password) in the data directory indicated; must call with --datadir"` | ||
DataDir string `short:"D" long:"datadir" description:"Directory to store wallets and transactions"` |
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.
Everything else in the suite uses -b
for the data directory. I think this should be consistent.
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.
Opened a new issue for this: #339
I like the grouping of the options in the source. It would be nice (not in this PR, but just an observation) to see if |
@@ -0,0 +1,9 @@ | |||
package legacyrpc | |||
|
|||
type Options struct { |
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.
Comments?
return &Server{wallet} | ||
} | ||
|
||
func (s *Server) Ping(cxt context.Context, req *pb.PingRequest) (*pb.PingResponse, error) { |
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.
Shouldn't all these cxt
be ctx
? First, ctx
matches the name used in api.pb.go
and second, context is almost always abbreviated as ctx
.
Almost all of |
@@ -165,6 +167,14 @@ type accountInfo struct { | |||
lastInternalAddr ManagedAddress | |||
} | |||
|
|||
type AccountProperties struct { |
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.
Exported type must be commented.
Commenting for myself to fix later: SynchronizeRPC does nothing if the rpc client is already set, so the connection logic elsewhere needs a way to replace this client after a disconnect. |
I am working on adding documentation to cover the new RPC server's API and developer documentation for making changes to the server. This is being done on another branch so I can preview the changes on GitHub without adding significant noise to this PR. https://github.com/jrick/btcwallet/tree/grpc_doco/rpc/documentation |
Here's a first pass at a spec for the new api: https://github.com/jrick/btcwallet/blob/grpc_doco/rpc/documentation/api.md It's all unstable for now, and stability can be gradually added as we see fit, but it should nonetheless be reviewed before going in the repo. I plan to include other documentation for client usage of the new API, and developer usage (making server/api changes) since both cases require some external tools for the grpc parts (except for Go clients, which could just import the btcwallet package, but that also must be documented). All other comments in the implementation package should be to help future me and other developers by explaining how something works, why it's done that way, marking TODOs, etc. Documentation for the API itself needs to be maintained in a language-agnostic document. |
How can we give feedback to this API? Here? |
@arnuschky comments are welcome here. The account number is the BIP0044 account, but assuming other BIP0043 purposes are added later and also use an account number, it could reference those as well. |
Regarding the timeline for this PR, I'd like to get this committed to master either today or tomorrow, with an open source release of a Windows GUI making use of this API be done by Friday. Remaining work:
|
While fixing up the new server implementation to match the API, some minor bugs (differences in behavior between the api spec and the implementation) were discovered that are still unfixed. These are commented with BUGS comments above the function. I plan on fixing these later after this is on master, since they require relatively large changes for a temporary, minor inconvenience. Or, since the api is unstable, I can make the spec match, and then change it to how it is right now later... but I don't think that gains us anything. |
As an update to my last comment, I don't feel this is ready yet for master without more review. I still want to release the source for the Windows GUI tomorrow, so installation instructions for that will have to point out this PR and branch. That GUI has been updated for the API changes I made after writing the API spec and is now working well under my limited testing. That being said, another round of review can begin now. I haven't yet gone through all of the new code and fixed all of the new TODOs, but everything else should be more or less ready. |
I've squashed all changes since the first review to make the next review a little easier, and history a little cleaner. |
I took another look into the SynchronizeRPC issue I noted above and it should not actually be a problem. The wallet is stopped after rpc client disconnect and the rpc client pointer is set to nil there, so after starting it back up SynchronizeRPC will work as intended. I very much dislike that code flow though and want to separate the wallet structures from the syncing code asap after this is in. |
@davecgh If you'd be ok with it, I'm considering disabling the new RPC server in this branch (making the legacy one the default again) to get this on master quicker but still keeping all of the new RPC code around (just not usable). I want new feature branches to be based off of this code, such as the separation of the syncing code. |
I'm ok with that. |
I've already started work on separating the websocket RPC syncing code from the wallet itself, and I am basing it off of this branch since it had already begun some of the work by moving the RPC client to the old RPC server's functions instead of using the wallet's. However, there's one snag I'm running into. The current wallet service in the new gRPC server only has access to the wallet. This is fine for all but one of the new RPCs: PublishTransaction. Thoughts on moving this function to a new service specifically for bitcoin network-related services vs adding the RPC (or later, SPV) client to the rpcserver.walletServer type? edit: will have to take the second option. PublishTransaction is also supposed to add the transaction to the wallet first before sending, if it is relevant, although this isn't done yet and is commented as a bug. |
0ace7ec
to
68a2334
Compare
This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
Since this isn't enabled by default and it's needed to unblock some other PRs, let's go ahead and merge this to master. Any further cleanup and issues can be hacked out then before it's enabled by default. |
This is a rather monolithic commit that moves the old RPC server to
its own package (rpc/legacyrpc), introduces a new RPC server using
gRPC (rpc/rpcserver), and provides the ability to defer wallet loading
until request at a later time by an RPC (--noinitialload).
The legacy RPC server remains the default for now while the new gRPC
server is not enabled by default. Enabling the new server requires
setting a listen address (--experimenalrpclisten). This experimental
flag is used to effectively feature gate the server until it is ready
to use as a default. Both RPC servers can be run at the same time,
but require binding to different listen addresses.
In theory, with the legacy RPC server now living in its own package it
should become much easier to unit test the handlers. This will be
useful for any future changes to the package, as compatibility with
Core's wallet is still desired.
Type safety has also been improved in the legacy RPC server. Multiple
handler types are now used for methods that do and do not require the
RPC client as a dependency. This can statically help prevent nil
pointer dereferences, and was very useful for catching bugs during
refactoring.
To synchronize the wallet loading process between the main package
(the default) and through the gRPC WalletLoader service (with the
--noinitialload option), as well as increasing the loose coupling of
packages, a new wallet.Loader type has been added. All creating and
loading of existing wallets is done through a single Loader instance,
and callbacks can be attached to the instance to run after the wallet
has been opened. This is how the legacy RPC server is associated with
a loaded wallet, even after the wallet is loaded by a gRPC method in a
completely unrelated package.
Documentation for the new RPC server has been added to the
rpc/documentation directory. The documentation includes a
specification for the new RPC API, addresses how to make changes to
the server implementation, and provides short example clients in
several different languages.
Some of the new RPC methods are not implementated exactly as described
by the specification. These are considered bugs with the
implementation, not the spec. Known bugs are commented as such.