diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 7d2450c1..34c43a9e 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -44,6 +44,8 @@ static CCriticalSection cs_nWalletUnlockTime; extern Value dumpprivkey(const Array& params, bool fHelp); extern Value importprivkey(const Array& params, bool fHelp); +const Object emptyobj; + Object JSONRPCError(int code, const string& message) { Object error; @@ -111,6 +113,33 @@ HexBits(unsigned int nBits) return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); } +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(); @@ -126,11 +155,14 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) entry.push_back(Pair(item.first, item.second)); } -void TxToJSON(const CTransaction &tx, Object& entry) +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) { @@ -143,7 +175,18 @@ void TxToJSON(const CTransaction &tx, Object& entry) 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)); - in.push_back(Pair("scriptSig", txin.scriptSig.ToString())); + 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; + default: + throw JSONRPCError(-18, "Invalid script decomposition"); + } } in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence)); vin.push_back(in); @@ -154,12 +197,25 @@ void TxToJSON(const CTransaction &tx, Object& entry) { Object out; out.push_back(Pair("value", ValueFromAmount(txout.nValue))); - out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString())); + 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; + 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(); @@ -168,7 +224,7 @@ string AccountFromValue(const Value& value) return strAccount; } -Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) +Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const Object& decompositions) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); @@ -183,10 +239,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) 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))); - Array txhashes; - BOOST_FOREACH (const CTransaction&tx, block.vtx) - txhashes.push_back(tx.GetHash().GetHex()); - result.push_back(Pair("tx", txhashes)); + + 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())); @@ -197,6 +281,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) + /// /// Note: This interface may still be subject to change. /// @@ -1501,23 +1586,14 @@ Value listsinceblock(const Array& params, bool fHelp) return ret; } -Value gettransaction(const Array& params, bool fHelp) +void +AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions) { - if (fHelp || params.size() != 1) - throw runtime_error( - "gettransaction \n" - "Get detailed information about "); - - uint256 hash; - hash.SetHex(params[0].get_str()); - - Object entry; - if (pwalletMain->mapWallet.count(hash)) { const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - TxToJSON(wtx, entry); + TxToJSON(wtx, entry, decompositions); int64 nCredit = wtx.GetCredit(); int64 nDebit = wtx.GetDebit(); @@ -1538,10 +1614,12 @@ Value gettransaction(const Array& params, bool fHelp) { CTransaction tx; uint256 hashBlock = 0; - if (GetTransaction(hash, tx, hashBlock)) + if ((!ptx) && GetTransaction(hash, tx, hashBlock)) + ptx = &tx; + if (ptx) { entry.push_back(Pair("txid", hash.GetHex())); - TxToJSON(tx, entry); + TxToJSON(*ptx, entry, decompositions); if (hashBlock == 0) entry.push_back(Pair("confirmations", 0)); else @@ -1564,6 +1642,22 @@ Value gettransaction(const Array& params, bool fHelp) else throw JSONRPCError(-5, "No information available about transaction"); } +} + +Value gettransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "gettransaction [decompositions]\n" + "Get detailed information about "); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + Object entry; + + AnyTxToJSON(hash, NULL, entry, + (params.size() > 1) ? params[1].get_obj() : emptyobj); return entry; } @@ -2045,9 +2139,9 @@ Value getblockhash(const Array& params, bool fHelp) Value getblock(const Array& params, bool fHelp) { - if (fHelp || params.size() != 1) + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "getblock \n" + "getblock [decompositions]\n" "Returns details of a block with given block-hash."); std::string strHash = params[0].get_str(); @@ -2060,7 +2154,8 @@ Value getblock(const Array& params, bool fHelp) CBlockIndex* pblockindex = mapBlockIndex[hash]; block.ReadFromDisk(pblockindex, true); - return blockToJSON(block, pblockindex); + return blockToJSON(block, pblockindex, + (params.size() > 1) ? params[1].get_obj() : emptyobj); } @@ -2718,7 +2813,9 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector 0) ConvertTo(params[0]); if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo(params[1]); if (strMethod == "getbalance" && n > 1) ConvertTo(params[1]); + if (strMethod == "getblock" && n > 1) ConvertTo(params[1]); if (strMethod == "getblockhash" && n > 0) ConvertTo(params[0]); + if (strMethod == "gettransaction" && n > 1) ConvertTo(params[1]); if (strMethod == "move" && n > 2) ConvertTo(params[2]); if (strMethod == "move" && n > 3) ConvertTo(params[3]); if (strMethod == "sendfrom" && n > 2) ConvertTo(params[2]);