Skip to content

Commit 82ab06b

Browse files
committed
Merge pull request bitcoin-core#886 from luke-jr/getblock_full
More details for getblock and gettransaction
2 parents ab89d75 + 7e63dc3 commit 82ab06b

File tree

1 file changed

+199
-25
lines changed

1 file changed

+199
-25
lines changed

src/bitcoinrpc.cpp

Lines changed: 199 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ static CCriticalSection cs_nWalletUnlockTime;
4444
extern Value dumpprivkey(const Array& params, bool fHelp);
4545
extern Value importprivkey(const Array& params, bool fHelp);
4646

47+
const Object emptyobj;
48+
4749
Object JSONRPCError(int code, const string& message)
4850
{
4951
Object error;
@@ -111,6 +113,33 @@ HexBits(unsigned int nBits)
111113
return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
112114
}
113115

116+
enum DecomposeMode {
117+
DM_NONE = 0,
118+
DM_HASH,
119+
DM_HEX,
120+
DM_ASM,
121+
DM_OBJ,
122+
};
123+
124+
enum DecomposeMode
125+
FindDecompose(const Object& decompositions, const char* pcType, const char* pcDefault)
126+
{
127+
Value val = find_value(decompositions, pcType);
128+
std::string strDecompose = (val.type() == null_type) ? pcDefault : val.get_str();
129+
130+
if (strDecompose == "no")
131+
return DM_NONE;
132+
if (strDecompose == "hash")
133+
return DM_HASH;
134+
if (strDecompose == "hex")
135+
return DM_HEX;
136+
if (strDecompose == "asm")
137+
return DM_ASM;
138+
if (strDecompose == "obj")
139+
return DM_OBJ;
140+
throw JSONRPCError(-18, "Invalid decomposition");
141+
}
142+
114143
void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
115144
{
116145
int confirms = wtx.GetDepthInMainChain();
@@ -126,11 +155,74 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
126155
entry.push_back(Pair(item.first, item.second));
127156
}
128157

129-
void TxToJSON(const CTransaction &tx, Object& entry)
158+
void
159+
ScriptSigToJSON(const CTxIn& txin, Object& out)
160+
{
161+
out.push_back(Pair("asm", txin.scriptSig.ToString()));
162+
out.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
163+
164+
CTransaction txprev;
165+
uint256 hashTxprevBlock;
166+
if (!GetTransaction(txin.prevout.hash, txprev, hashTxprevBlock))
167+
return;
168+
169+
txnouttype type;
170+
vector<CBitcoinAddress> addresses;
171+
int nRequired;
172+
173+
if (!ExtractAddresses(txprev.vout[txin.prevout.n].scriptPubKey, type,
174+
addresses, nRequired))
175+
{
176+
out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
177+
return;
178+
}
179+
180+
out.push_back(Pair("type", GetTxnOutputType(type)));
181+
if (type == TX_MULTISIG)
182+
{
183+
// TODO: Need to handle this specially since not all input addresses are required...
184+
return;
185+
}
186+
187+
Array a;
188+
BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
189+
a.push_back(addr.ToString());
190+
out.push_back(Pair("addresses", a));
191+
}
192+
193+
void
194+
ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
195+
{
196+
txnouttype type;
197+
vector<CBitcoinAddress> addresses;
198+
int nRequired;
199+
200+
out.push_back(Pair("asm", scriptPubKey.ToString()));
201+
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
202+
203+
if (!ExtractAddresses(scriptPubKey, type, addresses, nRequired))
204+
{
205+
out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
206+
return;
207+
}
208+
209+
out.push_back(Pair("reqSigs", nRequired));
210+
out.push_back(Pair("type", GetTxnOutputType(type)));
211+
212+
Array a;
213+
BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
214+
a.push_back(addr.ToString());
215+
out.push_back(Pair("addresses", a));
216+
}
217+
218+
void TxToJSON(const CTransaction &tx, Object& entry, const Object& decompositions)
130219
{
131220
entry.push_back(Pair("version", tx.nVersion));
132221
entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
133222
entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
223+
224+
enum DecomposeMode decomposeScript = FindDecompose(decompositions, "script", "asm");
225+
134226
Array vin;
135227
BOOST_FOREACH(const CTxIn& txin, tx.vin)
136228
{
@@ -143,7 +235,25 @@ void TxToJSON(const CTransaction &tx, Object& entry)
143235
prevout.push_back(Pair("hash", txin.prevout.hash.GetHex()));
144236
prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n));
145237
in.push_back(Pair("prevout", prevout));
146-
in.push_back(Pair("scriptSig", txin.scriptSig.ToString()));
238+
switch (decomposeScript) {
239+
case DM_NONE:
240+
break;
241+
case DM_HEX:
242+
in.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
243+
break;
244+
case DM_ASM:
245+
in.push_back(Pair("scriptSig", txin.scriptSig.ToString()));
246+
break;
247+
case DM_OBJ:
248+
{
249+
Object o;
250+
ScriptSigToJSON(txin, o);
251+
in.push_back(Pair("scriptSig", o));
252+
break;
253+
}
254+
default:
255+
throw JSONRPCError(-18, "Invalid script decomposition");
256+
}
147257
}
148258
in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
149259
vin.push_back(in);
@@ -154,12 +264,32 @@ void TxToJSON(const CTransaction &tx, Object& entry)
154264
{
155265
Object out;
156266
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
157-
out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString()));
267+
switch (decomposeScript) {
268+
case DM_NONE:
269+
break;
270+
case DM_HEX:
271+
out.push_back(Pair("scriptPubKey", HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end())));
272+
break;
273+
case DM_ASM:
274+
out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString()));
275+
break;
276+
case DM_OBJ:
277+
{
278+
Object o;
279+
ScriptPubKeyToJSON(txout.scriptPubKey, o);
280+
out.push_back(Pair("scriptPubKey", o));
281+
break;
282+
}
283+
default:
284+
throw JSONRPCError(-18, "Invalid script decomposition");
285+
}
158286
vout.push_back(out);
159287
}
160288
entry.push_back(Pair("vout", vout));
161289
}
162290

291+
void AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions);
292+
163293
string AccountFromValue(const Value& value)
164294
{
165295
string strAccount = value.get_str();
@@ -168,10 +298,13 @@ string AccountFromValue(const Value& value)
168298
return strAccount;
169299
}
170300

171-
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
301+
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const Object& decompositions)
172302
{
173303
Object result;
174304
result.push_back(Pair("hash", block.GetHash().GetHex()));
305+
CMerkleTx txGen(block.vtx[0]);
306+
txGen.SetMerkleBranch(&block);
307+
result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
175308
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
176309
result.push_back(Pair("height", blockindex->nHeight));
177310
result.push_back(Pair("version", block.nVersion));
@@ -180,10 +313,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
180313
result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
181314
result.push_back(Pair("bits", HexBits(block.nBits)));
182315
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
183-
Array txhashes;
184-
BOOST_FOREACH (const CTransaction&tx, block.vtx)
185-
txhashes.push_back(tx.GetHash().GetHex());
186-
result.push_back(Pair("tx", txhashes));
316+
317+
enum DecomposeMode decomposeTxn = FindDecompose(decompositions, "tx", "hash");
318+
if (decomposeTxn)
319+
{
320+
Array txs;
321+
switch (decomposeTxn) {
322+
case DM_OBJ:
323+
BOOST_FOREACH (const CTransaction&tx, block.vtx)
324+
{
325+
Object entry;
326+
AnyTxToJSON(tx.GetHash(), &tx, entry, decompositions);
327+
txs.push_back(entry);
328+
}
329+
break;
330+
case DM_HEX:
331+
BOOST_FOREACH (const CTransaction&tx, block.vtx)
332+
{
333+
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
334+
ssTx << tx;
335+
336+
txs.push_back(HexStr(ssTx.begin(), ssTx.end()));
337+
}
338+
break;
339+
case DM_HASH:
340+
BOOST_FOREACH (const CTransaction&tx, block.vtx)
341+
txs.push_back(tx.GetHash().GetHex());
342+
break;
343+
default:
344+
throw JSONRPCError(-18, "Invalid transaction decomposition");
345+
}
346+
result.push_back(Pair("tx", txs));
347+
}
187348

188349
if (blockindex->pprev)
189350
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
@@ -194,6 +355,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
194355

195356

196357

358+
197359
///
198360
/// Note: This interface may still be subject to change.
199361
///
@@ -1498,23 +1660,14 @@ Value listsinceblock(const Array& params, bool fHelp)
14981660
return ret;
14991661
}
15001662

1501-
Value gettransaction(const Array& params, bool fHelp)
1663+
void
1664+
AnyTxToJSON(const uint256 hash, const CTransaction* ptx, Object& entry, const Object& decompositions)
15021665
{
1503-
if (fHelp || params.size() != 1)
1504-
throw runtime_error(
1505-
"gettransaction <txid>\n"
1506-
"Get detailed information about <txid>");
1507-
1508-
uint256 hash;
1509-
hash.SetHex(params[0].get_str());
1510-
1511-
Object entry;
1512-
15131666
if (pwalletMain->mapWallet.count(hash))
15141667
{
15151668
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
15161669

1517-
TxToJSON(wtx, entry);
1670+
TxToJSON(wtx, entry, decompositions);
15181671

15191672
int64 nCredit = wtx.GetCredit();
15201673
int64 nDebit = wtx.GetDebit();
@@ -1535,10 +1688,12 @@ Value gettransaction(const Array& params, bool fHelp)
15351688
{
15361689
CTransaction tx;
15371690
uint256 hashBlock = 0;
1538-
if (GetTransaction(hash, tx, hashBlock))
1691+
if ((!ptx) && GetTransaction(hash, tx, hashBlock))
1692+
ptx = &tx;
1693+
if (ptx)
15391694
{
15401695
entry.push_back(Pair("txid", hash.GetHex()));
1541-
TxToJSON(tx, entry);
1696+
TxToJSON(*ptx, entry, decompositions);
15421697
if (hashBlock == 0)
15431698
entry.push_back(Pair("confirmations", 0));
15441699
else
@@ -1561,6 +1716,22 @@ Value gettransaction(const Array& params, bool fHelp)
15611716
else
15621717
throw JSONRPCError(-5, "No information available about transaction");
15631718
}
1719+
}
1720+
1721+
Value gettransaction(const Array& params, bool fHelp)
1722+
{
1723+
if (fHelp || params.size() < 1 || params.size() > 2)
1724+
throw runtime_error(
1725+
"gettransaction <txid> [decompositions]\n"
1726+
"Get detailed information about <txid>");
1727+
1728+
uint256 hash;
1729+
hash.SetHex(params[0].get_str());
1730+
1731+
Object entry;
1732+
1733+
AnyTxToJSON(hash, NULL, entry,
1734+
(params.size() > 1) ? params[1].get_obj() : emptyobj);
15641735

15651736
return entry;
15661737
}
@@ -2042,9 +2213,9 @@ Value getblockhash(const Array& params, bool fHelp)
20422213

20432214
Value getblock(const Array& params, bool fHelp)
20442215
{
2045-
if (fHelp || params.size() != 1)
2216+
if (fHelp || params.size() < 1 || params.size() > 2)
20462217
throw runtime_error(
2047-
"getblock <hash>\n"
2218+
"getblock <hash> [decompositions]\n"
20482219
"Returns details of a block with given block-hash.");
20492220

20502221
std::string strHash = params[0].get_str();
@@ -2057,7 +2228,8 @@ Value getblock(const Array& params, bool fHelp)
20572228
CBlockIndex* pblockindex = mapBlockIndex[hash];
20582229
block.ReadFromDisk(pblockindex, true);
20592230

2060-
return blockToJSON(block, pblockindex);
2231+
return blockToJSON(block, pblockindex,
2232+
(params.size() > 1) ? params[1].get_obj() : emptyobj);
20612233
}
20622234

20632235

@@ -2715,7 +2887,9 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
27152887
if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
27162888
if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
27172889
if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2890+
if (strMethod == "getblock" && n > 1) ConvertTo<Object>(params[1]);
27182891
if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2892+
if (strMethod == "gettransaction" && n > 1) ConvertTo<Object>(params[1]);
27192893
if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
27202894
if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
27212895
if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);

0 commit comments

Comments
 (0)