changeset 3336:14bdab76124c draft

Merge pull request #1690 from gavinandresen/signrawtx_null Allow signrawtransaction '...' null null 'hashtype'
author Gregory Maxwell <greg@xiph.org>
date Tue, 21 Aug 2012 06:40:50 -0700
parents bae61bc3d331 (current diff) 71d199d19f59 (diff)
children f25c04d61768
files src/bitcoinrpc.cpp
diffstat 3 files changed, 28 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -74,7 +74,8 @@
 }
 
 void RPCTypeCheck(const Array& params,
-                  const list<Value_type>& typesExpected)
+                  const list<Value_type>& typesExpected,
+                  bool fAllowNull)
 {
     unsigned int i = 0;
     BOOST_FOREACH(Value_type t, typesExpected)
@@ -82,8 +83,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()]);
@@ -94,14 +95,16 @@
 }
 
 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)
     {
         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()]);
@@ -2694,8 +2697,10 @@
 
 
 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)
     {
         // reinterpret string as unquoted json value
@@ -2703,7 +2708,8 @@
         string strJSON = value.get_str();
         if (!read_string(strJSON, value2))
             throw runtime_error(string("Error parsing JSON:")+strJSON);
-        value = value2.get_value<T>();
+        ConvertTo<T>(value2, fAllowNull);
+        value = value2;
     }
     else
     {
@@ -2754,8 +2760,8 @@
     if (strMethod == "getrawtransaction"      && n > 1) ConvertTo<boost::int64_t>(params[1]);
     if (strMethod == "createrawtransaction"   && n > 0) ConvertTo<Array>(params[0]);
     if (strMethod == "createrawtransaction"   && n > 1) ConvertTo<Object>(params[1]);
-    if (strMethod == "signrawtransaction"     && n > 1) ConvertTo<Array>(params[1]);
-    if (strMethod == "signrawtransaction"     && n > 2) ConvertTo<Array>(params[2]);
+    if (strMethod == "signrawtransaction"     && n > 1) ConvertTo<Array>(params[1], true);
+    if (strMethod == "signrawtransaction"     && n > 2) ConvertTo<Array>(params[2], true);
 
     return params;
 }
--- 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<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.
   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<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);
 
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -280,21 +280,18 @@
         throw runtime_error(
             "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [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<unsigned char> 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<string, int> mapSigHashValues =
             boost::assign::map_list_of