Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115083
D515.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
32 KB
Subscribers
None
D515.diff
View Options
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
Details
Attached
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)
Attached To
D515: Move the CCoins abstraction in txdb.cpp
Event Timeline
Log In to Comment