aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Maxwell <gmaxwell@gmail.com>2012-05-08 15:31:52 -0700
committerGregory Maxwell <gmaxwell@gmail.com>2012-05-08 15:31:52 -0700
commit82ab06b84955f1e4b80b52eea8c089bb67d3de24 (patch)
treeb44f401de769944b82d70248748d25da932755f8
parentab89d75daf21a6529312d13e275ee3b2acf5d1a3 (diff)
parent7e63dc361512ccaeba5dd31e90549e2fe4d0c1a3 (diff)
Merge pull request #886 from luke-jr/getblock_full
More details for getblock and gettransaction
-rw-r--r--src/bitcoinrpc.cpp224
1 files changed, 199 insertions, 25 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 54bec8623d..a189b2b2b0 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,74 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
entry.push_back(Pair(item.first, item.second));
}
-void TxToJSON(const CTransaction &tx, Object& entry)
+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<CBitcoinAddress> addresses;
+ int nRequired;
+
+ if (!ExtractAddresses(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 CBitcoinAddress& addr, addresses)
+ a.push_back(addr.ToString());
+ out.push_back(Pair("addresses", a));
+}
+
+void
+ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
+{
+ txnouttype type;
+ vector<CBitcoinAddress> addresses;
+ int nRequired;
+
+ out.push_back(Pair("asm", scriptPubKey.ToString()));
+ out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
+
+ if (!ExtractAddresses(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 CBitcoinAddress& addr, addresses)
+ a.push_back(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)
{
@@ -143,7 +235,25 @@ 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;
+ 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);
@@ -154,12 +264,32 @@ 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;
+ 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();
@@ -168,10 +298,13 @@ 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()));
+ CMerkleTx txGen(block.vtx[0]);
+ txGen.SetMerkleBranch(&block);
+ result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
@@ -180,10 +313,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()));
@@ -194,6 +355,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
+
///
/// Note: This interface may still be subject to change.
///
@@ -1498,23 +1660,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 <txid>\n"
- "Get detailed information about <txid>");
-
- 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();
@@ -1535,10 +1688,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
@@ -1561,6 +1716,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 <txid> [decompositions]\n"
+ "Get detailed information about <txid>");
+
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+
+ Object entry;
+
+ AnyTxToJSON(hash, NULL, entry,
+ (params.size() > 1) ? params[1].get_obj() : emptyobj);
return entry;
}
@@ -2042,9 +2213,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 <hash>\n"
+ "getblock <hash> [decompositions]\n"
"Returns details of a block with given block-hash.");
std::string strHash = params[0].get_str();
@@ -2057,7 +2228,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);
}
@@ -2715,7 +2887,9 @@ 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]);