@@ -31,14 +31,6 @@ std::string GetAllOutputTypes()
3131 return Join (ret, " , " );
3232}
3333
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-
4234void RPCTypeCheckObj (const UniValue& o,
4335 const std::map<std::string, UniValueType>& typesExpected,
4436 bool fAllowNull ,
@@ -564,8 +556,16 @@ UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const
564556 if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs (request.params .size ())) {
565557 throw std::runtime_error (ToString ());
566558 }
559+ UniValue arg_mismatch{UniValue::VOBJ};
567560 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 )));
569569 }
570570 UniValue ret = m_fun (*this , request);
571571 if (gArgs .GetBoolArg (" -rpcdoccheck" , DEFAULT_RPC_DOC_CHECK)) {
@@ -684,42 +684,50 @@ UniValue RPCHelpMan::GetArgMap() const
684684 return arr;
685685}
686686
687- void RPCArg::MatchesType ( const UniValue& request) const
687+ static std::optional< UniValue::VType> ExpectedType (RPCArg::Type type)
688688{
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) {
692691 case Type::STR_HEX:
693692 case Type::STR: {
694- RPCTypeCheckArgument (request, UniValue::VSTR);
695- return ;
693+ return UniValue::VSTR;
696694 }
697695 case Type::NUM: {
698- RPCTypeCheckArgument (request, UniValue::VNUM);
699- return ;
696+ return UniValue::VNUM;
700697 }
701698 case Type::AMOUNT: {
702699 // VNUM or VSTR, checked inside AmountFromValue()
703- return ;
700+ return std:: nullopt ;
704701 }
705702 case Type::RANGE: {
706703 // VNUM or VARR, checked inside ParseRange()
707- return ;
704+ return std:: nullopt ;
708705 }
709706 case Type::BOOL: {
710- RPCTypeCheckArgument (request, UniValue::VBOOL);
711- return ;
707+ return UniValue::VBOOL;
712708 }
713709 case Type::OBJ:
714710 case Type::OBJ_USER_KEYS: {
715- RPCTypeCheckArgument (request, UniValue::VOBJ);
716- return ;
711+ return UniValue::VOBJ;
717712 }
718713 case Type::ARR: {
719- RPCTypeCheckArgument (request, UniValue::VARR);
720- return ;
714+ return UniValue::VARR;
721715 }
722716 } // 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 ;
723731}
724732
725733std::string RPCArg::GetFirstName () const
@@ -902,7 +910,7 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
902910 NONFATAL_UNREACHABLE ();
903911}
904912
905- static const std::optional<UniValue::VType> ExpectedType (RPCResult::Type type)
913+ static std::optional<UniValue::VType> ExpectedType (RPCResult::Type type)
906914{
907915 using Type = RPCResult::Type;
908916 switch (type) {
0 commit comments