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.
This commit is contained in:
Gavin Andresen 2012-08-20 16:18:17 -04:00
parent b86da2abe8
commit cc6dfd1f4b
3 changed files with 28 additions and 22 deletions

View file

@ -66,7 +66,8 @@ Object JSONRPCError(int code, const string& message)
} }
void RPCTypeCheck(const Array& params, void RPCTypeCheck(const Array& params,
const list<Value_type>& typesExpected) const list<Value_type>& typesExpected,
bool fAllowNull)
{ {
unsigned int i = 0; unsigned int i = 0;
BOOST_FOREACH(Value_type t, typesExpected) BOOST_FOREACH(Value_type t, typesExpected)
@ -74,8 +75,8 @@ void RPCTypeCheck(const Array& params,
if (params.size() <= i) if (params.size() <= i)
break; break;
const Value& v = params[i]; const Value& v = params[i];
if (v.type() != t) if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
{ {
string err = strprintf("Expected type %s, got %s", string err = strprintf("Expected type %s, got %s",
Value_type_name[t], Value_type_name[v.type()]); Value_type_name[t], Value_type_name[v.type()]);
@ -86,14 +87,16 @@ void RPCTypeCheck(const Array& params,
} }
void RPCTypeCheck(const Object& o, void RPCTypeCheck(const Object& o,
const map<string, Value_type>& typesExpected) const map<string, Value_type>& typesExpected,
bool fAllowNull)
{ {
BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
{ {
const Value& v = find_value(o, t.first); 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())); 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", string err = strprintf("Expected type %s for %s, got %s",
Value_type_name[t.second], t.first.c_str(), Value_type_name[v.type()]); 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<typename T> template<typename T>
void ConvertTo(Value& value) void ConvertTo(Value& value, bool fAllowNull=false)
{ {
if (fAllowNull && value.type() == null_type)
return;
if (value.type() == str_type) if (value.type() == str_type)
{ {
// reinterpret string as unquoted json value // reinterpret string as unquoted json value
@ -3049,7 +3054,8 @@ void ConvertTo(Value& value)
string strJSON = value.get_str(); string strJSON = value.get_str();
if (!read_string(strJSON, value2)) if (!read_string(strJSON, value2))
throw runtime_error(string("Error parsing JSON:")+strJSON); throw runtime_error(string("Error parsing JSON:")+strJSON);
value = value2.get_value<T>(); ConvertTo<T>(value2, fAllowNull);
value = value2;
} }
else else
{ {
@ -3100,8 +3106,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "getrawtransaction" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]); if (strMethod == "createrawtransaction" && n > 0) ConvertTo<Array>(params[0]);
if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]); if (strMethod == "createrawtransaction" && n > 1) ConvertTo<Object>(params[1]);
if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1]); if (strMethod == "signrawtransaction" && n > 1) ConvertTo<Array>(params[1], true);
if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2]); if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
return params; return params;
} }

View file

@ -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)); Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type));
*/ */
void RPCTypeCheck(const json_spirit::Array& params, void RPCTypeCheck(const json_spirit::Array& params,
const std::list<json_spirit::Value_type>& typesExpected); const std::list<json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
/* /*
Check for expected keys/value types in an Object. Check for expected keys/value types in an Object.
Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type)); Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type));
*/ */
void RPCTypeCheck(const json_spirit::Object& o, void RPCTypeCheck(const json_spirit::Object& o,
const std::map<std::string, json_spirit::Value_type>& typesExpected); const std::map<std::string, json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp); typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp);

View file

@ -280,21 +280,18 @@ Value signrawtransaction(const Array& params, bool fHelp)
throw runtime_error( throw runtime_error(
"signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n" "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
"Sign inputs for raw transaction (serialized, hex-encoded).\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" "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" "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" "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
"Returns json object with keys:\n" "Returns json object with keys:\n"
" hex : raw transaction with signature(s) (hex-encoded string)\n" " hex : raw transaction with signature(s) (hex-encoded string)\n"
" complete : 1 if transaction has a complete set of signature (0 if not)" " complete : 1 if transaction has a complete set of signature (0 if not)"
+ HelpRequiringPassphrase()); + HelpRequiringPassphrase());
if (params.size() < 3) RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
EnsureWalletIsUnlocked();
RPCTypeCheck(params, list_of(str_type)(array_type)(array_type));
vector<unsigned char> txData(ParseHex(params[0].get_str())); vector<unsigned char> txData(ParseHex(params[0].get_str()));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); 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: // 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(); Array prevTxs = params[1].get_array();
BOOST_FOREACH(Value& p, prevTxs) BOOST_FOREACH(Value& p, prevTxs)
@ -390,7 +387,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGivenKeys = false; bool fGivenKeys = false;
CBasicKeyStore tempKeystore; CBasicKeyStore tempKeystore;
if (params.size() > 2) if (params.size() > 2 && params[2].type() != null_type)
{ {
fGivenKeys = true; fGivenKeys = true;
Array keys = params[2].get_array(); Array keys = params[2].get_array();
@ -407,10 +404,13 @@ Value signrawtransaction(const Array& params, bool fHelp)
tempKeystore.AddKey(key); tempKeystore.AddKey(key);
} }
} }
else
EnsureWalletIsUnlocked();
const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain); const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
int nHashType = SIGHASH_ALL; int nHashType = SIGHASH_ALL;
if (params.size() > 3) if (params.size() > 3 && params[3].type() != null_type)
{ {
static map<string, int> mapSigHashValues = static map<string, int> mapSigHashValues =
boost::assign::map_list_of boost::assign::map_list_of