Skip to content

Commit 1b36e2c

Browse files
author
Braydon Fuller
committed
rpc: minimize locking in getrawtransaction
since there is i/o that can happen when retrieving extended input and output information, limiting the duration of the lock in getrawtransaction can help improve concurrency
1 parent de05c9e commit 1b36e2c

File tree

1 file changed

+86
-6
lines changed

1 file changed

+86
-6
lines changed

src/rpcrawtransaction.cpp

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud
5959
out.push_back(Pair("addresses", a));
6060
}
6161

62-
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
62+
void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& entry,
63+
int nHeight = 0, int nConfirmations = 0, int nBlockTime = 0)
6364
{
65+
6466
uint256 txid = tx.GetHash();
6567
entry.push_back(Pair("txid", txid.GetHex()));
6668
entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
@@ -121,6 +123,63 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
121123
}
122124
entry.push_back(Pair("vout", vout));
123125

126+
if (!hashBlock.IsNull()) {
127+
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
128+
129+
if (nConfirmations > 0) {
130+
entry.push_back(Pair("height", nHeight));
131+
entry.push_back(Pair("confirmations", nConfirmations));
132+
entry.push_back(Pair("time", nBlockTime));
133+
entry.push_back(Pair("blocktime", nBlockTime));
134+
} else {
135+
entry.push_back(Pair("height", -1));
136+
entry.push_back(Pair("confirmations", 0));
137+
}
138+
}
139+
140+
}
141+
142+
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
143+
{
144+
145+
uint256 txid = tx.GetHash();
146+
entry.push_back(Pair("txid", txid.GetHex()));
147+
entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
148+
entry.push_back(Pair("version", tx.nVersion));
149+
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
150+
151+
UniValue vin(UniValue::VARR);
152+
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
153+
UniValue in(UniValue::VOBJ);
154+
if (tx.IsCoinBase())
155+
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
156+
else {
157+
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
158+
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
159+
UniValue o(UniValue::VOBJ);
160+
o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
161+
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
162+
in.push_back(Pair("scriptSig", o));
163+
}
164+
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
165+
vin.push_back(in);
166+
}
167+
entry.push_back(Pair("vin", vin));
168+
169+
UniValue vout(UniValue::VARR);
170+
for (unsigned int i = 0; i < tx.vout.size(); i++) {
171+
const CTxOut& txout = tx.vout[i];
172+
UniValue out(UniValue::VOBJ);
173+
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
174+
out.push_back(Pair("valueSat", txout.nValue));
175+
out.push_back(Pair("n", (int64_t)i));
176+
UniValue o(UniValue::VOBJ);
177+
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
178+
out.push_back(Pair("scriptPubKey", o));
179+
vout.push_back(out);
180+
}
181+
entry.push_back(Pair("vout", vout));
182+
124183
if (!hashBlock.IsNull()) {
125184
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
126185
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
@@ -206,18 +265,38 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
206265
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
207266
);
208267

209-
LOCK(cs_main);
210-
211268
uint256 hash = ParseHashV(params[0], "parameter 1");
212269

213270
bool fVerbose = false;
214271
if (params.size() > 1)
215272
fVerbose = (params[1].get_int() != 0);
216273

217274
CTransaction tx;
275+
218276
uint256 hashBlock;
219-
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
220-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
277+
int nHeight = 0;
278+
int nConfirmations = 0;
279+
int nBlockTime = 0;
280+
281+
{
282+
LOCK(cs_main);
283+
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
284+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
285+
286+
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
287+
if (mi != mapBlockIndex.end() && (*mi).second) {
288+
CBlockIndex* pindex = (*mi).second;
289+
if (chainActive.Contains(pindex)) {
290+
nHeight = pindex->nHeight;
291+
nConfirmations = 1 + chainActive.Height() - pindex->nHeight;
292+
nBlockTime = pindex->GetBlockTime();
293+
} else {
294+
nHeight = -1;
295+
nConfirmations = 0;
296+
nBlockTime = pindex->GetBlockTime();
297+
}
298+
}
299+
}
221300

222301
string strHex = EncodeHexTx(tx);
223302

@@ -226,7 +305,8 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
226305

227306
UniValue result(UniValue::VOBJ);
228307
result.push_back(Pair("hex", strHex));
229-
TxToJSON(tx, hashBlock, result);
308+
TxToJSONExpanded(tx, hashBlock, result, nHeight, nConfirmations, nBlockTime);
309+
230310
return result;
231311
}
232312

0 commit comments

Comments
 (0)