Page MenuHomePhabricator

D515.diff
No OneTemporary

D515.diff

diff --git a/src/coins.h b/src/coins.h
--- a/src/coins.h
+++ b/src/coins.h
@@ -70,235 +70,6 @@
}
};
-/**
- * Pruned version of CTransaction: only retains metadata and unspent transaction outputs
- *
- * Serialized format:
- * - VARINT(nVersion) - DEPRECATED, always zero on new reccords.
- * - VARINT(nCode)
- * - unspentness bitvector, for vout[2] and further; least significant byte first
- * - the non-spent CTxOuts (via CTxOutCompressor)
- * - VARINT(nHeight)
- *
- * The nCode value consists of:
- * - bit 0: IsCoinBase()
- * - bit 1: vout[0] is not spent
- * - bit 2: vout[1] is not spent
- * - The higher bits encode N, the number of non-zero bytes in the following bitvector.
- * - In case both bit 1 and bit 2 are unset, they encode N-1, as there must be at
- * least one non-spent output).
- *
- * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e
- * <><><--------------------------------------------><---->
- * | \ | /
- * version code vout[1] height
- *
- * - version = 1
- * - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
- * - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
- * - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
- * * 8358: compact amount representation for 60000000000 (600 BCC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
- * - height = 203998
- *
- *
- * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b
- * <><><--><--------------------------------------------------><----------------------------------------------><---->
- * / \ \ | | /
- * version code unspentness vout[4] vout[16] height
- *
- * - version = 1
- * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
- * 2 (1, +1 because both bit 1 and bit 2 are unset) non-zero bitvector bytes follow)
- * - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
- * - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
- * * 86ef97d579: compact amount representation for 234925952 (2.35 BCC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160
- * - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
- * * bbd123: compact amount representation for 110397 (0.001 BCC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
- * - height = 120891
- *
- * @DISABLE FORMATING FOR THIS COMMENT@
- */
-class CCoins {
-public:
- //! whether transaction is a coinbase
- bool fCoinBase;
-
- //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs
- //! at the end of the array are dropped
- std::vector<CTxOut> vout;
-
- //! at which height this transaction was included in the active block chain
- int nHeight;
-
- void FromTx(const CTransaction &tx, int nHeightIn) {
- fCoinBase = tx.IsCoinBase();
- vout = tx.vout;
- nHeight = nHeightIn;
- ClearUnspendable();
- }
-
- //! construct a CCoins from a CTransaction, at a given height
- CCoins(const CTransaction &tx, int nHeightIn) { FromTx(tx, nHeightIn); }
-
- void Clear() {
- fCoinBase = false;
- std::vector<CTxOut>().swap(vout);
- nHeight = 0;
- }
-
- //! empty constructor
- CCoins() : fCoinBase(false), vout(0), nHeight(0) {}
-
- //! remove spent outputs at the end of vout
- void Cleanup() {
- while (vout.size() > 0 && vout.back().IsNull()) {
- vout.pop_back();
- }
-
- if (vout.empty()) {
- std::vector<CTxOut>().swap(vout);
- }
- }
-
- void ClearUnspendable() {
- for (CTxOut &txout : vout) {
- if (txout.scriptPubKey.IsUnspendable()) {
- txout.SetNull();
- }
- }
-
- Cleanup();
- }
-
- void swap(CCoins &to) {
- std::swap(to.fCoinBase, fCoinBase);
- to.vout.swap(vout);
- std::swap(to.nHeight, nHeight);
- }
-
- //! equality test
- friend bool operator==(const CCoins &a, const CCoins &b) {
- // Empty CCoins objects are always equal.
- if (a.IsPruned() && b.IsPruned()) {
- return true;
- }
-
- return a.fCoinBase == b.fCoinBase && a.nHeight == b.nHeight &&
- a.vout == b.vout;
- }
-
- friend bool operator!=(const CCoins &a, const CCoins &b) {
- return !(a == b);
- }
-
- void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const;
-
- bool IsCoinBase() const { return fCoinBase; }
-
- template <typename Stream> void Serialize(Stream &s) const {
- unsigned int nMaskSize = 0, nMaskCode = 0;
- CalcMaskSize(nMaskSize, nMaskCode);
- bool fFirst = vout.size() > 0 && !vout[0].IsNull();
- bool fSecond = vout.size() > 1 && !vout[1].IsNull();
- assert(fFirst || fSecond || nMaskCode);
- unsigned int nCode = 8 * (nMaskCode - (fFirst || fSecond ? 0 : 1)) +
- (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) +
- (fSecond ? 4 : 0);
- // version
- int nVersionDummy = 0;
- ::Serialize(s, VARINT(nVersionDummy));
- // header code
- ::Serialize(s, VARINT(nCode));
- // spentness bitmask
- for (unsigned int b = 0; b < nMaskSize; b++) {
- uint8_t chAvail = 0;
- for (size_t i = 0; i < 8 && 2 + b * 8 + i < vout.size(); i++) {
- if (!vout[2 + b * 8 + i].IsNull()) {
- chAvail |= (1 << i);
- }
- }
- ::Serialize(s, chAvail);
- }
- // txouts themself
- for (unsigned int i = 0; i < vout.size(); i++) {
- if (!vout[i].IsNull()) {
- ::Serialize(s, CTxOutCompressor(REF(vout[i])));
- }
- }
- // coinbase height
- ::Serialize(s, VARINT(nHeight));
- }
-
- template <typename Stream> void Unserialize(Stream &s) {
- unsigned int nCode = 0;
- // version
- int nVersionDummy;
- ::Unserialize(s, VARINT(nVersionDummy));
- // header code
- ::Unserialize(s, VARINT(nCode));
- fCoinBase = nCode & 1;
- std::vector<bool> vAvail(2, false);
- vAvail[0] = (nCode & 2) != 0;
- vAvail[1] = (nCode & 4) != 0;
- unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
- // spentness bitmask
- while (nMaskCode > 0) {
- uint8_t chAvail = 0;
- ::Unserialize(s, chAvail);
- for (unsigned int p = 0; p < 8; p++) {
- bool f = (chAvail & (1 << p)) != 0;
- vAvail.push_back(f);
- }
- if (chAvail != 0) {
- nMaskCode--;
- }
- }
- // txouts themself
- vout.assign(vAvail.size(), CTxOut());
- for (unsigned int i = 0; i < vAvail.size(); i++) {
- if (vAvail[i]) {
- ::Unserialize(s, REF(CTxOutCompressor(vout[i])));
- }
- }
- // coinbase height
- ::Unserialize(s, VARINT(nHeight));
- Cleanup();
- }
-
- //! mark a vout spent
- bool Spend(uint32_t nPos);
-
- //! check whether a particular output is still available
- bool IsAvailable(unsigned int nPos) const {
- return (nPos < vout.size() && !vout[nPos].IsNull());
- }
-
- //! check whether the entire CCoins is spent
- //! note that only !IsPruned() CCoins can be serialized
- bool IsPruned() const {
- for (const CTxOut &out : vout) {
- if (!out.IsNull()) {
- return false;
- }
- }
- return true;
- }
-
- size_t DynamicMemoryUsage() const {
- size_t ret = memusage::DynamicUsage(vout);
- for (const CTxOut &out : vout) {
- ret += RecursiveDynamicUsage(out.scriptPubKey);
- }
- return ret;
- }
-};
-
class SaltedOutpointHasher {
private:
/** Salt */
diff --git a/src/coins.cpp b/src/coins.cpp
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -10,37 +10,6 @@
#include <cassert>
-/**
- * calculate number of bytes for the bitmask, and its number of non-zero bytes
- * each bit in the bitmask represents the availability of one output, but the
- * availabilities of the first two outputs are encoded separately
- */
-void CCoins::CalcMaskSize(unsigned int &nBytes,
- unsigned int &nNonzeroBytes) const {
- unsigned int nLastUsedByte = 0;
- for (unsigned int b = 0; 2 + b * 8 < vout.size(); b++) {
- bool fZero = true;
- for (unsigned int i = 0; i < 8 && 2 + b * 8 + i < vout.size(); i++) {
- if (!vout[2 + b * 8 + i].IsNull()) {
- fZero = false;
- continue;
- }
- }
- if (!fZero) {
- nLastUsedByte = b + 1;
- nNonzeroBytes++;
- }
- }
- nBytes += nLastUsedByte;
-}
-
-bool CCoins::Spend(uint32_t nPos) {
- if (nPos >= vout.size() || vout[nPos].IsNull()) return false;
- vout[nPos].SetNull();
- Cleanup();
- return true;
-}
-
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const {
return false;
}
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -548,82 +548,6 @@
}
}
-BOOST_AUTO_TEST_CASE(ccoins_serialization) {
- // Good example
- CDataStream ss1(
- ParseHex("0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e"),
- SER_DISK, CLIENT_VERSION);
- CCoins cc1;
- ss1 >> cc1;
- BOOST_CHECK_EQUAL(cc1.fCoinBase, false);
- BOOST_CHECK_EQUAL(cc1.nHeight, 203998);
- BOOST_CHECK_EQUAL(cc1.vout.size(), 2);
- BOOST_CHECK_EQUAL(cc1.IsAvailable(0), false);
- BOOST_CHECK_EQUAL(cc1.IsAvailable(1), true);
- BOOST_CHECK_EQUAL(cc1.vout[1].nValue, 60000000000ULL);
- BOOST_CHECK_EQUAL(HexStr(cc1.vout[1].scriptPubKey),
- HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex(
- "816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
-
- // Good example
- CDataStream ss2(
- ParseHex("0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eeb"
- "bd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b"),
- SER_DISK, CLIENT_VERSION);
- CCoins cc2;
- ss2 >> cc2;
- BOOST_CHECK_EQUAL(cc2.fCoinBase, true);
- BOOST_CHECK_EQUAL(cc2.nHeight, 120891);
- BOOST_CHECK_EQUAL(cc2.vout.size(), 17);
- for (int i = 0; i < 17; i++) {
- BOOST_CHECK_EQUAL(cc2.IsAvailable(i), i == 4 || i == 16);
- }
- BOOST_CHECK_EQUAL(cc2.vout[4].nValue, 234925952);
- BOOST_CHECK_EQUAL(HexStr(cc2.vout[4].scriptPubKey),
- HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex(
- "61b01caab50f1b8e9c50a5057eb43c2d9563a4ee"))))));
- BOOST_CHECK_EQUAL(cc2.vout[16].nValue, 110397);
- BOOST_CHECK_EQUAL(HexStr(cc2.vout[16].scriptPubKey),
- HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex(
- "8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
-
- // Smallest possible example
- CDataStream ssx(SER_DISK, CLIENT_VERSION);
- BOOST_CHECK_EQUAL(HexStr(ssx.begin(), ssx.end()), "");
-
- CDataStream ss3(ParseHex("0002000600"), SER_DISK, CLIENT_VERSION);
- CCoins cc3;
- ss3 >> cc3;
- BOOST_CHECK_EQUAL(cc3.fCoinBase, false);
- BOOST_CHECK_EQUAL(cc3.nHeight, 0);
- BOOST_CHECK_EQUAL(cc3.vout.size(), 1);
- BOOST_CHECK_EQUAL(cc3.IsAvailable(0), true);
- BOOST_CHECK_EQUAL(cc3.vout[0].nValue, 0);
- BOOST_CHECK_EQUAL(cc3.vout[0].scriptPubKey.size(), 0);
-
- // scriptPubKey that ends beyond the end of the stream
- CDataStream ss4(ParseHex("0002000800"), SER_DISK, CLIENT_VERSION);
- try {
- CCoins cc4;
- ss4 >> cc4;
- BOOST_CHECK_MESSAGE(false, "We should have thrown");
- } catch (const std::ios_base::failure &e) {
- }
-
- // Very large scriptPubKey (3*10^9 bytes) past the end of the stream
- CDataStream tmp(SER_DISK, CLIENT_VERSION);
- uint64_t x = 3000000000ULL;
- tmp << VARINT(x);
- BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00");
- CDataStream ss5(ParseHex("0002008a95c0bb0000"), SER_DISK, CLIENT_VERSION);
- try {
- CCoins cc5;
- ss5 >> cc5;
- BOOST_CHECK_MESSAGE(false, "We should have thrown");
- } catch (const std::ios_base::failure &e) {
- }
-}
-
static const COutPoint OUTPOINT;
static const CAmount PRUNED = -1;
static const CAmount ABSENT = -2;
@@ -639,7 +563,7 @@
static const auto CLEAN_FLAGS = {char(0), FRESH};
static const auto ABSENT_FLAGS = {NO_ENTRY};
-void SetCoinsValue(CAmount value, Coin &coin) {
+static void SetCoinValue(CAmount value, Coin &coin) {
assert(value != ABSENT);
coin.Clear();
assert(coin.IsSpent());
@@ -651,7 +575,7 @@
}
}
-size_t InsertCoinsMapEntry(CCoinsMap &map, CAmount value, char flags) {
+size_t InsertCoinMapEntry(CCoinsMap &map, CAmount value, char flags) {
if (value == ABSENT) {
assert(flags == NO_ENTRY);
return 0;
@@ -659,13 +583,13 @@
assert(flags != NO_ENTRY);
CCoinsCacheEntry entry;
entry.flags = flags;
- SetCoinsValue(value, entry.coin);
+ SetCoinValue(value, entry.coin);
auto inserted = map.emplace(OUTPOINT, std::move(entry));
assert(inserted.second);
return inserted.first->second.coin.DynamicMemoryUsage();
}
-void GetCoinsMapEntry(const CCoinsMap &map, CAmount &value, char &flags) {
+void GetCoinMapEntry(const CCoinsMap &map, CAmount &value, char &flags) {
auto it = map.find(OUTPOINT);
if (it == map.end()) {
value = ABSENT;
@@ -681,9 +605,9 @@
}
}
-void WriteCoinsViewEntry(CCoinsView &view, CAmount value, char flags) {
+void WriteCoinViewEntry(CCoinsView &view, CAmount value, char flags) {
CCoinsMap map;
- InsertCoinsMapEntry(map, value, flags);
+ InsertCoinMapEntry(map, value, flags);
view.BatchWrite(map, {});
}
@@ -691,10 +615,10 @@
public:
SingleEntryCacheTest(CAmount base_value, CAmount cache_value,
char cache_flags) {
- WriteCoinsViewEntry(base, base_value,
- base_value == ABSENT ? NO_ENTRY : DIRTY);
+ WriteCoinViewEntry(base, base_value,
+ base_value == ABSENT ? NO_ENTRY : DIRTY);
cache.usage() +=
- InsertCoinsMapEntry(cache.map(), cache_value, cache_flags);
+ InsertCoinMapEntry(cache.map(), cache_value, cache_flags);
}
CCoinsView root;
@@ -711,7 +635,7 @@
CAmount result_value;
char result_flags;
- GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ GetCoinMapEntry(test.cache.map(), result_value, result_flags);
BOOST_CHECK_EQUAL(result_value, expected_value);
BOOST_CHECK_EQUAL(result_flags, expected_flags);
}
@@ -753,16 +677,16 @@
CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH);
}
-void CheckSpendCoins(CAmount base_value, CAmount cache_value,
- CAmount expected_value, char cache_flags,
- char expected_flags) {
+void CheckSpendCoin(CAmount base_value, CAmount cache_value,
+ CAmount expected_value, char cache_flags,
+ char expected_flags) {
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
test.cache.SpendCoin(OUTPOINT);
test.cache.SelfTest();
CAmount result_value;
char result_flags;
- GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ GetCoinMapEntry(test.cache.map(), result_value, result_flags);
BOOST_CHECK_EQUAL(result_value, expected_value);
BOOST_CHECK_EQUAL(result_flags, expected_flags);
};
@@ -776,33 +700,33 @@
* Base Cache Result Cache Result
* Value Value Value Flags Flags
*/
- CheckSpendCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
- CheckSpendCoins(ABSENT, PRUNED, PRUNED, 0, DIRTY);
- CheckSpendCoins(ABSENT, PRUNED, ABSENT, FRESH, NO_ENTRY);
- CheckSpendCoins(ABSENT, PRUNED, PRUNED, DIRTY, DIRTY);
- CheckSpendCoins(ABSENT, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY);
- CheckSpendCoins(ABSENT, VALUE2, PRUNED, 0, DIRTY);
- CheckSpendCoins(ABSENT, VALUE2, ABSENT, FRESH, NO_ENTRY);
- CheckSpendCoins(ABSENT, VALUE2, PRUNED, DIRTY, DIRTY);
- CheckSpendCoins(ABSENT, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
- CheckSpendCoins(PRUNED, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
- CheckSpendCoins(PRUNED, PRUNED, PRUNED, 0, DIRTY);
- CheckSpendCoins(PRUNED, PRUNED, ABSENT, FRESH, NO_ENTRY);
- CheckSpendCoins(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY);
- CheckSpendCoins(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY);
- CheckSpendCoins(PRUNED, VALUE2, PRUNED, 0, DIRTY);
- CheckSpendCoins(PRUNED, VALUE2, ABSENT, FRESH, NO_ENTRY);
- CheckSpendCoins(PRUNED, VALUE2, PRUNED, DIRTY, DIRTY);
- CheckSpendCoins(PRUNED, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
- CheckSpendCoins(VALUE1, ABSENT, PRUNED, NO_ENTRY, DIRTY);
- CheckSpendCoins(VALUE1, PRUNED, PRUNED, 0, DIRTY);
- CheckSpendCoins(VALUE1, PRUNED, ABSENT, FRESH, NO_ENTRY);
- CheckSpendCoins(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY);
- CheckSpendCoins(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY);
- CheckSpendCoins(VALUE1, VALUE2, PRUNED, 0, DIRTY);
- CheckSpendCoins(VALUE1, VALUE2, ABSENT, FRESH, NO_ENTRY);
- CheckSpendCoins(VALUE1, VALUE2, PRUNED, DIRTY, DIRTY);
- CheckSpendCoins(VALUE1, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
+ CheckSpendCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
+ CheckSpendCoin(ABSENT, PRUNED, PRUNED, 0, DIRTY);
+ CheckSpendCoin(ABSENT, PRUNED, ABSENT, FRESH, NO_ENTRY);
+ CheckSpendCoin(ABSENT, PRUNED, PRUNED, DIRTY, DIRTY);
+ CheckSpendCoin(ABSENT, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY);
+ CheckSpendCoin(ABSENT, VALUE2, PRUNED, 0, DIRTY);
+ CheckSpendCoin(ABSENT, VALUE2, ABSENT, FRESH, NO_ENTRY);
+ CheckSpendCoin(ABSENT, VALUE2, PRUNED, DIRTY, DIRTY);
+ CheckSpendCoin(ABSENT, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
+ CheckSpendCoin(PRUNED, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
+ CheckSpendCoin(PRUNED, PRUNED, PRUNED, 0, DIRTY);
+ CheckSpendCoin(PRUNED, PRUNED, ABSENT, FRESH, NO_ENTRY);
+ CheckSpendCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY);
+ CheckSpendCoin(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY);
+ CheckSpendCoin(PRUNED, VALUE2, PRUNED, 0, DIRTY);
+ CheckSpendCoin(PRUNED, VALUE2, ABSENT, FRESH, NO_ENTRY);
+ CheckSpendCoin(PRUNED, VALUE2, PRUNED, DIRTY, DIRTY);
+ CheckSpendCoin(PRUNED, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
+ CheckSpendCoin(VALUE1, ABSENT, PRUNED, NO_ENTRY, DIRTY);
+ CheckSpendCoin(VALUE1, PRUNED, PRUNED, 0, DIRTY);
+ CheckSpendCoin(VALUE1, PRUNED, ABSENT, FRESH, NO_ENTRY);
+ CheckSpendCoin(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY);
+ CheckSpendCoin(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY);
+ CheckSpendCoin(VALUE1, VALUE2, PRUNED, 0, DIRTY);
+ CheckSpendCoin(VALUE1, VALUE2, ABSENT, FRESH, NO_ENTRY);
+ CheckSpendCoin(VALUE1, VALUE2, PRUNED, DIRTY, DIRTY);
+ CheckSpendCoin(VALUE1, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
}
void CheckAddCoinBase(CAmount base_value, CAmount cache_value,
@@ -818,7 +742,7 @@
test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase),
coinbase);
test.cache.SelfTest();
- GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ GetCoinMapEntry(test.cache.map(), result_value, result_flags);
} catch (std::logic_error &e) {
result_value = FAIL;
result_flags = NO_ENTRY;
@@ -869,17 +793,17 @@
CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, true);
}
-void CheckWriteCoins(CAmount parent_value, CAmount child_value,
- CAmount expected_value, char parent_flags,
- char child_flags, char expected_flags) {
+void CheckWriteCoin(CAmount parent_value, CAmount child_value,
+ CAmount expected_value, char parent_flags, char child_flags,
+ char expected_flags) {
SingleEntryCacheTest test(ABSENT, parent_value, parent_flags);
CAmount result_value;
char result_flags;
try {
- WriteCoinsViewEntry(test.cache, child_value, child_flags);
+ WriteCoinViewEntry(test.cache, child_value, child_flags);
test.cache.SelfTest();
- GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
+ GetCoinMapEntry(test.cache.map(), result_value, result_flags);
} catch (std::logic_error &e) {
result_value = FAIL;
result_flags = NO_ENTRY;
@@ -889,7 +813,7 @@
BOOST_CHECK_EQUAL(result_flags, expected_flags);
}
-BOOST_AUTO_TEST_CASE(ccoins_write) {
+BOOST_AUTO_TEST_CASE(coin_write) {
/* Check BatchWrite behavior, flushing one entry from a child cache to a
* parent cache, and checking the resulting entry in the parent cache
* after the write.
@@ -897,74 +821,75 @@
* Parent Child Result Parent Child Result
* Value Value Value Flags Flags Flags
*/
- CheckWriteCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY, NO_ENTRY);
- CheckWriteCoins(ABSENT, PRUNED, PRUNED, NO_ENTRY, DIRTY, DIRTY);
- CheckWriteCoins(ABSENT, PRUNED, ABSENT, NO_ENTRY, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY, DIRTY);
- CheckWriteCoins(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY | FRESH,
- DIRTY | FRESH);
- CheckWriteCoins(PRUNED, ABSENT, PRUNED, 0, NO_ENTRY, 0);
- CheckWriteCoins(PRUNED, ABSENT, PRUNED, FRESH, NO_ENTRY, FRESH);
- CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY, NO_ENTRY, DIRTY);
- CheckWriteCoins(PRUNED, ABSENT, PRUNED, DIRTY | FRESH, NO_ENTRY,
- DIRTY | FRESH);
- CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0, DIRTY, DIRTY);
- CheckWriteCoins(PRUNED, PRUNED, PRUNED, 0, DIRTY | FRESH, DIRTY);
- CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY);
- CheckWriteCoins(PRUNED, PRUNED, ABSENT, FRESH, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY);
- CheckWriteCoins(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY | FRESH, DIRTY);
- CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY);
- CheckWriteCoins(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY | FRESH,
- NO_ENTRY);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0, DIRTY, DIRTY);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, 0, DIRTY | FRESH, DIRTY);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, FRESH, DIRTY | FRESH,
- DIRTY | FRESH);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY | FRESH, DIRTY);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY,
- DIRTY | FRESH);
- CheckWriteCoins(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH,
- DIRTY | FRESH);
- CheckWriteCoins(VALUE1, ABSENT, VALUE1, 0, NO_ENTRY, 0);
- CheckWriteCoins(VALUE1, ABSENT, VALUE1, FRESH, NO_ENTRY, FRESH);
- CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY, NO_ENTRY, DIRTY);
- CheckWriteCoins(VALUE1, ABSENT, VALUE1, DIRTY | FRESH, NO_ENTRY,
- DIRTY | FRESH);
- CheckWriteCoins(VALUE1, PRUNED, PRUNED, 0, DIRTY, DIRTY);
- CheckWriteCoins(VALUE1, PRUNED, FAIL, 0, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(VALUE1, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY);
- CheckWriteCoins(VALUE1, PRUNED, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY);
- CheckWriteCoins(VALUE1, PRUNED, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY);
- CheckWriteCoins(VALUE1, PRUNED, FAIL, DIRTY | FRESH, DIRTY | FRESH,
- NO_ENTRY);
- CheckWriteCoins(VALUE1, VALUE2, VALUE2, 0, DIRTY, DIRTY);
- CheckWriteCoins(VALUE1, VALUE2, FAIL, 0, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(VALUE1, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH);
- CheckWriteCoins(VALUE1, VALUE2, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY);
- CheckWriteCoins(VALUE1, VALUE2, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY);
- CheckWriteCoins(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY,
- DIRTY | FRESH);
- CheckWriteCoins(VALUE1, VALUE2, FAIL, DIRTY | FRESH, DIRTY | FRESH,
- NO_ENTRY);
+ CheckWriteCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY, NO_ENTRY);
+ CheckWriteCoin(ABSENT, PRUNED, PRUNED, NO_ENTRY, DIRTY, DIRTY);
+ CheckWriteCoin(ABSENT, PRUNED, ABSENT, NO_ENTRY, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY, DIRTY);
+ CheckWriteCoin(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY | FRESH,
+ DIRTY | FRESH);
+ CheckWriteCoin(PRUNED, ABSENT, PRUNED, 0, NO_ENTRY, 0);
+ CheckWriteCoin(PRUNED, ABSENT, PRUNED, FRESH, NO_ENTRY, FRESH);
+ CheckWriteCoin(PRUNED, ABSENT, PRUNED, DIRTY, NO_ENTRY, DIRTY);
+ CheckWriteCoin(PRUNED, ABSENT, PRUNED, DIRTY | FRESH, NO_ENTRY,
+ DIRTY | FRESH);
+ CheckWriteCoin(PRUNED, PRUNED, PRUNED, 0, DIRTY, DIRTY);
+ CheckWriteCoin(PRUNED, PRUNED, PRUNED, 0, DIRTY | FRESH, DIRTY);
+ CheckWriteCoin(PRUNED, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY);
+ CheckWriteCoin(PRUNED, PRUNED, ABSENT, FRESH, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY);
+ CheckWriteCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY | FRESH, DIRTY);
+ CheckWriteCoin(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY);
+ CheckWriteCoin(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY | FRESH,
+ NO_ENTRY);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, 0, DIRTY, DIRTY);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, 0, DIRTY | FRESH, DIRTY);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, FRESH, DIRTY | FRESH, DIRTY | FRESH);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY | FRESH, DIRTY);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH);
+ CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH,
+ DIRTY | FRESH);
+ CheckWriteCoin(VALUE1, ABSENT, VALUE1, 0, NO_ENTRY, 0);
+ CheckWriteCoin(VALUE1, ABSENT, VALUE1, FRESH, NO_ENTRY, FRESH);
+ CheckWriteCoin(VALUE1, ABSENT, VALUE1, DIRTY, NO_ENTRY, DIRTY);
+ CheckWriteCoin(VALUE1, ABSENT, VALUE1, DIRTY | FRESH, NO_ENTRY,
+ DIRTY | FRESH);
+ CheckWriteCoin(VALUE1, PRUNED, PRUNED, 0, DIRTY, DIRTY);
+ CheckWriteCoin(VALUE1, PRUNED, FAIL, 0, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(VALUE1, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY);
+ CheckWriteCoin(VALUE1, PRUNED, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY);
+ CheckWriteCoin(VALUE1, PRUNED, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY);
+ CheckWriteCoin(VALUE1, PRUNED, FAIL, DIRTY | FRESH, DIRTY | FRESH,
+ NO_ENTRY);
+ CheckWriteCoin(VALUE1, VALUE2, VALUE2, 0, DIRTY, DIRTY);
+ CheckWriteCoin(VALUE1, VALUE2, FAIL, 0, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(VALUE1, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH);
+ CheckWriteCoin(VALUE1, VALUE2, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY);
+ CheckWriteCoin(VALUE1, VALUE2, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY);
+ CheckWriteCoin(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH);
+ CheckWriteCoin(VALUE1, VALUE2, FAIL, DIRTY | FRESH, DIRTY | FRESH,
+ NO_ENTRY);
// The checks above omit cases where the child flags are not DIRTY, since
// they would be too repetitive (the parent cache is never updated in these
// cases). The loop below covers these cases and makes sure the parent cache
// is always left unchanged.
- for (CAmount parent_value : {ABSENT, PRUNED, VALUE1})
- for (CAmount child_value : {ABSENT, PRUNED, VALUE2})
+ for (CAmount parent_value : {ABSENT, PRUNED, VALUE1}) {
+ for (CAmount child_value : {ABSENT, PRUNED, VALUE2}) {
for (char parent_flags :
- parent_value == ABSENT ? ABSENT_FLAGS : FLAGS)
+ parent_value == ABSENT ? ABSENT_FLAGS : FLAGS) {
for (char child_flags :
- child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS)
- CheckWriteCoins(parent_value, child_value, parent_value,
- parent_flags, child_flags, parent_flags);
+ child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS) {
+ CheckWriteCoin(parent_value, child_value, parent_value,
+ parent_flags, child_flags, parent_flags);
+ }
+ }
+ }
+ }
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
--- a/src/test/test_bitcoin_fuzzy.cpp
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -36,7 +36,7 @@
CBANENTRY_DESERIALIZE,
CTXUNDO_DESERIALIZE,
CBLOCKUNDO_DESERIALIZE,
- CCOINS_DESERIALIZE,
+ COIN_DESERIALIZE,
CNETADDR_DESERIALIZE,
CSERVICE_DESERIALIZE,
CMESSAGEHEADER_DESERIALIZE,
@@ -164,10 +164,10 @@
}
break;
}
- case CCOINS_DESERIALIZE: {
+ case COIN_DESERIALIZE: {
try {
- CCoins block;
- ds >> block;
+ Coin coin;
+ ds >> coin;
} catch (const std::ios_base::failure &e) {
return 0;
}
diff --git a/src/txdb.cpp b/src/txdb.cpp
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -264,6 +264,60 @@
return true;
}
+namespace {
+//! Legacy class to deserialize pre-pertxout database entries without reindex.
+class CCoins {
+public:
+ //! whether transaction is a coinbase
+ bool fCoinBase;
+
+ //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs
+ //! at the end of the array are dropped
+ std::vector<CTxOut> vout;
+
+ //! at which height this transaction was included in the active block chain
+ int nHeight;
+
+ //! empty constructor
+ CCoins() : fCoinBase(false), vout(0), nHeight(0) {}
+
+ template <typename Stream> void Unserialize(Stream &s) {
+ uint32_t nCode = 0;
+ // version
+ int nVersionDummy;
+ ::Unserialize(s, VARINT(nVersionDummy));
+ // header code
+ ::Unserialize(s, VARINT(nCode));
+ fCoinBase = nCode & 1;
+ std::vector<bool> vAvail(2, false);
+ vAvail[0] = (nCode & 2) != 0;
+ vAvail[1] = (nCode & 4) != 0;
+ uint32_t nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
+ // spentness bitmask
+ while (nMaskCode > 0) {
+ uint8_t chAvail = 0;
+ ::Unserialize(s, chAvail);
+ for (unsigned int p = 0; p < 8; p++) {
+ bool f = (chAvail & (1 << p)) != 0;
+ vAvail.push_back(f);
+ }
+ if (chAvail != 0) {
+ nMaskCode--;
+ }
+ }
+ // txouts themself
+ vout.assign(vAvail.size(), CTxOut());
+ for (size_t i = 0; i < vAvail.size(); i++) {
+ if (vAvail[i]) {
+ ::Unserialize(s, REF(CTxOutCompressor(vout[i])));
+ }
+ }
+ // coinbase height
+ ::Unserialize(s, VARINT(nHeight));
+ }
+};
+}
+
/**
* Upgrade the database from older formats.
*

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 1, 09:38 (4 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187229
Default Alt Text
D515.diff (32 KB)

Event Timeline