Paste: RPCv1

Author: Luke-Jr
Mode: patch
Date: Mon, 21 Feb 2011 00:11:24
Plain Text |
diff --git a/init.cpp b/init.cpp
index 04bdd68..ec843d8 100644
--- a/init.cpp
+++ b/init.cpp
@@ -185,6 +185,7 @@ bool AppInit2(int argc, char* argv[])
             "  -rpcport=<port>  \t\t  " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") +
             "  -rpcallowip=<ip> \t\t  " + _("Allow JSON-RPC connections from specified IP address\n") +
             "  -rpcconnect=<ip> \t  "   + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") +
+            "  -rpcversion=<n>  \t  "   + _("Send commands in RPC version <n>, default 0 (for now)\n") +
             "  -keypool=<n>     \t  "   + _("Set key pool size to <n> (default: 100)\n") +
             "  -rescan          \t  "   + _("Rescan the block chain for missing wallet transactions\n");
 
diff --git a/json/json_spirit_value.h b/json/json_spirit_value.h
index 7e83a2a..89be790 100644
--- a/json/json_spirit_value.h
+++ b/json/json_spirit_value.h
@@ -59,6 +59,8 @@ namespace json_spirit
 
         bool is_uint64() const;
         bool is_null() const;
+        bool is_amount() const;
+        void set_amount(bool);
 
         const String_type& get_str()    const;
         const Object&      get_obj()    const;
@@ -88,6 +90,7 @@ namespace json_spirit
         Value_type type_;
         Variant v_;
         bool is_uint64_;
+        bool is_amount_;
     };
 
     // vector objects
@@ -211,6 +214,7 @@ namespace json_spirit
     template< class Config >
     Value_impl< Config >::Value_impl()
     :   type_( null_type )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -219,6 +223,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Const_str_ptr value )
     :   type_( str_type )
     ,   v_( String_type( value ) )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -227,6 +232,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const String_type& value )
     :   type_( str_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -235,6 +241,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Object& value )
     :   type_( obj_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -243,6 +250,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Array& value )
     :   type_( array_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -251,6 +259,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( bool value )
     :   type_( bool_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -259,6 +268,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( int value )
     :   type_( int_type )
     ,   v_( static_cast< boost::int64_t >( value ) )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -267,6 +277,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( boost::int64_t value )
     :   type_( int_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -275,6 +286,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( boost::uint64_t value )
     :   type_( int_type )
     ,   v_( static_cast< boost::int64_t >( value ) )
+    ,   is_amount_( false )
     ,   is_uint64_( true )
     {
     }
@@ -283,6 +295,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( double value )
     :   type_( real_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -291,6 +304,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Value_impl< Config >& other )
     :   type_( other.type() )
     ,   v_( other.v_ )
+    ,   is_amount_( other.is_amount_ )
     ,   is_uint64_( other.is_uint64_ )
     {
     }
@@ -303,6 +317,7 @@ namespace json_spirit
         std::swap( type_, tmp.type_ );
         std::swap( v_, tmp.v_ );
         std::swap( is_uint64_, tmp.is_uint64_ );
+        std::swap( is_amount_, tmp.is_amount_ );
 
         return *this;
     }
@@ -330,6 +345,18 @@ namespace json_spirit
     }
 
     template< class Config >
+    bool Value_impl< Config >::is_amount() const
+    {
+        return is_amount_;
+    }
+
+    template< class Config >
+    void Value_impl< Config >::set_amount(bool nv)
+    {
+        is_amount_ = nv;
+    }
+
+    template< class Config >
     bool Value_impl< Config >::is_null() const
     {
         return type() == null_type;
@@ -392,6 +419,11 @@ namespace json_spirit
     template< class Config >
     boost::int64_t Value_impl< Config >::get_int64() const
     {
+        if( type() == real_type )
+        {
+            return static_cast< boost::int64_t >( get_real() );
+        }
+
         check_type(  int_type );
 
         return boost::get< boost::int64_t >( v_ );
diff --git a/json/json_spirit_writer_template.h b/json/json_spirit_writer_template.h
index 28c49dd..98910a6 100644
--- a/json/json_spirit_writer_template.h
+++ b/json/json_spirit_writer_template.h
@@ -161,6 +161,8 @@ namespace json_spirit
             {
                os_ << value.get_int64();
             }
+            if (value.is_amount())
+               os_ << ".0";
         }
 
         void output( const String_type& s )
diff --git a/main.cpp b/main.cpp
index a47f3a9..cbbe795 100644
--- a/main.cpp
+++ b/main.cpp
@@ -3750,16 +3750,16 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
             int64 n = pcoin->GetCredit();
             if (n <= 0)
                 continue;
-            if (n < nTargetValue)
-            {
-                vValue.push_back(make_pair(n, pcoin));
-                nTotalLower += n;
-            }
-            else if (n == nTargetValue)
+            if (n == nTargetValue)
             {
                 setCoinsRet.insert(pcoin);
                 return true;
             }
+            else if (n < nTargetValue + CENT)
+            {
+                vValue.push_back(make_pair(n, pcoin));
+                nTotalLower += n;
+            }
             else if (n < nLowestLarger)
             {
                 nLowestLarger = n;
@@ -3768,7 +3768,14 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
         }
     }
 
-    if (nTotalLower < nTargetValue)
+    if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
+    {
+        for (int i = 0; i < vValue.size(); ++i)
+            setCoinsRet.insert(vValue[i].second);
+        return true;
+    }
+
+    if (nTotalLower < nTargetValue + (pcoinLowestLarger ? CENT : 0))
     {
         if (pcoinLowestLarger == NULL)
             return false;
@@ -3776,6 +3783,9 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
         return true;
     }
 
+    if (nTotalLower >= nTargetValue + CENT)
+        nTargetValue += CENT;
+
     // Solve subset sum by stochastic approximation
     sort(vValue.rbegin(), vValue.rend());
     vector<char> vfIncluded;
diff --git a/rpc.cpp b/rpc.cpp
index 69b09bc..21a098e 100644
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -2,6 +2,8 @@
 // Distributed under the MIT/X11 software license, see the accompanying
 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
 
+#include <string.h>
+
 #include "headers.h"
 #include "cryptopp/sha.h"
 #undef printf
@@ -12,6 +14,7 @@
 #include <boost/asio/ssl.hpp> 
 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
 #endif
+#include <boost/lexical_cast.hpp>
 #include "json/json_spirit_reader_template.h"
 #include "json/json_spirit_writer_template.h"
 #include "json/json_spirit_utils.h"
@@ -25,7 +28,7 @@ using namespace boost::asio;
 using namespace json_spirit;
 
 void ThreadRPCServer2(void* parg);
-typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
+typedef Value(*rpcfn_type)(int, const Array& params, bool fHelp);
 extern map<string, rpcfn_type> mapCallTable;
 
 
@@ -60,20 +63,41 @@ void PrintConsole(const char* format, ...)
 }
 
 
-int64 AmountFromValue(const Value& value)
+int64 AmountFromValue(int ver, const Value& value)
 {
+    int64 nAmount;
+    if (!ver) {
     double dAmount = value.get_real();
     if (dAmount <= 0.0 || dAmount > 21000000.0)
         throw JSONRPCError(-3, "Invalid amount");
-    int64 nAmount = roundint64(dAmount * 100.00) * CENT;
+        nAmount = roundint64(dAmount * 100.00) * CENT;
+    }
+    else
+        nAmount = value.get_int64();
     if (!MoneyRange(nAmount))
         throw JSONRPCError(-3, "Invalid amount");
     return nAmount;
 }
 
+Value ValueFromAmount(int ver, int64 amount)
+{
+    if (!ver)
+        return (double)amount / (double)COIN;
+    Value rv((boost::int64_t)amount);
+    rv.set_amount(true);
+    return rv;
+}
+
+__deprecated__
+int64 AmountFromValue(const Value& value)
+{
+    return AmountFromValue(0, value);
+}
+
+__deprecated__
 Value ValueFromAmount(int64 amount)
 {
-    return (double)amount / (double)COIN;
+    return ValueFromAmount(0, amount);
 }
 
 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
@@ -100,7 +124,7 @@ string AccountFromValue(const Value& value)
 ///
 
 
-Value help(const Array& params, bool fHelp)
+Value help(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -128,7 +152,7 @@ Value help(const Array& params, bool fHelp)
             Array params;
             rpcfn_type pfn = (*mi).second;
             if (setDone.insert(pfn).second)
-                (*pfn)(params, true);
+                (*pfn)(ver, params, true);
         }
         catch (std::exception& e)
         {
@@ -147,7 +171,7 @@ Value help(const Array& params, bool fHelp)
 }
 
 
-Value stop(const Array& params, bool fHelp)
+Value stop(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -160,7 +184,7 @@ Value stop(const Array& params, bool fHelp)
 }
 
 
-Value getblockcount(const Array& params, bool fHelp)
+Value getblockcount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -171,7 +195,7 @@ Value getblockcount(const Array& params, bool fHelp)
 }
 
 
-Value getblocknumber(const Array& params, bool fHelp)
+Value getblocknumber(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -182,7 +206,7 @@ Value getblocknumber(const Array& params, bool fHelp)
 }
 
 
-Value getconnectioncount(const Array& params, bool fHelp)
+Value getconnectioncount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -205,7 +229,7 @@ double GetDifficulty()
     return dMinimum / dCurrently;
 }
 
-Value getdifficulty(const Array& params, bool fHelp)
+Value getdifficulty(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -216,7 +240,7 @@ Value getdifficulty(const Array& params, bool fHelp)
 }
 
 
-Value getgenerate(const Array& params, bool fHelp)
+Value getgenerate(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -227,7 +251,7 @@ Value getgenerate(const Array& params, bool fHelp)
 }
 
 
-Value setgenerate(const Array& params, bool fHelp)
+Value setgenerate(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -255,7 +279,7 @@ Value setgenerate(const Array& params, bool fHelp)
 }
 
 
-Value gethashespersec(const Array& params, bool fHelp)
+Value gethashespersec(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -268,7 +292,7 @@ Value gethashespersec(const Array& params, bool fHelp)
 }
 
 
-Value getinfo(const Array& params, bool fHelp)
+Value getinfo(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -277,23 +301,24 @@ Value getinfo(const Array& params, bool fHelp)
 
     Object obj;
     obj.push_back(Pair("version",       (int)VERSION));
-    obj.push_back(Pair("balance",       (double)GetBalance() / (double)COIN));
+    obj.push_back(Pair("rpcversion",    (int)ver));
+    obj.push_back(Pair("balance",       ValueFromAmount(ver, GetBalance())));
+    obj.push_back(Pair("paytxfee",      ValueFromAmount(ver, nTransactionFee)));
     obj.push_back(Pair("blocks",        (int)nBestHeight));
     obj.push_back(Pair("connections",   (int)vNodes.size()));
     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
-    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
+    obj.push_back(Pair("hashespersec",  gethashespersec(ver, params, false)));
     obj.push_back(Pair("testnet",       fTestNet));
     obj.push_back(Pair("keypoololdest", (boost::int64_t)GetOldestKeyPoolTime()));
-    obj.push_back(Pair("paytxfee",      (double)nTransactionFee / (double)COIN));
     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
     return obj;
 }
 
 
-Value getnewaddress(const Array& params, bool fHelp)
+Value getnewaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -358,7 +383,7 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
     return strAddress;
 }
 
-Value getaccountaddress(const Array& params, bool fHelp)
+Value getaccountaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -373,7 +398,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
 
 
 
-Value setaccount(const Array& params, bool fHelp)
+Value setaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -401,7 +426,7 @@ Value setaccount(const Array& params, bool fHelp)
 }
 
 
-Value getaccount(const Array& params, bool fHelp)
+Value getaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -421,7 +446,7 @@ Value getaccount(const Array& params, bool fHelp)
 }
 
 
-Value getaddressesbyaccount(const Array& params, bool fHelp)
+Value getaddressesbyaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -450,7 +475,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
     return ret;
 }
 
-Value sendtoaddress(const Array& params, bool fHelp)
+Value sendtoaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 2 || params.size() > 4)
         throw runtime_error(
@@ -460,7 +485,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
     string strAddress = params[0].get_str();
 
     // Amount
-    int64 nAmount = AmountFromValue(params[1]);
+    int64 nAmount = AmountFromValue(ver, params[1]);
 
     // Wallet comments
     CWalletTx wtx;
@@ -476,7 +501,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
 }
 
 
-Value getreceivedbyaddress(const Array& params, bool fHelp)
+Value getreceivedbyaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -513,7 +538,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
         }
     }
 
-    return (double)nAmount / (double)COIN;
+    return ValueFromAmount(ver, nAmount);
 }
 
 
@@ -538,7 +563,7 @@ void GetAccountPubKeys(string strAccount, set<CScript>& setPubKey)
 }
 
 
-Value getreceivedbyaccount(const Array& params, bool fHelp)
+Value getreceivedbyaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -572,7 +597,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
         }
     }
 
-    return (double)nAmount / (double)COIN;
+    return ValueFromAmount(ver, nAmount);
 }
 
 
@@ -610,7 +635,7 @@ int64 GetAccountBalance(const string& strAccount, int nMinDepth)
 }
 
 
-Value getbalance(const Array& params, bool fHelp)
+Value getbalance(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 0 || params.size() > 2)
         throw runtime_error(
@@ -618,8 +643,9 @@ Value getbalance(const Array& params, bool fHelp)
             "If [account] is not specified, returns the server's total available balance.\n"
             "If [account] is specified, returns the balance in the account.");
 
-    if (params.size() == 0)
-        return ((double)GetBalance() / (double)COIN);
+    if (params.size() == 0) {
+        return ValueFromAmount(ver, GetBalance());
+    }
 
     if (params[0].get_str() == "*") {
         // Calculate total balance a different way from GetBalance()
@@ -648,7 +674,7 @@ Value getbalance(const Array& params, bool fHelp)
             nBalance += allGenerated;
         }
         printf("Found %d accounts\n", vAccounts.size());
-        return (double)nBalance / (double)COIN;
+        return ValueFromAmount(ver, nBalance);
     }
 
     string strAccount = AccountFromValue(params[0]);
@@ -658,11 +684,11 @@ Value getbalance(const Array& params, bool fHelp)
 
     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
 
-    return (double)nBalance / (double)COIN;
+    return ValueFromAmount(ver, nBalance);
 }
 
 
-Value movecmd(const Array& params, bool fHelp)
+Value movecmd(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 3 || params.size() > 5)
         throw runtime_error(
@@ -671,7 +697,7 @@ Value movecmd(const Array& params, bool fHelp)
 
     string strFrom = AccountFromValue(params[0]);
     string strTo = AccountFromValue(params[1]);
-    int64 nAmount = AmountFromValue(params[2]);
+    int64 nAmount = AmountFromValue(ver, params[2]);
     int nMinDepth = 1;
     if (params.size() > 3)
         nMinDepth = params[3].get_int();
@@ -725,7 +751,7 @@ Value movecmd(const Array& params, bool fHelp)
 }
 
 
-Value sendfrom(const Array& params, bool fHelp)
+Value sendfrom(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 3 || params.size() > 6)
         throw runtime_error(
@@ -734,7 +760,7 @@ Value sendfrom(const Array& params, bool fHelp)
 
     string strAccount = AccountFromValue(params[0]);
     string strAddress = params[1].get_str();
-    int64 nAmount = AmountFromValue(params[2]);
+    int64 nAmount = AmountFromValue(ver, params[2]);
     int nMinDepth = 1;
     if (params.size() > 3)
         nMinDepth = params[3].get_int();
@@ -775,7 +801,7 @@ struct tallyitem
     }
 };
 
-Value ListReceived(const Array& params, bool fByAccounts)
+Value ListReceived(int ver, const Array& params, bool fByAccounts)
 {
     // Minimum confirmations
     int nMinDepth = 1;
@@ -851,7 +877,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
                 obj.push_back(Pair("address",       strAddress));
                 obj.push_back(Pair("account",       strAccount));
                 obj.push_back(Pair("label",         strAccount)); // deprecated
-                obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
+                obj.push_back(Pair("amount",        ValueFromAmount(ver, nAmount)));
                 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
                 ret.push_back(obj);
             }
@@ -867,7 +893,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
             Object obj;
             obj.push_back(Pair("account",       (*it).first));
             obj.push_back(Pair("label",         (*it).first)); // deprecated
-            obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
+            obj.push_back(Pair("amount",        ValueFromAmount(ver, nAmount)));
             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
             ret.push_back(obj);
         }
@@ -876,7 +902,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
     return ret;
 }
 
-Value listreceivedbyaddress(const Array& params, bool fHelp)
+Value listreceivedbyaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 2)
         throw runtime_error(
@@ -889,10 +915,10 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
             "  \"amount\" : total amount received by the address\n"
             "  \"confirmations\" : number of confirmations of the most recent transaction included");
 
-    return ListReceived(params, false);
+    return ListReceived(ver, params, false);
 }
 
-Value listreceivedbyaccount(const Array& params, bool fHelp)
+Value listreceivedbyaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 2)
         throw runtime_error(
@@ -904,10 +930,10 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
             "  \"amount\" : total amount received by addresses with this account\n"
             "  \"confirmations\" : number of confirmations of the most recent transaction included");
 
-    return ListReceived(params, true);
+    return ListReceived(ver, params, true);
 }
 
-void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
+void ListTransactions(int ver, const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
 {
     int64 nGenerated, nFee;
     string strSentAccount;
@@ -923,7 +949,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
         Object entry;
         entry.push_back(Pair("account", string("")));
         entry.push_back(Pair("category", "generate"));
-        entry.push_back(Pair("amount", ValueFromAmount(nGenerated)));
+        entry.push_back(Pair("amount", ValueFromAmount(ver, nGenerated)));
         if (fLong)
             WalletTxToJSON(wtx, entry);
         ret.push_back(entry);
@@ -938,8 +964,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
             entry.push_back(Pair("account", strSentAccount));
             entry.push_back(Pair("address", s.first));
             entry.push_back(Pair("category", "send"));
-            entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
-            entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
+            entry.push_back(Pair("amount", ValueFromAmount(ver, -s.second)));
+            entry.push_back(Pair("fee", ValueFromAmount(ver, -nFee)));
             if (fLong)
                 WalletTxToJSON(wtx, entry);
             ret.push_back(entry);
@@ -961,7 +987,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
                     entry.push_back(Pair("account", account));
                     entry.push_back(Pair("address", r.first));
                     entry.push_back(Pair("category", "receive"));
-                    entry.push_back(Pair("amount", ValueFromAmount(r.second)));
+                    entry.push_back(Pair("amount", ValueFromAmount(ver, r.second)));
                     if (fLong)
                         WalletTxToJSON(wtx, entry);
                     ret.push_back(entry);
@@ -971,7 +997,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
 
 }
 
-void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
+void AcentryToJSON(int ver, const CAccountingEntry& acentry, const string& strAccount, Array& ret)
 {
     bool fAllAccounts = (strAccount == string("*"));
 
@@ -981,14 +1007,14 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar
         entry.push_back(Pair("account", acentry.strAccount));
         entry.push_back(Pair("category", "move"));
         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
-        entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
+        entry.push_back(Pair("amount", ValueFromAmount(ver, acentry.nCreditDebit)));
         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
         entry.push_back(Pair("comment", acentry.strComment));
         ret.push_back(entry);
     }
 }
 
-Value listtransactions(const Array& params, bool fHelp)
+Value listtransactions(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 2)
         throw runtime_error(
@@ -1029,10 +1055,10 @@ Value listtransactions(const Array& params, bool fHelp)
         {
             CWalletTx *const pwtx = (*it).second.first;
             if (pwtx != 0)
-                ListTransactions(*pwtx, strAccount, 0, true, ret);
+                ListTransactions(ver, *pwtx, strAccount, 0, true, ret);
             CAccountingEntry *const pacentry = (*it).second.second;
             if (pacentry != 0)
-                AcentryToJSON(*pacentry, strAccount, ret);
+                AcentryToJSON(ver, *pacentry, strAccount, ret);
 
             if (ret.size() >= nCount) break;
         }
@@ -1051,7 +1077,7 @@ Value listtransactions(const Array& params, bool fHelp)
     return ret;
 }
 
-Value listaccounts(const Array& params, bool fHelp)
+Value listaccounts(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -1099,12 +1125,12 @@ Value listaccounts(const Array& params, bool fHelp)
 
     Object ret;
     foreach(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
-        ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
+        ret.push_back(Pair(accountBalance.first, ValueFromAmount(ver, accountBalance.second)));
     }
     return ret;
 }
 
-Value gettransaction(const Array& params, bool fHelp)
+Value gettransaction(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -1126,14 +1152,14 @@ Value gettransaction(const Array& params, bool fHelp)
         int64 nNet = nCredit - nDebit;
         int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
 
-        entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+        entry.push_back(Pair("amount", ValueFromAmount(ver, nNet - nFee)));
         if (wtx.IsFromMe())
-            entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+            entry.push_back(Pair("fee", ValueFromAmount(ver, nFee)));
 
         WalletTxToJSON(mapWallet[hash], entry);
 
         Array details;
-        ListTransactions(mapWallet[hash], "*", 0, false, details);
+        ListTransactions(ver, mapWallet[hash], "*", 0, false, details);
         entry.push_back(Pair("details", details));
     }
 
@@ -1141,7 +1167,7 @@ Value gettransaction(const Array& params, bool fHelp)
 }
 
 
-Value backupwallet(const Array& params, bool fHelp)
+Value backupwallet(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -1155,7 +1181,7 @@ Value backupwallet(const Array& params, bool fHelp)
 }
 
 
-Value validateaddress(const Array& params, bool fHelp)
+Value validateaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -1185,7 +1211,7 @@ Value validateaddress(const Array& params, bool fHelp)
 }
 
 
-Value getwork(const Array& params, bool fHelp)
+Value getwork(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -1806,6 +1832,21 @@ void ThreadRPCServer2(void* parg)
             if (valMethod.type() != str_type)
                 throw JSONRPCError(-32600, "Method must be a string");
             string strMethod = valMethod.get_str();
+            int APIVersion = 0;
+            {
+                size_t nlen;
+                const char*data;
+                if (strMethod.size() > 10
+                 && 0 == strncmp(data = strMethod.data(), "bitcoin.", 8)
+                 && (nlen = strMethod.find('.', 8)) != string::npos) {
+                    nlen -= 8;
+                    char ndata[nlen + 1];
+                    memcpy(ndata, data + 8, nlen);
+                    ndata[nlen] = '\0';
+                    APIVersion = atoi(ndata);
+                    strMethod.erase(0, 9 + nlen);
+                }
+            }
             if (strMethod != "getwork")
                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
 
@@ -1832,7 +1873,7 @@ void ThreadRPCServer2(void* parg)
             try
             {
                 // Execute
-                Value result = (*(*mi).second)(params, false);
+                Value result = (*(*mi).second)(APIVersion, params, false);
 
                 // Send reply
                 string strReply = JSONRPCReply(result, Value::null, id);
@@ -1938,6 +1979,18 @@ void ConvertTo(Value& value)
     }
 }
 
+void ConvertToAmount(int ver, Value& value)
+{
+    switch (ver) {
+    case 0:
+        ConvertTo<double>(value);
+        break;
+    default:
+        ConvertTo<boost::int64_t>(value);
+        value.set_amount(true);
+    }
+}
+
 int CommandLineRPC(int argc, char *argv[])
 {
     string strPrint;
@@ -1951,6 +2004,8 @@ int CommandLineRPC(int argc, char *argv[])
             argv++;
         }
 
+        int64 APIVersion = GetArg("-rpcversion", 0);
+
         // Method
         if (argc < 2)
             throw runtime_error("too few parameters");
@@ -1967,7 +2022,7 @@ int CommandLineRPC(int argc, char *argv[])
         //
         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
-        if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
+        if (strMethod == "sendtoaddress"          && n > 1) ConvertToAmount(APIVersion, params[1]);
         if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
@@ -1981,13 +2036,16 @@ int CommandLineRPC(int argc, char *argv[])
         if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
         if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]); // deprecated
         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
-        if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
+        if (strMethod == "move"                   && n > 2) ConvertToAmount(APIVersion, params[2]);
         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
-        if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
+        if (strMethod == "sendfrom"               && n > 2) ConvertToAmount(APIVersion, params[2]);
         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
 
+        if (APIVersion)
+            strMethod.insert(0, "bitcoin." + boost::lexical_cast<string>(APIVersion) + '.');
+
         // Execute
         Object reply = CallRPC(strMethod, params);
 
diff --git a/util.h b/util.h
index c69bf1c..69fd2ea 100644
--- a/util.h
+++ b/util.h
@@ -17,6 +17,14 @@ typedef unsigned long long  uint64;
 #define __forceinline  inline
 #endif
 
+#ifndef __deprecated__
+#  if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#    define __deprecated__ __attribute ((__deprecated__))
+#  else
+#    define __deprecated /* noop */
+#  endif
+#endif
+
 #define foreach             BOOST_FOREACH
 #define loop                for (;;)
 #define BEGIN(a)            ((char*)&(a))

Annotation: RPCv1

Author: Luke-Jr
Mode: patch
Date: Mon, 21 Feb 2011 03:30:52
Plain Text |
diff --git a/init.cpp b/init.cpp
index 04bdd68..ec843d8 100644
--- a/init.cpp
+++ b/init.cpp
@@ -185,6 +185,7 @@ bool AppInit2(int argc, char* argv[])
             "  -rpcport=<port>  \t\t  " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") +
             "  -rpcallowip=<ip> \t\t  " + _("Allow JSON-RPC connections from specified IP address\n") +
             "  -rpcconnect=<ip> \t  "   + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") +
+            "  -rpcversion=<n>  \t  "   + _("Send commands in RPC version <n>, default 0 (for now)\n") +
             "  -keypool=<n>     \t  "   + _("Set key pool size to <n> (default: 100)\n") +
             "  -rescan          \t  "   + _("Rescan the block chain for missing wallet transactions\n");
 
diff --git a/json/json_spirit_value.h b/json/json_spirit_value.h
index 7e83a2a..89be790 100644
--- a/json/json_spirit_value.h
+++ b/json/json_spirit_value.h
@@ -59,6 +59,8 @@ namespace json_spirit
 
         bool is_uint64() const;
         bool is_null() const;
+        bool is_amount() const;
+        void set_amount(bool);
 
         const String_type& get_str()    const;
         const Object&      get_obj()    const;
@@ -88,6 +90,7 @@ namespace json_spirit
         Value_type type_;
         Variant v_;
         bool is_uint64_;
+        bool is_amount_;
     };
 
     // vector objects
@@ -211,6 +214,7 @@ namespace json_spirit
     template< class Config >
     Value_impl< Config >::Value_impl()
     :   type_( null_type )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -219,6 +223,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Const_str_ptr value )
     :   type_( str_type )
     ,   v_( String_type( value ) )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -227,6 +232,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const String_type& value )
     :   type_( str_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -235,6 +241,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Object& value )
     :   type_( obj_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -243,6 +250,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Array& value )
     :   type_( array_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -251,6 +259,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( bool value )
     :   type_( bool_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -259,6 +268,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( int value )
     :   type_( int_type )
     ,   v_( static_cast< boost::int64_t >( value ) )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -267,6 +277,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( boost::int64_t value )
     :   type_( int_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -275,6 +286,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( boost::uint64_t value )
     :   type_( int_type )
     ,   v_( static_cast< boost::int64_t >( value ) )
+    ,   is_amount_( false )
     ,   is_uint64_( true )
     {
     }
@@ -283,6 +295,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( double value )
     :   type_( real_type )
     ,   v_( value )
+    ,   is_amount_( false )
     ,   is_uint64_( false )
     {
     }
@@ -291,6 +304,7 @@ namespace json_spirit
     Value_impl< Config >::Value_impl( const Value_impl< Config >& other )
     :   type_( other.type() )
     ,   v_( other.v_ )
+    ,   is_amount_( other.is_amount_ )
     ,   is_uint64_( other.is_uint64_ )
     {
     }
@@ -303,6 +317,7 @@ namespace json_spirit
         std::swap( type_, tmp.type_ );
         std::swap( v_, tmp.v_ );
         std::swap( is_uint64_, tmp.is_uint64_ );
+        std::swap( is_amount_, tmp.is_amount_ );
 
         return *this;
     }
@@ -330,6 +345,18 @@ namespace json_spirit
     }
 
     template< class Config >
+    bool Value_impl< Config >::is_amount() const
+    {
+        return is_amount_;
+    }
+
+    template< class Config >
+    void Value_impl< Config >::set_amount(bool nv)
+    {
+        is_amount_ = nv;
+    }
+
+    template< class Config >
     bool Value_impl< Config >::is_null() const
     {
         return type() == null_type;
@@ -392,6 +419,11 @@ namespace json_spirit
     template< class Config >
     boost::int64_t Value_impl< Config >::get_int64() const
     {
+        if( type() == real_type )
+        {
+            return static_cast< boost::int64_t >( get_real() );
+        }
+
         check_type(  int_type );
 
         return boost::get< boost::int64_t >( v_ );
diff --git a/json/json_spirit_writer_template.h b/json/json_spirit_writer_template.h
index 28c49dd..98910a6 100644
--- a/json/json_spirit_writer_template.h
+++ b/json/json_spirit_writer_template.h
@@ -161,6 +161,8 @@ namespace json_spirit
             {
                os_ << value.get_int64();
             }
+            if (value.is_amount())
+               os_ << ".0";
         }
 
         void output( const String_type& s )
diff --git a/rpc.cpp b/rpc.cpp
index 69b09bc..21a098e 100644
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -2,6 +2,8 @@
 // Distributed under the MIT/X11 software license, see the accompanying
 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
 
+#include <string.h>
+
 #include "headers.h"
 #include "cryptopp/sha.h"
 #undef printf
@@ -12,6 +14,7 @@
 #include <boost/asio/ssl.hpp> 
 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
 #endif
+#include <boost/lexical_cast.hpp>
 #include "json/json_spirit_reader_template.h"
 #include "json/json_spirit_writer_template.h"
 #include "json/json_spirit_utils.h"
@@ -25,7 +28,7 @@ using namespace boost::asio;
 using namespace json_spirit;
 
 void ThreadRPCServer2(void* parg);
-typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
+typedef Value(*rpcfn_type)(int, const Array& params, bool fHelp);
 extern map<string, rpcfn_type> mapCallTable;
 
 
@@ -60,20 +63,41 @@ void PrintConsole(const char* format, ...)
 }
 
 
-int64 AmountFromValue(const Value& value)
+int64 AmountFromValue(int ver, const Value& value)
 {
+    int64 nAmount;
+    if (!ver) {
     double dAmount = value.get_real();
     if (dAmount <= 0.0 || dAmount > 21000000.0)
         throw JSONRPCError(-3, "Invalid amount");
-    int64 nAmount = roundint64(dAmount * 100.00) * CENT;
+        nAmount = roundint64(dAmount * 100.00) * CENT;
+    }
+    else
+        nAmount = value.get_int64();
     if (!MoneyRange(nAmount))
         throw JSONRPCError(-3, "Invalid amount");
     return nAmount;
 }
 
+Value ValueFromAmount(int ver, int64 amount)
+{
+    if (!ver)
+        return (double)amount / (double)COIN;
+    Value rv((boost::int64_t)amount);
+    rv.set_amount(true);
+    return rv;
+}
+
+__deprecated__
+int64 AmountFromValue(const Value& value)
+{
+    return AmountFromValue(0, value);
+}
+
+__deprecated__
 Value ValueFromAmount(int64 amount)
 {
-    return (double)amount / (double)COIN;
+    return ValueFromAmount(0, amount);
 }
 
 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
@@ -100,7 +124,7 @@ string AccountFromValue(const Value& value)
 ///
 
 
-Value help(const Array& params, bool fHelp)
+Value help(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -128,7 +152,7 @@ Value help(const Array& params, bool fHelp)
             Array params;
             rpcfn_type pfn = (*mi).second;
             if (setDone.insert(pfn).second)
-                (*pfn)(params, true);
+                (*pfn)(ver, params, true);
         }
         catch (std::exception& e)
         {
@@ -147,7 +171,7 @@ Value help(const Array& params, bool fHelp)
 }
 
 
-Value stop(const Array& params, bool fHelp)
+Value stop(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -160,7 +184,7 @@ Value stop(const Array& params, bool fHelp)
 }
 
 
-Value getblockcount(const Array& params, bool fHelp)
+Value getblockcount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -171,7 +195,7 @@ Value getblockcount(const Array& params, bool fHelp)
 }
 
 
-Value getblocknumber(const Array& params, bool fHelp)
+Value getblocknumber(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -182,7 +206,7 @@ Value getblocknumber(const Array& params, bool fHelp)
 }
 
 
-Value getconnectioncount(const Array& params, bool fHelp)
+Value getconnectioncount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -205,7 +229,7 @@ double GetDifficulty()
     return dMinimum / dCurrently;
 }
 
-Value getdifficulty(const Array& params, bool fHelp)
+Value getdifficulty(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -216,7 +240,7 @@ Value getdifficulty(const Array& params, bool fHelp)
 }
 
 
-Value getgenerate(const Array& params, bool fHelp)
+Value getgenerate(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -227,7 +251,7 @@ Value getgenerate(const Array& params, bool fHelp)
 }
 
 
-Value setgenerate(const Array& params, bool fHelp)
+Value setgenerate(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -255,7 +279,7 @@ Value setgenerate(const Array& params, bool fHelp)
 }
 
 
-Value gethashespersec(const Array& params, bool fHelp)
+Value gethashespersec(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -268,7 +292,7 @@ Value gethashespersec(const Array& params, bool fHelp)
 }
 
 
-Value getinfo(const Array& params, bool fHelp)
+Value getinfo(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 0)
         throw runtime_error(
@@ -277,23 +301,24 @@ Value getinfo(const Array& params, bool fHelp)
 
     Object obj;
     obj.push_back(Pair("version",       (int)VERSION));
-    obj.push_back(Pair("balance",       (double)GetBalance() / (double)COIN));
+    obj.push_back(Pair("rpcversion",    (int)ver));
+    obj.push_back(Pair("balance",       ValueFromAmount(ver, GetBalance())));
+    obj.push_back(Pair("paytxfee",      ValueFromAmount(ver, nTransactionFee)));
     obj.push_back(Pair("blocks",        (int)nBestHeight));
     obj.push_back(Pair("connections",   (int)vNodes.size()));
     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
-    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
+    obj.push_back(Pair("hashespersec",  gethashespersec(ver, params, false)));
     obj.push_back(Pair("testnet",       fTestNet));
     obj.push_back(Pair("keypoololdest", (boost::int64_t)GetOldestKeyPoolTime()));
-    obj.push_back(Pair("paytxfee",      (double)nTransactionFee / (double)COIN));
     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
     return obj;
 }
 
 
-Value getnewaddress(const Array& params, bool fHelp)
+Value getnewaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -358,7 +383,7 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
     return strAddress;
 }
 
-Value getaccountaddress(const Array& params, bool fHelp)
+Value getaccountaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -373,7 +398,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
 
 
 
-Value setaccount(const Array& params, bool fHelp)
+Value setaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -401,7 +426,7 @@ Value setaccount(const Array& params, bool fHelp)
 }
 
 
-Value getaccount(const Array& params, bool fHelp)
+Value getaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -421,7 +446,7 @@ Value getaccount(const Array& params, bool fHelp)
 }
 
 
-Value getaddressesbyaccount(const Array& params, bool fHelp)
+Value getaddressesbyaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -450,7 +475,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
     return ret;
 }
 
-Value sendtoaddress(const Array& params, bool fHelp)
+Value sendtoaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 2 || params.size() > 4)
         throw runtime_error(
@@ -460,7 +485,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
     string strAddress = params[0].get_str();
 
     // Amount
-    int64 nAmount = AmountFromValue(params[1]);
+    int64 nAmount = AmountFromValue(ver, params[1]);
 
     // Wallet comments
     CWalletTx wtx;
@@ -476,7 +501,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
 }
 
 
-Value getreceivedbyaddress(const Array& params, bool fHelp)
+Value getreceivedbyaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -513,7 +538,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
         }
     }
 
-    return (double)nAmount / (double)COIN;
+    return ValueFromAmount(ver, nAmount);
 }
 
 
@@ -538,7 +563,7 @@ void GetAccountPubKeys(string strAccount, set<CScript>& setPubKey)
 }
 
 
-Value getreceivedbyaccount(const Array& params, bool fHelp)
+Value getreceivedbyaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
@@ -572,7 +597,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
         }
     }
 
-    return (double)nAmount / (double)COIN;
+    return ValueFromAmount(ver, nAmount);
 }
 
 
@@ -610,7 +635,7 @@ int64 GetAccountBalance(const string& strAccount, int nMinDepth)
 }
 
 
-Value getbalance(const Array& params, bool fHelp)
+Value getbalance(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 0 || params.size() > 2)
         throw runtime_error(
@@ -618,8 +643,9 @@ Value getbalance(const Array& params, bool fHelp)
             "If [account] is not specified, returns the server's total available balance.\n"
             "If [account] is specified, returns the balance in the account.");
 
-    if (params.size() == 0)
-        return ((double)GetBalance() / (double)COIN);
+    if (params.size() == 0) {
+        return ValueFromAmount(ver, GetBalance());
+    }
 
     if (params[0].get_str() == "*") {
         // Calculate total balance a different way from GetBalance()
@@ -648,7 +674,7 @@ Value getbalance(const Array& params, bool fHelp)
             nBalance += allGenerated;
         }
         printf("Found %d accounts\n", vAccounts.size());
-        return (double)nBalance / (double)COIN;
+        return ValueFromAmount(ver, nBalance);
     }
 
     string strAccount = AccountFromValue(params[0]);
@@ -658,11 +684,11 @@ Value getbalance(const Array& params, bool fHelp)
 
     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
 
-    return (double)nBalance / (double)COIN;
+    return ValueFromAmount(ver, nBalance);
 }
 
 
-Value movecmd(const Array& params, bool fHelp)
+Value movecmd(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 3 || params.size() > 5)
         throw runtime_error(
@@ -671,7 +697,7 @@ Value movecmd(const Array& params, bool fHelp)
 
     string strFrom = AccountFromValue(params[0]);
     string strTo = AccountFromValue(params[1]);
-    int64 nAmount = AmountFromValue(params[2]);
+    int64 nAmount = AmountFromValue(ver, params[2]);
     int nMinDepth = 1;
     if (params.size() > 3)
         nMinDepth = params[3].get_int();
@@ -725,7 +751,7 @@ Value movecmd(const Array& params, bool fHelp)
 }
 
 
-Value sendfrom(const Array& params, bool fHelp)
+Value sendfrom(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() < 3 || params.size() > 6)
         throw runtime_error(
@@ -734,7 +760,7 @@ Value sendfrom(const Array& params, bool fHelp)
 
     string strAccount = AccountFromValue(params[0]);
     string strAddress = params[1].get_str();
-    int64 nAmount = AmountFromValue(params[2]);
+    int64 nAmount = AmountFromValue(ver, params[2]);
     int nMinDepth = 1;
     if (params.size() > 3)
         nMinDepth = params[3].get_int();
@@ -775,7 +801,7 @@ struct tallyitem
     }
 };
 
-Value ListReceived(const Array& params, bool fByAccounts)
+Value ListReceived(int ver, const Array& params, bool fByAccounts)
 {
     // Minimum confirmations
     int nMinDepth = 1;
@@ -851,7 +877,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
                 obj.push_back(Pair("address",       strAddress));
                 obj.push_back(Pair("account",       strAccount));
                 obj.push_back(Pair("label",         strAccount)); // deprecated
-                obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
+                obj.push_back(Pair("amount",        ValueFromAmount(ver, nAmount)));
                 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
                 ret.push_back(obj);
             }
@@ -867,7 +893,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
             Object obj;
             obj.push_back(Pair("account",       (*it).first));
             obj.push_back(Pair("label",         (*it).first)); // deprecated
-            obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
+            obj.push_back(Pair("amount",        ValueFromAmount(ver, nAmount)));
             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
             ret.push_back(obj);
         }
@@ -876,7 +902,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
     return ret;
 }
 
-Value listreceivedbyaddress(const Array& params, bool fHelp)
+Value listreceivedbyaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 2)
         throw runtime_error(
@@ -889,10 +915,10 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
             "  \"amount\" : total amount received by the address\n"
             "  \"confirmations\" : number of confirmations of the most recent transaction included");
 
-    return ListReceived(params, false);
+    return ListReceived(ver, params, false);
 }
 
-Value listreceivedbyaccount(const Array& params, bool fHelp)
+Value listreceivedbyaccount(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 2)
         throw runtime_error(
@@ -904,10 +930,10 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
             "  \"amount\" : total amount received by addresses with this account\n"
             "  \"confirmations\" : number of confirmations of the most recent transaction included");
 
-    return ListReceived(params, true);
+    return ListReceived(ver, params, true);
 }
 
-void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
+void ListTransactions(int ver, const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
 {
     int64 nGenerated, nFee;
     string strSentAccount;
@@ -923,7 +949,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
         Object entry;
         entry.push_back(Pair("account", string("")));
         entry.push_back(Pair("category", "generate"));
-        entry.push_back(Pair("amount", ValueFromAmount(nGenerated)));
+        entry.push_back(Pair("amount", ValueFromAmount(ver, nGenerated)));
         if (fLong)
             WalletTxToJSON(wtx, entry);
         ret.push_back(entry);
@@ -938,8 +964,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
             entry.push_back(Pair("account", strSentAccount));
             entry.push_back(Pair("address", s.first));
             entry.push_back(Pair("category", "send"));
-            entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
-            entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
+            entry.push_back(Pair("amount", ValueFromAmount(ver, -s.second)));
+            entry.push_back(Pair("fee", ValueFromAmount(ver, -nFee)));
             if (fLong)
                 WalletTxToJSON(wtx, entry);
             ret.push_back(entry);
@@ -961,7 +987,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
                     entry.push_back(Pair("account", account));
                     entry.push_back(Pair("address", r.first));
                     entry.push_back(Pair("category", "receive"));
-                    entry.push_back(Pair("amount", ValueFromAmount(r.second)));
+                    entry.push_back(Pair("amount", ValueFromAmount(ver, r.second)));
                     if (fLong)
                         WalletTxToJSON(wtx, entry);
                     ret.push_back(entry);
@@ -971,7 +997,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
 
 }
 
-void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
+void AcentryToJSON(int ver, const CAccountingEntry& acentry, const string& strAccount, Array& ret)
 {
     bool fAllAccounts = (strAccount == string("*"));
 
@@ -981,14 +1007,14 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar
         entry.push_back(Pair("account", acentry.strAccount));
         entry.push_back(Pair("category", "move"));
         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
-        entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
+        entry.push_back(Pair("amount", ValueFromAmount(ver, acentry.nCreditDebit)));
         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
         entry.push_back(Pair("comment", acentry.strComment));
         ret.push_back(entry);
     }
 }
 
-Value listtransactions(const Array& params, bool fHelp)
+Value listtransactions(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 2)
         throw runtime_error(
@@ -1029,10 +1055,10 @@ Value listtransactions(const Array& params, bool fHelp)
         {
             CWalletTx *const pwtx = (*it).second.first;
             if (pwtx != 0)
-                ListTransactions(*pwtx, strAccount, 0, true, ret);
+                ListTransactions(ver, *pwtx, strAccount, 0, true, ret);
             CAccountingEntry *const pacentry = (*it).second.second;
             if (pacentry != 0)
-                AcentryToJSON(*pacentry, strAccount, ret);
+                AcentryToJSON(ver, *pacentry, strAccount, ret);
 
             if (ret.size() >= nCount) break;
         }
@@ -1051,7 +1077,7 @@ Value listtransactions(const Array& params, bool fHelp)
     return ret;
 }
 
-Value listaccounts(const Array& params, bool fHelp)
+Value listaccounts(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -1099,12 +1125,12 @@ Value listaccounts(const Array& params, bool fHelp)
 
     Object ret;
     foreach(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
-        ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
+        ret.push_back(Pair(accountBalance.first, ValueFromAmount(ver, accountBalance.second)));
     }
     return ret;
 }
 
-Value gettransaction(const Array& params, bool fHelp)
+Value gettransaction(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -1126,14 +1152,14 @@ Value gettransaction(const Array& params, bool fHelp)
         int64 nNet = nCredit - nDebit;
         int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
 
-        entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+        entry.push_back(Pair("amount", ValueFromAmount(ver, nNet - nFee)));
         if (wtx.IsFromMe())
-            entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+            entry.push_back(Pair("fee", ValueFromAmount(ver, nFee)));
 
         WalletTxToJSON(mapWallet[hash], entry);
 
         Array details;
-        ListTransactions(mapWallet[hash], "*", 0, false, details);
+        ListTransactions(ver, mapWallet[hash], "*", 0, false, details);
         entry.push_back(Pair("details", details));
     }
 
@@ -1141,7 +1167,7 @@ Value gettransaction(const Array& params, bool fHelp)
 }
 
 
-Value backupwallet(const Array& params, bool fHelp)
+Value backupwallet(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -1155,7 +1181,7 @@ Value backupwallet(const Array& params, bool fHelp)
 }
 
 
-Value validateaddress(const Array& params, bool fHelp)
+Value validateaddress(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
         throw runtime_error(
@@ -1185,7 +1211,7 @@ Value validateaddress(const Array& params, bool fHelp)
 }
 
 
-Value getwork(const Array& params, bool fHelp)
+Value getwork(int ver, const Array& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
         throw runtime_error(
@@ -1806,6 +1832,21 @@ void ThreadRPCServer2(void* parg)
             if (valMethod.type() != str_type)
                 throw JSONRPCError(-32600, "Method must be a string");
             string strMethod = valMethod.get_str();
+            int APIVersion = 0;
+            {
+                size_t nlen;
+                const char*data;
+                if (strMethod.size() > 10
+                 && 0 == strncmp(data = strMethod.data(), "bitcoin.", 8)
+                 && (nlen = strMethod.find('.', 8)) != string::npos) {
+                    nlen -= 8;
+                    char ndata[nlen + 1];
+                    memcpy(ndata, data + 8, nlen);
+                    ndata[nlen] = '\0';
+                    APIVersion = atoi(ndata);
+                    strMethod.erase(0, 9 + nlen);
+                }
+            }
             if (strMethod != "getwork")
                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
 
@@ -1832,7 +1873,7 @@ void ThreadRPCServer2(void* parg)
             try
             {
                 // Execute
-                Value result = (*(*mi).second)(params, false);
+                Value result = (*(*mi).second)(APIVersion, params, false);
 
                 // Send reply
                 string strReply = JSONRPCReply(result, Value::null, id);
@@ -1938,6 +1979,18 @@ void ConvertTo(Value& value)
     }
 }
 
+void ConvertToAmount(int ver, Value& value)
+{
+    switch (ver) {
+    case 0:
+        ConvertTo<double>(value);
+        break;
+    default:
+        ConvertTo<boost::int64_t>(value);
+        value.set_amount(true);
+    }
+}
+
 int CommandLineRPC(int argc, char *argv[])
 {
     string strPrint;
@@ -1951,6 +2004,8 @@ int CommandLineRPC(int argc, char *argv[])
             argv++;
         }
 
+        int64 APIVersion = GetArg("-rpcversion", 0);
+
         // Method
         if (argc < 2)
             throw runtime_error("too few parameters");
@@ -1967,7 +2022,7 @@ int CommandLineRPC(int argc, char *argv[])
         //
         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
-        if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
+        if (strMethod == "sendtoaddress"          && n > 1) ConvertToAmount(APIVersion, params[1]);
         if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
@@ -1981,13 +2036,16 @@ int CommandLineRPC(int argc, char *argv[])
         if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
         if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]); // deprecated
         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
-        if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
+        if (strMethod == "move"                   && n > 2) ConvertToAmount(APIVersion, params[2]);
         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
-        if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
+        if (strMethod == "sendfrom"               && n > 2) ConvertToAmount(APIVersion, params[2]);
         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
 
+        if (APIVersion)
+            strMethod.insert(0, "bitcoin." + boost::lexical_cast<string>(APIVersion) + '.');
+
         // Execute
         Object reply = CallRPC(strMethod, params);
 
diff --git a/util.h b/util.h
index c69bf1c..69fd2ea 100644
--- a/util.h
+++ b/util.h
@@ -17,6 +17,14 @@ typedef unsigned long long  uint64;
 #define __forceinline  inline
 #endif
 
+#ifndef __deprecated__
+#  if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#    define __deprecated__ __attribute ((__deprecated__))
+#  else
+#    define __deprecated /* noop */
+#  endif
+#endif
+
 #define foreach             BOOST_FOREACH
 #define loop                for (;;)
 #define BEGIN(a)            ((char*)&(a))

New Annotation

Summary:
Author:
Mode:
Body: