Merge pull request #886 from luke-jr/getblock_full

More details for getblock and gettransaction
This commit is contained in:
Gregory Maxwell 2012-05-08 15:31:52 -07:00
commit 82ab06b849

View File

@ -44,6 +44,8 @@ static CCriticalSection cs_nWalletUnlockTime;
extern Value dumpprivkey(const Array& params, bool fHelp); extern Value dumpprivkey(const Array& params, bool fHelp);
extern Value importprivkey(const Array& params, bool fHelp); extern Value importprivkey(const Array& params, bool fHelp);
const Object emptyobj;
Object JSONRPCError(int code, const string& message) Object JSONRPCError(int code, const string& message)
{ {
Object error; Object error;
@ -111,6 +113,33 @@ HexBits(unsigned int nBits)
return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); 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) void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
{ {
int confirms = wtx.GetDepthInMainChain(); int confirms = wtx.GetDepthInMainChain();
@ -126,11 +155,74 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
entry.push_back(Pair(item.first, item.second)); 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("version", tx.nVersion));
entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
enum DecomposeMode decomposeScript = FindDecompose(decompositions, "script", "asm");
Array vin; Array vin;
BOOST_FOREACH(const CTxIn& txin, tx.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("hash", txin.prevout.hash.GetHex()));
prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n)); prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n));
in.push_back(Pair("prevout", prevout)); 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())); 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)); in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
vin.push_back(in); vin.push_back(in);
@ -154,12 +264,32 @@ void TxToJSON(const CTransaction &tx, Object& entry)
{ {
Object out; Object out;
out.push_back(Pair("value", ValueFromAmount(txout.nValue))); 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())); 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); vout.push_back(out);
} }
entry.push_back(Pair("vout", vout)); 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 AccountFromValue(const Value& value)
{ {
string strAccount = value.get_str(); string strAccount = value.get_str();
@ -168,10 +298,13 @@ string AccountFromValue(const Value& value)
return strAccount; return strAccount;
} }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const Object& decompositions)
{ {
Object result; Object result;
result.push_back(Pair("hash", block.GetHash().GetHex())); 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("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion)); 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("nonce", (boost::uint64_t)block.nNonce));
result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("bits", HexBits(block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
Array txhashes;
enum DecomposeMode decomposeTxn = FindDecompose(decompositions, "tx", "hash");
if (decomposeTxn)
{
Array txs;
switch (decomposeTxn) {
case DM_OBJ:
BOOST_FOREACH (const CTransaction&tx, block.vtx) BOOST_FOREACH (const CTransaction&tx, block.vtx)
txhashes.push_back(tx.GetHash().GetHex()); {
result.push_back(Pair("tx", txhashes)); 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) if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); 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. /// Note: This interface may still be subject to change.
/// ///
@ -1498,23 +1660,14 @@ Value listsinceblock(const Array& params, bool fHelp)
return ret; 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)) if (pwalletMain->mapWallet.count(hash))
{ {
const CWalletTx& wtx = pwalletMain->mapWallet[hash]; const CWalletTx& wtx = pwalletMain->mapWallet[hash];
TxToJSON(wtx, entry); TxToJSON(wtx, entry, decompositions);
int64 nCredit = wtx.GetCredit(); int64 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit(); int64 nDebit = wtx.GetDebit();
@ -1535,10 +1688,12 @@ Value gettransaction(const Array& params, bool fHelp)
{ {
CTransaction tx; CTransaction tx;
uint256 hashBlock = 0; 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())); entry.push_back(Pair("txid", hash.GetHex()));
TxToJSON(tx, entry); TxToJSON(*ptx, entry, decompositions);
if (hashBlock == 0) if (hashBlock == 0)
entry.push_back(Pair("confirmations", 0)); entry.push_back(Pair("confirmations", 0));
else else
@ -1561,6 +1716,22 @@ Value gettransaction(const Array& params, bool fHelp)
else else
throw JSONRPCError(-5, "No information available about transaction"); 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; return entry;
} }
@ -2042,9 +2213,9 @@ Value getblockhash(const Array& params, bool fHelp)
Value getblock(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( throw runtime_error(
"getblock <hash>\n" "getblock <hash> [decompositions]\n"
"Returns details of a block with given block-hash."); "Returns details of a block with given block-hash.");
std::string strHash = params[0].get_str(); std::string strHash = params[0].get_str();
@ -2057,7 +2228,8 @@ Value getblock(const Array& params, bool fHelp)
CBlockIndex* pblockindex = mapBlockIndex[hash]; CBlockIndex* pblockindex = mapBlockIndex[hash];
block.ReadFromDisk(pblockindex, true); 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 > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]); if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(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 == "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 > 2) ConvertTo<double>(params[2]);
if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]); 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) ConvertTo<double>(params[2]);