Skip to content

Commit 03031a5

Browse files
ryanofskyrandom-zebra
authored andcommitted
Check FRESH validity in CCoinsViewCache::BatchWrite
1 parent 3fb3e03 commit 03031a5

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

src/coins.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlockIn
213213
entry.flags |= CCoinsCacheEntry::FRESH;
214214
}
215215
} else {
216+
// Assert that the child cache entry was not marked FRESH if the
217+
// parent cache entry has unspent outputs. If this ever happens,
218+
// it means the FRESH flag was misapplied and there is a logic
219+
// error in the calling code.
220+
if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coins.IsPruned())
221+
throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
222+
216223
// Found the entry in the parent cache
217224
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
218225
// The grandparent does not have an entry, and the child is

src/test/coins_tests.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -742,12 +742,18 @@ BOOST_AUTO_TEST_CASE(ccoins_modify_new)
742742
void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)
743743
{
744744
SingleEntryCacheTest test(ABSENT, parent_value, parent_flags);
745-
WriteCoinsViewEntry(test.cache, child_value, child_flags);
746-
test.cache.SelfTest();
747745

748746
CAmount result_value;
749747
char result_flags;
750-
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
748+
try {
749+
WriteCoinsViewEntry(test.cache, child_value, child_flags);
750+
test.cache.SelfTest();
751+
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
752+
} catch (std::logic_error& e) {
753+
result_value = FAIL;
754+
result_flags = NO_ENTRY;
755+
}
756+
751757
BOOST_CHECK_EQUAL(result_value, expected_value);
752758
BOOST_CHECK_EQUAL(result_flags, expected_flags);
753759
}
@@ -791,21 +797,21 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
791797
CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY , NO_ENTRY , DIRTY );
792798
CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY|FRESH, NO_ENTRY , DIRTY|FRESH);
793799
CheckWriteCoins(VALUE1, PRUNED, PRUNED, 0 , DIRTY , DIRTY );
794-
CheckWriteCoins(VALUE1, PRUNED, PRUNED, 0 , DIRTY|FRESH, DIRTY );
800+
CheckWriteCoins(VALUE1, PRUNED, FAIL , 0 , DIRTY|FRESH, NO_ENTRY );
795801
CheckWriteCoins(VALUE1, PRUNED, ABSENT, FRESH , DIRTY , NO_ENTRY );
796-
CheckWriteCoins(VALUE1, PRUNED, ABSENT, FRESH , DIRTY|FRESH, NO_ENTRY );
802+
CheckWriteCoins(VALUE1, PRUNED, FAIL , FRESH , DIRTY|FRESH, NO_ENTRY );
797803
CheckWriteCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY , DIRTY );
798-
CheckWriteCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY|FRESH, DIRTY );
804+
CheckWriteCoins(VALUE1, PRUNED, FAIL , DIRTY , DIRTY|FRESH, NO_ENTRY );
799805
CheckWriteCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, DIRTY , NO_ENTRY );
800-
CheckWriteCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
806+
CheckWriteCoins(VALUE1, PRUNED, FAIL , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
801807
CheckWriteCoins(VALUE1, VALUE2, VALUE2, 0 , DIRTY , DIRTY );
802-
CheckWriteCoins(VALUE1, VALUE2, VALUE2, 0 , DIRTY|FRESH, DIRTY );
808+
CheckWriteCoins(VALUE1, VALUE2, FAIL , 0 , DIRTY|FRESH, NO_ENTRY );
803809
CheckWriteCoins(VALUE1, VALUE2, VALUE2, FRESH , DIRTY , DIRTY|FRESH);
804-
CheckWriteCoins(VALUE1, VALUE2, VALUE2, FRESH , DIRTY|FRESH, DIRTY|FRESH);
810+
CheckWriteCoins(VALUE1, VALUE2, FAIL , FRESH , DIRTY|FRESH, NO_ENTRY );
805811
CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY , DIRTY );
806-
CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY|FRESH, DIRTY );
812+
CheckWriteCoins(VALUE1, VALUE2, FAIL , DIRTY , DIRTY|FRESH, NO_ENTRY );
807813
CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY , DIRTY|FRESH);
808-
CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH, DIRTY|FRESH);
814+
CheckWriteCoins(VALUE1, VALUE2, FAIL , DIRTY|FRESH, DIRTY|FRESH, NO_ENTRY );
809815

810816
// The checks above omit cases where the child flags are not DIRTY, since
811817
// they would be too repetitive (the parent cache is never updated in these

0 commit comments

Comments
 (0)