You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge bitcoin#30410: rpc, rest: Improve block rpc error handling, check header before attempting to read block data.
6a1aa51 rpc: check block index before reading block / undo data (Martin Zumsande)
6cbf2e5 rpc: Improve gettxoutproof error when only header is available. (Martin Zumsande)
69fc867 test: add coverage to getblock and getblockstats (Martin Zumsande)
5290cbd rpc: Improve getblock / getblockstats error when only header is available. (Martin Zumsande)
e5b537b rest: improve error when only header of a block is available. (Martin Zumsande)
Pull request description:
Fixesbitcoin#20978
If a block was pruned, `getblock` already returns a specific error: "Block not available (pruned data)".
But if we haven't received the full block yet (e.g. in a race with block downloading after a new block was received headers-first, or during IBD) we just return an unspecific "Block not found on disk" error and log
`ERROR: ReadBlockFromDisk: OpenBlockFile failed for FlatFilePos(nFile=-1, nPos=0) `
which suggest something went wrong even though this is a completely normal and expected situation.
This PR improves the error message and stops calling `ReadRawBlockFromDisk()`, when we already know from the header that the block is not available on disk.
Similarly, it prevents all other rpcs from calling blockstorage read functions unless we expect the data to be there, so that `LogError()` will only be thrown when there is an actual file system problem.
I'm not completely sure if the cause is important enough to change the wording of the rpc error, that some scripts may rely on.
If reviewers prefer it, an alternative solution would be to keep returning the current "Block not found on disk" error, but return it immediately instead of calling `ReadRawBlockFromDisk`, which would at least prevent the log error and also be an improvement in my opinion.
ACKs for top commit:
fjahr:
re-ACK 6a1aa51
achow101:
ACK 6a1aa51
andrewtoth:
re-ACK 6a1aa51
Tree-SHA512: 491aef880e8298a05841c4bf8eb913ef84820d1ad5415fd17d9b441bff181959ebfdd432b5eb8347dc9c568433f9a2384ca9d84cd72c79d8a58323ca117538fe
if (have_undo && !blockman.UndoReadFromDisk(blockUndo, blockindex)) {
206
+
throwJSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
207
+
}
206
208
for (size_t i = 0; i < block.vtx.size(); ++i) {
207
209
const CTransactionRef& tx = block.vtx.at(i);
208
210
// coinbase transaction (i.e. i == 0) doesn't have undo data
if (!chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex)) {
413
+
throwJSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
414
+
}
415
+
if (!chainman.m_blockman.ReadBlockFromDisk(block, *blockindex)) {
416
+
throwJSONRPCError(RPC_INTERNAL_ERROR, "Block data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
417
+
}
413
418
414
419
CTxUndo* undoTX {nullptr};
415
420
auto it = std::find_if(block.vtx.begin(), block.vtx.end(), [tx](CTransactionRef t){ return *t == *tx; });
# Move instead of deleting so we can restore chain state afterwards
623
625
move_block_file('rev00000.dat', 'rev_wrong')
624
626
625
-
assert_fee_not_in_block(2)
626
-
assert_fee_not_in_block(3)
627
-
assert_vin_does_not_contain_prevout(2)
628
-
assert_vin_does_not_contain_prevout(3)
627
+
assert_raises_rpc_error(-32603, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.", lambda: node.getblock(blockhash, 2))
628
+
assert_raises_rpc_error(-32603, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.", lambda: node.getblock(blockhash, 3))
0 commit comments