Conversation
|
Here's more goals of this change:
|
24654fc to
c6ecc35
Compare
|
Concept ACK I think this looks nicer btw: kallewoof@fe349cf |
|
@kallewoof thanks for taking a look! I'll wait for more concept acks before going forward. Regarding your suggestion to use |
|
Yeah, it may be confusing too. I do think we can afford to use one function that takes a null default, though. Overhead negligible. Gotcha on the concept ACKs. Edit: alternatively, Edit again: I dug some more, and it doesn't seem like the |
|
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. |
1a07390 to
871487c
Compare
|
Updated with IMO a better API. @ryanofsky care to take a look too? |
871487c to
a25df4d
Compare
|
@promag Nice. I can't figure out what was wrong with the old code. Care to explain? |
Before RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCLegacyMethodImpl fun)
: RPCHelpMan(std::move(name), std::move(description), std::move(args), std::move(results), std::move(examples), [&](const RPCContext& ctx) -> UniValue {
return fun(ctx.m_helpman, ctx.m_request);
})
{} |
|
Concept ACK. Would be nice if the default was already filled in by rpc help man. ;) |
|
@MarcoFalke yes, it was already suggested in #20017 (comment) but I think that can be done next. I also wonder if this should be an exhaustive change, at the moment I'm inclined to do it. |
|
The benefit of doing it in one step would be to avoid changing the same line of code twice |
01a1554 to
95453d7
Compare
|
See last commit @MarcoFalke. |
|
Rebased now that #21679 is merged. Not sure what is the best approach going forward, whether this should be an exhaustive change or not. I've included a commit to just change |
97bc6af to
f473a17
Compare
|
Concept ACK |
kallewoof
left a comment
There was a problem hiding this comment.
reACK f473a17740f57eaecd884b59333e6e44e1695286
|
reACK f473a17740f57eaecd884b59333e6e44e1695286 |
src/rpc/util.h
Outdated
There was a problem hiding this comment.
62047855691e1f1e07c99db259177b2fdb82cb2c: It looks like you are using this like a struct (without m_ prefix and scoped access ctx.request), so it could make sense to make it a struct. Also, with RPCHelpMan being renamed to RPCMethod (#19386 (comment)), it could make sese to name the variable appropriately:
| class RPCContext | |
| { | |
| public: | |
| const RPCHelpMan& helpman; | |
| const JSONRPCRequest& request; | |
| struct RPCContext { | |
| const RPCHelpMan& method; | |
| const JSONRPCRequest& request; |
src/rpc/util.h
Outdated
There was a problem hiding this comment.
I don't understand how any of this works. I removed this and everything compiled just fine:
diff --git a/src/rpc/util.h b/src/rpc/util.h
index f7a1acd1b5..1d5b7fc318 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -348,11 +348,6 @@ struct RPCParam
const RPCArg& m_arg;
const UniValue& m_value;
std::optional<T> m_defaults = {};
- RPCParam<T>& defaults(const T& defaults) {
- CHECK_NONFATAL(m_arg.m_fallback.index() != 2);
- m_defaults = defaults;
- return *this;
- }
T get() const {
if (!m_value.isNull()) return value(m_value);
if (m_defaults) return *m_defaults;I think it would make sense to split this into at least two commits:
- First one to introduce
RPCContext - Second one to introduce
RPCParam
Finally, would be nice to use clang-format on new code.
There was a problem hiding this comment.
https://github.com/bitcoin/bitcoin/pull/20017/files#r682710976
@MarcoFalke yup, not used in this branch.
There was a problem hiding this comment.
Then maybe remove the dead, (not even compiled) code?
There was a problem hiding this comment.
I’ll rebase and remove dead code.
f473a17 to
7a7b050
Compare
|
@MarcoFalke updated, I think fail is unrelated. |
|
Concept ACK |
| bool isNum() const { return value.isNum(); } | ||
| bool isStr() const { return value.isStr(); } | ||
| template <typename F> | ||
| void forEach(F fn) const { |
There was a problem hiding this comment.
Any reason not to use UpperCamelCase?
| } | ||
| } | ||
| private: | ||
| T convert(const UniValue& value) const; |
There was a problem hiding this comment.
Parameter name shadows member variable. Shouldn't this method be static anyway?
| T get() const { | ||
| if (!value.isNull()) return convert(value); | ||
| // if (m_defaults) return *m_defaults; | ||
| CHECK_NONFATAL(arg.m_fallback.index() == 2); |
There was a problem hiding this comment.
CHECK_NONFATAL(std::holds_alternative<Default>(arg.m_fallback)) ?
| const std::vector<RPCArg> m_args; | ||
| const RPCResults m_results; | ||
| const RPCExamples m_examples; | ||
| friend struct RPCContext; |
There was a problem hiding this comment.
Rather than having a friend accessing this class's privates directly, why not have RPCHelpMan be able to create a parameter directly and just call that from RPCContext:
class RPCHelpMan
{
...
template <typename T>
RPCParam<T> GetParam(size_t index, const JSONRPCRequest& request) const
{
return {m_args[index], request.params[index]};
}
...
};
class RPCContext
{
...
template <typename T=UniValue>
RPCParam<T> param(size_t index) const
{
return method.GetParam<T>(index, request);
}
};| template <typename T=UniValue> | ||
| RPCParam<T> param(size_t index) const | ||
| { | ||
| return {method.m_args[index], request.params[index]}; |
There was a problem hiding this comment.
CHECK_NONFATAL(index < m_args.size()); ?
There was a problem hiding this comment.
When constructing an RPCParam<T> wouldn't it be worth checking that T aligns with method.m_args[index].m_type along similar lines to RPCResult::MatchesType ?
| auto param(size_t index, F fn) const -> decltype(fn(UniValue{})) | ||
| { | ||
| return fn(request.params[index]); | ||
| } |
There was a problem hiding this comment.
Why would you call ctx.param(i, fn) instead of fn(ctx.param(i)) -- ctx.param(i) defaults to being UniValue and automatically converts to UniValue, no?
| const RPCArg& arg; | ||
| const UniValue& value; | ||
| T get() const { | ||
| if (!value.isNull()) return convert(value); |
There was a problem hiding this comment.
if constexpr (std::is_same_v<T, UniValue>()) return convert(value);would allow you to get a VNULL value out cleanly if you're treating the param as UniValue
|
🐙 This pull request conflicts with the target branch and needs rebase. Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft". |
|
Are you still working on this? |
|
I took the concept from here (Thanks!), but implemented it differently (in just three lines of code in the header file). See #28230 |
This change allows to do
[&](const RPCContext& ctx) -> UniValueinstead of
So
RPCContexttiesRPCHelpManandJSONRPCRequest. Thenctxis used to get actual parameter values. For instance, before:and now
Not that the default value defined in the RPC spec is used.
It is also possible to iterate an array parameter:
std::set<std::string> stats; ctx.param(1).forEach([&](const UniValue& stat) { stats.insert(stat.get_str()); });Or even do custom parameter handling: