Skip to content

Commit 10baa70

Browse files
committed
error() in disconnect for disk corruption, not inconsistency
>>> backports bitcoin/bitcoin@f54580e The error() function unconditionally reports an error. It should only be used for actually exception situations, and not for the type of inconsistencies that ApplyTxInUndo/DisconnectBlock can graciously deal with. This also makes a subtle semantics change: in ApplyTxInUndo, when a record with metadata is encountered (indicating it is the last spend from a tx), don't wipe the CCoins record if it wasn't empty at that point. This makes sure that UTXO operations never affect any other UTXOs (including those from the same tx).
1 parent 802f8c8 commit 10baa70

File tree

2 files changed

+18
-21
lines changed

2 files changed

+18
-21
lines changed

src/main.cpp

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,46 +2023,43 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
20232023

20242024
} // anon namespace
20252025

2026+
enum DisconnectResult
2027+
{
2028+
DISCONNECT_OK, // All good.
2029+
DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
2030+
DISCONNECT_FAILED // Something else went wrong.
2031+
};
2032+
20262033
/**
20272034
* Apply the undo operation of a CTxInUndo to the given chain state.
20282035
* @param undo The undo object.
20292036
* @param view The coins view to which to apply the changes.
20302037
* @param out The out point that corresponds to the tx input.
2031-
* @return True on success.
2038+
* @return A DisconnectResult as an int
20322039
*/
2033-
bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
2040+
int ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
20342041
{
20352042
bool fClean = true;
20362043

20372044
CCoinsModifier coins = view.ModifyCoins(out.hash);
20382045
if (undo.nHeight != 0) {
20392046
// undo data contains height: this is the last output of the prevout tx being spent
2040-
if (!coins->IsPruned())
2041-
fClean = fClean && error("%s: undo data overwriting existing transaction", __func__);
2042-
coins->Clear();
2047+
if (!coins->IsPruned()) fClean = false; // overwriting existing transaction
20432048
coins->fCoinBase = undo.fCoinBase;
20442049
coins->fCoinStake = undo.fCoinStake;
20452050
coins->nHeight = undo.nHeight;
20462051
coins->nVersion = undo.nVersion;
20472052
} else {
2048-
if (coins->IsPruned())
2049-
fClean = fClean && error("%s: undo data adding output to missing transaction", __func__);
2053+
if (coins->IsPruned()) fClean = false; // adding output to missing transaction
20502054
}
2051-
if (coins->IsAvailable(out.n))
2052-
fClean = fClean && error("%s: undo data overwriting existing output", __func__);
2055+
if (coins->IsAvailable(out.n)) fClean = false; // overwriting existing output
20532056
if (coins->vout.size() < out.n+1)
20542057
coins->vout.resize(out.n+1);
20552058
coins->vout[out.n] = undo.txout;
20562059

2057-
return fClean;
2060+
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
20582061
}
20592062

2060-
enum DisconnectResult
2061-
{
2062-
DISCONNECT_OK, // All good.
2063-
DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
2064-
DISCONNECT_FAILED // Something else went wrong.
2065-
};
20662063

20672064
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
20682065
* When UNCLEAN or FAILED is returned, view is left in an indeterminate state. */
@@ -2123,8 +2120,7 @@ DisconnectResult DisconnectBlock(CBlock& block, CBlockIndex* pindex, CCoinsViewC
21232120
// but it must be corrected before txout nversion ever influences a network rule.
21242121
if (outsBlock.nVersion < 0)
21252122
outs->nVersion = outsBlock.nVersion;
2126-
if (*outs != outsBlock)
2127-
fClean = fClean && error("%s : added transaction mismatch? database corrupted", __func__);
2123+
if (*outs != outsBlock) fClean = false; // transaction mismatch
21282124

21292125
// remove outputs
21302126
outs->Clear();
@@ -2144,8 +2140,9 @@ DisconnectResult DisconnectBlock(CBlock& block, CBlockIndex* pindex, CCoinsViewC
21442140
for (unsigned int j = tx.vin.size(); j-- > 0;) {
21452141
const COutPoint& out = tx.vin[j].prevout;
21462142
const CTxInUndo& undo = txundo.vprevout[j];
2147-
if (!ApplyTxInUndo(undo, view, out))
2148-
fClean = false;
2143+
int res = ApplyTxInUndo(undo, view, out);
2144+
if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED;
2145+
fClean = fClean && res != DISCONNECT_UNCLEAN;
21492146
}
21502147

21512148
if (view.HaveInputs(tx))

src/test/coins_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#include <boost/test/unit_test.hpp>
1818

19-
bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out);
19+
int ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out);
2020
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
2121

2222
namespace

0 commit comments

Comments
 (0)