I've added a 'getrawtransactionsinblock' RPC command to bitcoind, in my local source code, and it seems like something that will be useful to other users, particularly if you're trying to split wallet functionality out of bitcoin core.
Is it worth me setting up a pull request for this?
The use case is that I want to scan the transactions in each block, as they come.
I can do this with getblock and a bunch of getrawtransaction calls, *if* txindex is set to 1.
But since I'm not looking up transactions at arbitrary positions in the block chain, I shouldn't need a full transaction index for this.
I know the hash of the block which contains the transactions, and it should then be possible to obtain the transaction information from this block, without a full transaction index.
The code for the new command is very straightforward, and this is essentially just the following, plus a couple of minor changes to make this available as an RPC command:
Value getrawtransactionsinblock(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1)
throw runtime_error(
"getrawtransactionsinblock \n"
"Returns txid and raw transaction data for all transactions in the specified block.\n"
"\nArguments:\n"
"1. \"hash\" (string, required) The block hash\n"
"\nResult\n"
"[ (array of json object)\n"
" {\n"
" \"txid\" : \"txid\", (string) the transaction id \n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("getrawtransactionsinblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getrawtransactionsinblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
);
std::string strHash = params[0].get_str();
uint256 hash(strHash);
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
ReadBlockFromDisk(block, pblockindex);
Array a;
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
Object txEntry;
txEntry.push_back(Pair("txid", tx.GetHash().GetHex()));
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
string strHex = HexStr(ssTx.begin(), ssTx.end());
txEntry.push_back(Pair("hex", strHex));
a.push_back(txEntry);
}
return a;
}
The name is quite long, but says what it does on the box.
(Could be shortened to something like 'getblocktransactions', I guess, but then it's less clear what it does exactly.
Another possibility could be to add the possibility to pass the containing blockhash in to getrawtransaction, I guess, and not require a full transaction index in this case.
That would be another way to avoid the need for a full transaction index in our use case, but is a lot less efficient because it requires a lot more RPC calls to get all the transactions.
Switching from getblock + getrawtransaction calls to getrawtransactionsinblock gave us quite a significant speedup.
Scanning all transactions as they come seems like it should be quite a common use case for things like wallets that use bitcoind as a backend for network management, and just returning all the transactions then does seem like a good efficient solution for this kind of stuff in general.
For info, we're using this custom method in the SwapBill protocol reference client (announcement thread here:
https://bitcointalksearch.org/topic/swapbill-embedded-protocol-preview-and-request-for-feedback-628547, client source code and readme on github here:
https://github.com/crispweed/swapbill), but it seems like this is quite a general requirement, and can be useful in a lot of other cases!
Thomas