-
Notifications
You must be signed in to change notification settings - Fork 37.7k
rpc: remove g_rpc_node & g_rpc_chain #18647
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
Conversation
Concept ACK on fixing #17548 Thanks for tackling this issue! |
Few thoughts:
|
#18531 Doesn't change how RPC methods are dispatched, but it wraps them into an RPCMan. Assuming my pull makes it in first, it is going to reduce the diff of this pull significantly. Though, when |
Hi @ryanofsky, and many thanks!
Didn't know about that. Could not find anything in the original issue. Anyway, thanks for pointing this out!
I never wanted to get rid of it, only make it:
And yes, there are still a few places where we still need g_rpc_node, but those aren't directly related to this PR, so I deliberately didn't change them. --EDIT: My sentence "never wanted to get rid of it" might have been misleading. Actually, I want to get rid of it as a global, but wanted to keep the NodeContext itself available to all RPC methods by forwarding it to Actors, of course. --EDIT 2: Now the g_rpc_node is completely gone.
Ok. --EDIT: Was changed and force-pushed.
Ok. Will check it again. --EDIT: Have checked it. Sadly, not possible because copy assignment operator of NodeContext is implicitly deleted. So, will keep it a pointer there, and the check, unless someone comes with a better idea. Any inputs that help me get rid of raw pointers are highly welcome :)
I didn't know about his. I thought it's the right place to put the context in, because those methods are being executed within a NodeContext. It's like "self" variable in python, for example. It's simply there, be it used or not, because at no point in time is an RPC method being used outside NodeContext. But I might be mistaken.
Again, why should a passive object, like a request, know anything about the environment that's using it? Why not create some kind of MetaContext that holds both Node- and WalletContext and forwards it directly to actors? This way one could easily extend contexts, if there might be a need to do so in future (I'm only speculating here) --EDIT: Another option would be to create a MetaContext that's based on aliasing shared_ptr. Something like this: struct MetaContext {
NodeContext node;
WalletContext wallet;
}; We then initialize the meta-context first: auto meta_ctx = std::shared_ptr<MetaContext>(new MetaContext()); Now, when we want to forward the "correct" context to a particular actor, we would do this: auto subctx_node = std::shared_ptr<NodeContext>(meta_ctx, &meta_ctx->node); For functions that should only deal with Wallet, we then go this way: auto subctx_wallet = std::shared_ptr<WalletContext>(meta_ctx, &meta_ctx->wallet); With this strategy we could put any number of different contexts in the same place, but only reveal those that are of use to functions which will consume them.
I see it like the "self" or "this" pointers. They're always there, regardless of usage. "Some" context is always there. Anyway, thanks again! |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
I don't think the the const part is good. RPC methods can start/stop the node, initiate connections, load wallets, so I don't think they should be prevented from changing all context members that exist now and all new context members we may add in the future.
This seems good. Maybe list it as a benefit in PR description. If you think of examples where it could help practically, those are good to mention too.
Maybe my suggestion here and in #17548 wasn't clear, but I'm not saying add a NodeContext member to JSONRPCRequest. I'm saying add a generic context member so it can be a vehicle for information about the environment without knowing about the environment, the same way it is vehicle for params without knowing about the meaning of params |
Well, then I think we should have different variants of contexts at our disposal. Maybe something similar to the example with aliasing shared_ptrs (in the EDIT-ed part of my previous posting). Read-only contexts, writeable ones etc.
Thanks for pointing this out. I will update the PR description.
I would not extend JSONRPCRequest in any way. It should be a message carrier in the purest KISS sense. |
It would be good to elaborate on the problem being solved in the PR description. It seems to have something to do with data data hiding, but specifics are unclear. I think the goal of #17548 is remove the global variable, though, so I wouldn't say this fixes that issue, even though it could help |
Yes, of course. I am very glad that my PR found much attention within such a short time frame. The learning process I went through while thinking about "this damn global NodeContext and how to make it less exposed" is already a win for me. We will surely find a way. |
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.
Instead of changing all RPC handlers I think you could override CRPCCommand
constructor to take
a UniValue (*rpcfn_type)(const JSONRPCRequest& jsonRequest)
. The same approach can be done in Marco PR, RPCMan
can take different method signatures.
Yes, this approach would be less invasive. Maybe I could rebase after Marco's PR gets merged? |
I really appreciate the effort here, but I don't think this PR is teneble, and I have a simpler alternative in #18740. This PR is too wide in scope changing things that don't need to be changed, and is accessing node context in places that will make changes we do want more difficult. Specifically this PR is:
It was good to see this PR opened and have progress on #17548, and be useful as an experiment, but I think this is not the best way forward and would recommend not doing more work on this PR |
Hi @ryanofsky
Simpler is very often better!
This indeed is the case, but mostly because g_rpc_node, and later g_rpc_chain, were basically "everywhere". This of course should not serve as an excuse to write an even bigger "solution" for the original problem.
As I don't know much about libevent, I will simply agree on that.
The NodeContext structure is actually even bigger. It contains various things, so you are right. But also: maybe NodeContext itself should be split into smaller parts? To me, it looks like NodeContext carries many heavy things. I actually never needed NodeContext as a whole but merely a pointer/ref to one of its members. However, this is not important here, imo, so I'll leave it for another discussion.
Yes, it's not the cutest thing to do, but a bit less ugly than a global pointer. And as I said, I never needed NodeContext itself, only a pointer/ref from it.
To understand why g_rpc_node is everywhere and how to deal with it correctly, was hard to me. :) Later then, g_rpc_chain came to the party.
As I still lack enough knowledge about these areas, I can only agree with you.
Ok.
I was actually checking for nullptr at the very beginning of the initialization. But, this is not important here, so the code as it is, is not stable enough. Accepted.
I use clang format as stated in Bitcoin docs. git diff -U0 HEAD~1.. | ./contrib/devtools/clang-format-diff.py -p1 -i -v Regarding const/non-costs: it was because the NodeContext has an implicitly deleted copy assignment constructor, because one of its members is a unique_ptr. So, I had to find a way around this impasse. This too is one of the things that make me believe, that NodeContext itself should be split into smaller parts. But, this is not that important here, I think.
I would like to know more about the bitcoinic coding style. If you have any doc/link please, let me know. I could not find anything.
NodeContext should maybe be made even smaller, imo. So, yes, I agree with you.
Yes, that was the initial motivation. The original issue #17548 was hanging around for some time, so I thought, let's do something about it.
In my opinion, it was the best way to forward for me, as it helped me a lot to understand some interesting parts of Bitcoin. And I thank you for that! However, you are right, it's not the best way to forward for the project, so I will close my PR, and will study your code and try it out. Thanks again! |
b3f7f37 refactor: Remove g_rpc_node global (Russell Yanofsky) ccb5059 scripted-diff: Remove g_rpc_node references (Russell Yanofsky) 6fca33b refactor: Pass NodeContext to RPC and REST methods through util::Ref (Russell Yanofsky) 691c817 Add util::Ref class as temporary alternative for c++17 std::any (Russell Yanofsky) Pull request description: This PR removes the `g_rpc_node` global, to get same benefits we see removing other globals and make RPC code more testable, modular, and reusable. This uses a hybrid of the approaches suggested in #17548. Instead of using `std::any`, which isn't available in c++11, or `void*`, which isn't type safe, it uses a small new `util::Ref` helper class, which acts like a simplified `std::any` that only holds references, not values. Motivation for writing this was to provide an simpler alternative to #18647 by Harris Brakmić (brakmic) which avoids some shortcomings of that PR (#18647 (comment)) ACKs for top commit: MarcoFalke: re-ACK b3f7f37, only change is adding back const and more tests 🚾 ajtowns: ACK b3f7f37 Tree-SHA512: 56292268a001bdbe34d641db1180c215351503966ff451e55cc96c9137f1d262225d7d7733de9c9da7ce7d7a4b34213a98c2476266b58c89dbbb0f3cb5aa5d70
b3f7f37 refactor: Remove g_rpc_node global (Russell Yanofsky) ccb5059 scripted-diff: Remove g_rpc_node references (Russell Yanofsky) 6fca33b refactor: Pass NodeContext to RPC and REST methods through util::Ref (Russell Yanofsky) 691c817 Add util::Ref class as temporary alternative for c++17 std::any (Russell Yanofsky) Pull request description: This PR removes the `g_rpc_node` global, to get same benefits we see removing other globals and make RPC code more testable, modular, and reusable. This uses a hybrid of the approaches suggested in bitcoin#17548. Instead of using `std::any`, which isn't available in c++11, or `void*`, which isn't type safe, it uses a small new `util::Ref` helper class, which acts like a simplified `std::any` that only holds references, not values. Motivation for writing this was to provide an simpler alternative to bitcoin#18647 by Harris Brakmić (brakmic) which avoids some shortcomings of that PR (bitcoin#18647 (comment)) ACKs for top commit: MarcoFalke: re-ACK b3f7f37, only change is adding back const and more tests 🚾 ajtowns: ACK b3f7f37 Tree-SHA512: 56292268a001bdbe34d641db1180c215351503966ff451e55cc96c9137f1d262225d7d7733de9c9da7ce7d7a4b34213a98c2476266b58c89dbbb0f3cb5aa5d70
This PR removes the global g_rpc_node and g_rpc_chain pointers from RPC functions and other sources & headers. Instead, a NodeContext const reference, and in some cases a NodeContext pointer, is being forwarded to respective actor callbacks.
Also, this way we avoid changing the JSONRPCRequest that, imo, should remain a plain message transfer object without any knowledge about its environment. I consider the idea of having a void pointer member of JSONRPCRequest problematic because it defeats the compiler type checking. In a way, a globally available, but at least typed, pointer would still be better than a void pointer, in my opinion.
Previously, an RPC function signature looked like this:
This PR changes it to this:
For example, a function that previously used g_rpc_node like this:
would get the same object this way:
The same applies to former g_rpc_chain where functions like loadwallet don't need it anymore:
LoadWallet(*node.chain, location, error, warning);
This all is made possible by taking the NodeContext into the tableRPC object at init:
Each time an RPC is being called, tableRPC will forward the NodeContext argument:
Fixes #17548