diff options
author | Gavin Andresen <gavinandresen@gmail.com> | 2012-06-24 17:04:50 -0400 |
---|---|---|
committer | Gavin Andresen <gavinandresen@gmail.com> | 2012-07-05 12:42:25 -0400 |
commit | 9a6ab7f1420691267e78e302ff224076945e9133 (patch) | |
tree | 932408e289103a55f057eb34751cae5fcca2b2a5 /src | |
parent | fe70b09c428585166f1040e9023251c9c250e894 (diff) |
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).
Diffstat (limited to 'src')
-rw-r--r-- | src/bitcoinrpc.cpp | 292 |
1 files changed, 28 insertions, 264 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 109cb92f32..19815ef0fe 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -137,33 +137,6 @@ EnsureWalletIsUnlocked() 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 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) 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 @@ string AccountFromValue(const Value& value) 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 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const Obj 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 @@ Value listsinceblock(const Array& params, bool fHelp) 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; + 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))); - AnyTxToJSON(hash, NULL, entry, - (params.size() > 1) ? params[1].get_obj() : emptyobj); + WalletTxToJSON(wtx, entry); + + Array details; + ListTransactions(wtx, "*", 0, false, details); + entry.push_back(Pair("details", details)); return entry; } @@ -2226,9 +1993,9 @@ Value getblockhash(const Array& params, bool fHelp) 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 @@ Value getblock(const Array& params, bool fHelp) 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 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri 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]); |