@@ -31,14 +31,6 @@ std::string GetAllOutputTypes()
31
31
return Join (ret, " , " );
32
32
}
33
33
34
- void RPCTypeCheckArgument (const UniValue& value, const UniValueType& typeExpected)
35
- {
36
- if (!typeExpected.typeAny && value.type () != typeExpected.type ) {
37
- throw JSONRPCError (RPC_TYPE_ERROR,
38
- strprintf (" JSON value of type %s is not of expected type %s" , uvTypeName (value.type ()), uvTypeName (typeExpected.type )));
39
- }
40
- }
41
-
42
34
void RPCTypeCheckObj (const UniValue& o,
43
35
const std::map<std::string, UniValueType>& typesExpected,
44
36
bool fAllowNull ,
@@ -564,8 +556,16 @@ UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const
564
556
if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs (request.params .size ())) {
565
557
throw std::runtime_error (ToString ());
566
558
}
559
+ UniValue arg_mismatch{UniValue::VOBJ};
567
560
for (size_t i{0 }; i < m_args.size (); ++i) {
568
- m_args.at (i).MatchesType (request.params [i]);
561
+ const auto & arg{m_args.at (i)};
562
+ UniValue match{arg.MatchesType (request.params [i])};
563
+ if (!match.isTrue ()) {
564
+ arg_mismatch.pushKV (strprintf (" Position %s (%s)" , i + 1 , arg.m_names ), std::move (match));
565
+ }
566
+ }
567
+ if (!arg_mismatch.empty ()) {
568
+ throw JSONRPCError (RPC_TYPE_ERROR, strprintf (" Wrong type passed:\n %s" , arg_mismatch.write (4 )));
569
569
}
570
570
UniValue ret = m_fun (*this , request);
571
571
if (gArgs .GetBoolArg (" -rpcdoccheck" , DEFAULT_RPC_DOC_CHECK)) {
@@ -684,42 +684,50 @@ UniValue RPCHelpMan::GetArgMap() const
684
684
return arr;
685
685
}
686
686
687
- void RPCArg::MatchesType ( const UniValue& request) const
687
+ static std::optional< UniValue::VType> ExpectedType (RPCArg::Type type)
688
688
{
689
- if (m_opts.skip_type_check ) return ;
690
- if (IsOptional () && request.isNull ()) return ;
691
- switch (m_type) {
689
+ using Type = RPCArg::Type;
690
+ switch (type) {
692
691
case Type::STR_HEX:
693
692
case Type::STR: {
694
- RPCTypeCheckArgument (request, UniValue::VSTR);
695
- return ;
693
+ return UniValue::VSTR;
696
694
}
697
695
case Type::NUM: {
698
- RPCTypeCheckArgument (request, UniValue::VNUM);
699
- return ;
696
+ return UniValue::VNUM;
700
697
}
701
698
case Type::AMOUNT: {
702
699
// VNUM or VSTR, checked inside AmountFromValue()
703
- return ;
700
+ return std::nullopt ;
704
701
}
705
702
case Type::RANGE: {
706
703
// VNUM or VARR, checked inside ParseRange()
707
- return ;
704
+ return std::nullopt ;
708
705
}
709
706
case Type::BOOL: {
710
- RPCTypeCheckArgument (request, UniValue::VBOOL);
711
- return ;
707
+ return UniValue::VBOOL;
712
708
}
713
709
case Type::OBJ:
714
710
case Type::OBJ_USER_KEYS: {
715
- RPCTypeCheckArgument (request, UniValue::VOBJ);
716
- return ;
711
+ return UniValue::VOBJ;
717
712
}
718
713
case Type::ARR: {
719
- RPCTypeCheckArgument (request, UniValue::VARR);
720
- return ;
714
+ return UniValue::VARR;
721
715
}
722
716
} // no default case, so the compiler can warn about missing cases
717
+ NONFATAL_UNREACHABLE ();
718
+ }
719
+
720
+ UniValue RPCArg::MatchesType (const UniValue& request) const
721
+ {
722
+ if (m_opts.skip_type_check ) return true ;
723
+ if (IsOptional () && request.isNull ()) return true ;
724
+ const auto exp_type{ExpectedType (m_type)};
725
+ if (!exp_type) return true ; // nothing to check
726
+
727
+ if (*exp_type != request.getType ()) {
728
+ return strprintf (" JSON value of type %s is not of expected type %s" , uvTypeName (request.getType ()), uvTypeName (*exp_type));
729
+ }
730
+ return true ;
723
731
}
724
732
725
733
std::string RPCArg::GetFirstName () const
@@ -902,7 +910,7 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
902
910
NONFATAL_UNREACHABLE ();
903
911
}
904
912
905
- static const std::optional<UniValue::VType> ExpectedType (RPCResult::Type type)
913
+ static std::optional<UniValue::VType> ExpectedType (RPCResult::Type type)
906
914
{
907
915
using Type = RPCResult::Type;
908
916
switch (type) {
0 commit comments