diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 208c830aa..ef0c4a1be 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -66,7 +66,8 @@ Object JSONRPCError(int code, const string& message) } void RPCTypeCheck(const Array& params, - const list& typesExpected) + const list& typesExpected, + bool fAllowNull) { unsigned int i = 0; BOOST_FOREACH(Value_type t, typesExpected) @@ -74,8 +75,8 @@ void RPCTypeCheck(const Array& params, if (params.size() <= i) break; - const Value& v = params[i]; - if (v.type() != t) + const Value& v = params[i]; + if (!((v.type() == t) || (fAllowNull && (v.type() == null_type)))) { string err = strprintf("Expected type %s, got %s", Value_type_name[t], Value_type_name[v.type()]); @@ -86,14 +87,16 @@ void RPCTypeCheck(const Array& params, } void RPCTypeCheck(const Object& o, - const map& typesExpected) + const map& typesExpected, + bool fAllowNull) { BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) { const Value& v = find_value(o, t.first); - if (v.type() == null_type) + if (!fAllowNull && v.type() == null_type) throw JSONRPCError(-3, strprintf("Missing %s", t.first.c_str())); - if (v.type() != t.second) + + if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type)))) { string err = strprintf("Expected type %s for %s, got %s", Value_type_name[t.second], t.first.c_str(), Value_type_name[v.type()]); @@ -3040,8 +3043,10 @@ Object CallRPC(const string& strMethod, const Array& params) template -void ConvertTo(Value& value) +void ConvertTo(Value& value, bool fAllowNull=false) { + if (fAllowNull && value.type() == null_type) + return; if (value.type() == str_type) { // reinterpret string as unquoted json value @@ -3049,7 +3054,8 @@ void ConvertTo(Value& value) string strJSON = value.get_str(); if (!read_string(strJSON, value2)) throw runtime_error(string("Error parsing JSON:")+strJSON); - value = value2.get_value(); + ConvertTo(value2, fAllowNull); + value = value2; } else { @@ -3100,8 +3106,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector 1) ConvertTo(params[1]); if (strMethod == "createrawtransaction" && n > 0) ConvertTo(params[0]); if (strMethod == "createrawtransaction" && n > 1) ConvertTo(params[1]); - if (strMethod == "signrawtransaction" && n > 1) ConvertTo(params[1]); - if (strMethod == "signrawtransaction" && n > 2) ConvertTo(params[2]); + if (strMethod == "signrawtransaction" && n > 1) ConvertTo(params[1], true); + if (strMethod == "signrawtransaction" && n > 2) ConvertTo(params[2], true); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index b71d17ef2..40e7d7e11 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -28,13 +28,13 @@ json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vec Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); */ void RPCTypeCheck(const json_spirit::Array& params, - const std::list& typesExpected); + const std::list& typesExpected, bool fAllowNull=false); /* Check for expected keys/value types in an Object. Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type)); */ void RPCTypeCheck(const json_spirit::Object& o, - const std::map& typesExpected); + const std::map& typesExpected, bool fAllowNull=false); typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 56a49fd4d..b03745714 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -280,21 +280,18 @@ Value signrawtransaction(const Array& params, bool fHelp) throw runtime_error( "signrawtransaction [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [,...] [sighashtype=\"ALL\"]\n" "Sign inputs for raw transaction (serialized, hex-encoded).\n" - "Second optional argument is an array of previous transaction outputs that\n" + "Second optional argument (may be null) is an array of previous transaction outputs that\n" "this transaction depends on but may not yet be in the blockchain.\n" - "Third optional argument is an array of base58-encoded private\n" + "Third optional argument (may be null) is an array of base58-encoded private\n" "keys that, if given, will be the only keys used to sign the transaction.\n" - "Fourth option is a string that is one of six values; ALL, NONE, SINGLE or\n" + "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n" "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n" "Returns json object with keys:\n" " hex : raw transaction with signature(s) (hex-encoded string)\n" " complete : 1 if transaction has a complete set of signature (0 if not)" + HelpRequiringPassphrase()); - if (params.size() < 3) - EnsureWalletIsUnlocked(); - - RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)); + RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); vector txData(ParseHex(params[0].get_str())); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); @@ -343,7 +340,7 @@ Value signrawtransaction(const Array& params, bool fHelp) } // Add previous txouts given in the RPC call: - if (params.size() > 1) + if (params.size() > 1 && params[1].type() != null_type) { Array prevTxs = params[1].get_array(); BOOST_FOREACH(Value& p, prevTxs) @@ -390,7 +387,7 @@ Value signrawtransaction(const Array& params, bool fHelp) bool fGivenKeys = false; CBasicKeyStore tempKeystore; - if (params.size() > 2) + if (params.size() > 2 && params[2].type() != null_type) { fGivenKeys = true; Array keys = params[2].get_array(); @@ -407,10 +404,13 @@ Value signrawtransaction(const Array& params, bool fHelp) tempKeystore.AddKey(key); } } + else + EnsureWalletIsUnlocked(); + const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain); int nHashType = SIGHASH_ALL; - if (params.size() > 3) + if (params.size() > 3 && params[3].type() != null_type) { static map mapSigHashValues = boost::assign::map_list_of