changeset 3151:0bd236db489f draft

Rework gettransaction / getblock RPC calls This PULL reworks new (post-0.6.*) features of the gettransaction/getblock RPC calls as follows: It removes the 'decompositions' object argument from getblock, replacing it just a list of transaction hashes; equivalent (I believe) of passing the {"tx":"hash"} decomposition. It replaces the 'decompositions' object argument of gettransaction with a boolean flag; if true, returns the same stuff that the {"script":"obj"} decomposition would return (txins/txouts as hex, disassembled, and bitcoin addresses). It adds a "rawtx" field to the output of gettransaction, that is the entire transaction serialized and hex-encoded. It removes the "size" field from gettransaction, since the size is trivial to compute from the "rawtx" field (either take the length after hex-decoding, or just compute it as hex-length/2).
author Gavin Andresen <gavinandresen@gmail.com>
date Sun, 24 Jun 2012 17:04:50 -0400
parents 2145835b6be7
children bf716647e542
files src/bitcoinrpc.cpp
diffstat 1 files changed, 29 insertions(+), 265 deletions(-) [+]
line wrap: on
line diff
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -137,33 +137,6 @@
         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
 }
 
-enum DecomposeMode {
-    DM_NONE = 0,
-    DM_HASH,
-    DM_HEX,
-    DM_ASM,
-    DM_OBJ,
-};
-
-enum DecomposeMode
-FindDecompose(const Object& decompositions, const char* pcType, const char* pcDefault)
-{
-    Value val = find_value(decompositions, pcType);
-    std::string strDecompose = (val.type() == null_type) ? pcDefault : val.get_str();
-
-    if (strDecompose == "no")
-        return DM_NONE;
-    if (strDecompose == "hash")
-        return DM_HASH;
-    if (strDecompose == "hex")
-        return DM_HEX;
-    if (strDecompose == "asm")
-        return DM_ASM;
-    if (strDecompose == "obj")
-        return DM_OBJ;
-    throw JSONRPCError(-18, "Invalid decomposition");
-}
-
 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
 {
     int confirms = wtx.GetDepthInMainChain();
@@ -179,141 +152,6 @@
         entry.push_back(Pair(item.first, item.second));
 }
 
-void
-ScriptSigToJSON(const CTxIn& txin, Object& out)
-{
-    out.push_back(Pair("asm", txin.scriptSig.ToString()));
-    out.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
-
-    CTransaction txprev;
-    uint256 hashTxprevBlock;
-    if (!GetTransaction(txin.prevout.hash, txprev, hashTxprevBlock))
-        return;
-
-    txnouttype type;
-    vector<CTxDestination> addresses;
-    int nRequired;
-
-    if (!ExtractDestinations(txprev.vout[txin.prevout.n].scriptPubKey, type,
-                          addresses, nRequired))
-    {
-        out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
-        return;
-    }
-
-    out.push_back(Pair("type", GetTxnOutputType(type)));
-    if (type == TX_MULTISIG)
-    {
-        // TODO: Need to handle this specially since not all input addresses are required...
-        return;
-    }
-
-    Array a;
-    BOOST_FOREACH(const CTxDestination& addr, addresses)
-        a.push_back(CBitcoinAddress(addr).ToString());
-    out.push_back(Pair("addresses", a));
-}
-
-void
-ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
-{
-    txnouttype type;
-    vector<CTxDestination> addresses;
-    int nRequired;
-
-    out.push_back(Pair("asm", scriptPubKey.ToString()));
-    out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
-
-    if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
-    {
-        out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
-        return;
-    }
-
-    out.push_back(Pair("reqSigs", nRequired));
-    out.push_back(Pair("type", GetTxnOutputType(type)));
-
-    Array a;
-    BOOST_FOREACH(const CTxDestination& addr, addresses)
-        a.push_back(CBitcoinAddress(addr).ToString());
-    out.push_back(Pair("addresses", a));
-}
-
-void TxToJSON(const CTransaction &tx, Object& entry, const Object& decompositions)
-{
-    entry.push_back(Pair("version", tx.nVersion));
-    entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
-    entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
-
-    enum DecomposeMode decomposeScript = FindDecompose(decompositions, "script", "asm");
-
-    Array vin;
-    BOOST_FOREACH(const CTxIn& txin, tx.vin)
-    {
-        Object in;
-        if (tx.IsCoinBase())
-            in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
-        else
-        {
-            Object prevout;
-            prevout.push_back(Pair("hash", txin.prevout.hash.GetHex()));
-            prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n));
-            in.push_back(Pair("prevout", prevout));
-            switch (decomposeScript) {
-            case DM_NONE:
-                break;
-            case DM_HEX:
-                in.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
-                break;
-            case DM_ASM:
-                in.push_back(Pair("scriptSig", txin.scriptSig.ToString()));
-                break;
-            case DM_OBJ:
-            {
-                Object o;
-                ScriptSigToJSON(txin, o);
-                in.push_back(Pair("scriptSig", o));
-                break;
-            }
-            default:
-                throw JSONRPCError(-18, "Invalid script decomposition");
-            }
-        }
-        in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
-        vin.push_back(in);
-    }
-    entry.push_back(Pair("vin", vin));
-    Array vout;
-    BOOST_FOREACH(const CTxOut& txout, tx.vout)
-    {
-        Object out;
-        out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
-        switch (decomposeScript) {
-        case DM_NONE:
-            break;
-        case DM_HEX:
-            out.push_back(Pair("scriptPubKey", HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end())));
-            break;
-        case DM_ASM:
-            out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString()));
-            break;
-        case DM_OBJ:
-        {
-            Object o;
-            ScriptPubKeyToJSON(txout.scriptPubKey, o);
-            out.push_back(Pair("scriptPubKey", o));
-            break;
-        }
-        default:
-            throw JSONRPCError(-18, "Invalid script decomposition");
-        }
-        vout.push_back(out);
-    }
-    entry.push_back(Pair("vout", vout));
-}
-
-void AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions);
-
 string AccountFromValue(const Value& value)
 {
     string strAccount = value.get_str();
@@ -322,7 +160,7 @@
     return strAccount;
 }
 
-Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const Object& decompositions)
+Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
 {
     Object result;
     result.push_back(Pair("hash", block.GetHash().GetHex()));
@@ -333,43 +171,15 @@
     result.push_back(Pair("height", blockindex->nHeight));
     result.push_back(Pair("version", block.nVersion));
     result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
+    Array txs;
+    BOOST_FOREACH(const CTransaction&tx, block.vtx)
+        txs.push_back(tx.GetHash().GetHex());
+    result.push_back(Pair("tx", txs));
     result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
     result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
     result.push_back(Pair("bits", HexBits(block.nBits)));
     result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
 
-    enum DecomposeMode decomposeTxn = FindDecompose(decompositions, "tx", "hash");
-    if (decomposeTxn)
-    {
-        Array txs;
-        switch (decomposeTxn) {
-        case DM_OBJ:
-            BOOST_FOREACH (const CTransaction&tx, block.vtx)
-            {
-                Object entry;
-                AnyTxToJSON(tx.GetHash(), &tx, entry, decompositions);
-                txs.push_back(entry);
-            }
-            break;
-        case DM_HEX:
-            BOOST_FOREACH (const CTransaction&tx, block.vtx)
-            {
-                CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
-                ssTx << tx;
-
-                txs.push_back(HexStr(ssTx.begin(), ssTx.end()));
-            }
-            break;
-        case DM_HASH:
-            BOOST_FOREACH (const CTransaction&tx, block.vtx)
-                txs.push_back(tx.GetHash().GetHex());
-            break;
-        default:
-            throw JSONRPCError(-18, "Invalid transaction decomposition");
-        }
-        result.push_back(Pair("tx", txs));
-    }
-
     if (blockindex->pprev)
         result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
     if (blockindex->pnext)
@@ -1651,78 +1461,35 @@
     return ret;
 }
 
-void
-AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions)
-{
-    if (pwalletMain->mapWallet.count(hash))
-    {
-        const CWalletTx& wtx = pwalletMain->mapWallet[hash];
-
-        TxToJSON(wtx, entry, decompositions);
-
-        int64 nCredit = wtx.GetCredit();
-        int64 nDebit = wtx.GetDebit();
-        int64 nNet = nCredit - nDebit;
-        int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
-
-        entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
-        if (wtx.IsFromMe())
-            entry.push_back(Pair("fee", ValueFromAmount(nFee)));
-
-        WalletTxToJSON(wtx, entry);
-
-        Array details;
-        ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
-        entry.push_back(Pair("details", details));
-    }
-    else
-    {
-        CTransaction tx;
-        uint256 hashBlock = 0;
-        if ((!ptx) && GetTransaction(hash, tx, hashBlock))
-            ptx = &tx;
-        if (ptx)
-        {
-            entry.push_back(Pair("txid", hash.GetHex()));
-            TxToJSON(*ptx, entry, decompositions);
-            if (hashBlock == 0)
-                entry.push_back(Pair("confirmations", 0));
-            else
-            {
-                entry.push_back(Pair("blockhash", hashBlock.GetHex()));
-                map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
-                if (mi != mapBlockIndex.end() && (*mi).second)
-                {
-                    CBlockIndex* pindex = (*mi).second;
-                    if (pindex->IsInMainChain())
-                    {
-                        entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
-                        entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
-                    }
-                    else
-                        entry.push_back(Pair("confirmations", 0));
-                }
-            }
-        }
-        else
-            throw JSONRPCError(-5, "No information available about transaction");
-    }
-}
-
 Value gettransaction(const Array& params, bool fHelp)
 {
-    if (fHelp || params.size() < 1 || params.size() > 2)
+    if (fHelp || params.size() != 1)
         throw runtime_error(
-            "gettransaction <txid> [decompositions]\n"
-            "Get detailed information about <txid>");
+            "gettransaction <txid>\n"
+            "Get detailed information about in-wallet transaction <txid>");
 
     uint256 hash;
     hash.SetHex(params[0].get_str());
 
     Object entry;
-
-    AnyTxToJSON(hash, NULL, entry,
-                (params.size() > 1) ? params[1].get_obj() : emptyobj);
+    if (!pwalletMain->mapWallet.count(hash))
+        throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
+    const CWalletTx& wtx = pwalletMain->mapWallet[hash];
+
+    int64 nCredit = wtx.GetCredit();
+    int64 nDebit = wtx.GetDebit();
+    int64 nNet = nCredit - nDebit;
+    int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+
+    entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+    if (wtx.IsFromMe())
+        entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+
+    WalletTxToJSON(wtx, entry);
+
+    Array details;
+    ListTransactions(wtx, "*", 0, false, details);
+    entry.push_back(Pair("details", details));
 
     return entry;
 }
@@ -2226,9 +1993,9 @@
 
 Value getblock(const Array& params, bool fHelp)
 {
-    if (fHelp || params.size() < 1 || params.size() > 2)
+    if (fHelp || params.size() != 1)
         throw runtime_error(
-            "getblock <hash> [decompositions]\n"
+            "getblock <hash>\n"
             "Returns details of a block with given block-hash.");
 
     std::string strHash = params[0].get_str();
@@ -2241,8 +2008,7 @@
     CBlockIndex* pblockindex = mapBlockIndex[hash];
     block.ReadFromDisk(pblockindex, true);
 
-    return blockToJSON(block, pblockindex,
-                       (params.size() > 1) ? params[1].get_obj() : emptyobj);
+    return blockToJSON(block, pblockindex);
 }
 
 Value sendrawtx(const Array& params, bool fHelp)
@@ -3204,9 +2970,7 @@
     if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
     if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
     if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
-    if (strMethod == "getblock"               && n > 1) ConvertTo<Object>(params[1]);
     if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
-    if (strMethod == "gettransaction"         && n > 1) ConvertTo<Object>(params[1]);
     if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
     if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
     if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);