Skip to content

Commit dde7ac5

Browse files
committed
Merge bitcoin/bitcoin#29003: rpc: fix getrawtransaction segfault
9075a44 test: add regression test for the getrawtransaction segfault (Martin Zumsande) 494a926 rpc: fix getrawtransaction segfault (Martin Zumsande) Pull request description: The crash, reported in #28986, happens when calling `getrawtransaction` for any mempool transaction with `verbosity=2`, while pruning, because the rpc calls `IsBlockPruned(const CBlockIndex* pblockindex)`, which dereferences `pblockindex` without a check. For ease of backporting this PR fixes it just locally in `rpc/rawtransaction.cpp` by moving the check for`!blockindex` up so that `IsBlockPruned()` will not be called with a `nullptr`. We might also want to change `IsBlockPruned()` so it doesn't crash when called with a `nullptr`, but I didn't do that here. Fixes #28986 ACKs for top commit: maflcko: lgtm test-was-added ACK 9075a44 theStack: Tested ACK 9075a44 Tree-SHA512: 0f7ed52579487196c206e16b45582b64e4b02ecf2a2eb0a31d2f3b52415bc9c64278cb94259314ef14ab7fb393c6195f79b3027d6de471d67614e51474498b11
2 parents d854914 + 9075a44 commit dde7ac5

File tree

2 files changed

+13
-5
lines changed

2 files changed

+13
-5
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ static RPCHelpMan getrawtransaction()
396396
LOCK(cs_main);
397397
blockindex = chainman.m_blockman.LookupBlockIndex(hash_block);
398398
}
399-
if (verbosity == 1) {
399+
if (verbosity == 1 || !blockindex) {
400400
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
401401
return result;
402402
}
@@ -405,8 +405,7 @@ static RPCHelpMan getrawtransaction()
405405
CBlock block;
406406
const bool is_block_pruned{WITH_LOCK(cs_main, return chainman.m_blockman.IsBlockPruned(blockindex))};
407407

408-
if (tx->IsCoinBase() ||
409-
!blockindex || is_block_pruned ||
408+
if (tx->IsCoinBase() || is_block_pruned ||
410409
!(chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex) && chainman.m_blockman.ReadBlockFromDisk(block, *blockindex))) {
411410
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
412411
return result;

test/functional/rpc_rawtransaction.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from test_framework.test_framework import BitcoinTestFramework
3333
from test_framework.util import (
3434
assert_equal,
35+
assert_greater_than,
3536
assert_raises_rpc_error,
3637
)
3738
from test_framework.wallet import (
@@ -70,7 +71,7 @@ def set_test_params(self):
7071
self.extra_args = [
7172
["-txindex"],
7273
["-txindex"],
73-
[],
74+
["-fastprune", "-prune=1"],
7475
]
7576
# whitelist all peers to speed up tx relay / mempool sync
7677
for args in self.extra_args:
@@ -85,7 +86,6 @@ def run_test(self):
8586
self.wallet = MiniWallet(self.nodes[0])
8687

8788
self.getrawtransaction_tests()
88-
self.getrawtransaction_verbosity_tests()
8989
self.createrawtransaction_tests()
9090
self.sendrawtransaction_tests()
9191
self.sendrawtransaction_testmempoolaccept_tests()
@@ -94,6 +94,8 @@ def run_test(self):
9494
if self.is_specified_wallet_compiled() and not self.options.descriptors:
9595
self.import_deterministic_coinbase_privkeys()
9696
self.raw_multisig_transaction_legacy_tests()
97+
self.getrawtransaction_verbosity_tests()
98+
9799

98100
def getrawtransaction_tests(self):
99101
tx = self.wallet.send_self_transfer(from_node=self.nodes[0])
@@ -243,6 +245,13 @@ def getrawtransaction_verbosity_tests(self):
243245
coin_base = self.nodes[1].getblock(block1)['tx'][0]
244246
gottx = self.nodes[1].getrawtransaction(txid=coin_base, verbosity=2, blockhash=block1)
245247
assert 'fee' not in gottx
248+
# check that verbosity 2 for a mempool tx will fallback to verbosity 1
249+
# Do this with a pruned chain, as a regression test for https://github.com/bitcoin/bitcoin/pull/29003
250+
self.generate(self.nodes[2], 400)
251+
assert_greater_than(self.nodes[2].pruneblockchain(250), 0)
252+
mempool_tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']
253+
gottx = self.nodes[2].getrawtransaction(txid=mempool_tx, verbosity=2)
254+
assert 'fee' not in gottx
246255

247256
def createrawtransaction_tests(self):
248257
self.log.info("Test createrawtransaction")

0 commit comments

Comments
 (0)