# HG changeset patch # User Gavin Andresen # Date 1345493897 14400 # Node ID 71d199d19f59ac10c6a8329c6b4ead25f92e4e31 # Parent 0481be91a53cf3ce545e31897eb4d6dd7fa394a3 Allow signrawtransaction '...' null null 'hashtype' Allows the user to pass null as the second or third parameter to signrawtransaction, in case you need to (for example) fetch private keys from the wallet but want to specify the hash type. diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -66,7 +66,8 @@ } 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 @@ 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 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 @@ 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 @@ 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 @@ if (strMethod == "getrawtransaction" && n > 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 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -28,13 +28,13 @@ 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 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -280,21 +280,18 @@ 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 @@ } // 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 @@ 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 @@ 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