Implement a hard fork for extended/infinite claim expiration times #112

Closed
lbrynaut wants to merge 247 commits from claim-expiration into master
7 changed files with 601 additions and 80 deletions
Showing only changes of commit 30d123a70b - Show all commits

View file

@ -1625,7 +1625,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock(): block and undo data inconsistent");
assert(trieCache.decrementBlock(blockUndo.queueUndo));
assert(trieCache.decrementBlock(blockUndo.insertUndo, blockUndo.expireUndo));
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
@ -1934,7 +1934,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
assert(trieCache.incrementBlock(blockundo.queueUndo));
assert(trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo));
if (trieCache.getMerkleHash() != block.hashNCCTrie)
return state.DoS(100,

View file

@ -394,8 +394,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
pblock->nNonce = 0;
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
CNCCTrieQueueUndo dummyundo;
trieCache.incrementBlock(dummyundo);
CNCCTrieQueueUndo dummyInsertUndo;
CNCCTrieQueueUndo dummyExpireUndo;
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo);
pblock->hashNCCTrie = trieCache.getMerkleHash();
CValidationState state;

View file

@ -153,6 +153,43 @@ bool CNCCTrie::queueEmpty() const
return true;
}
bool CNCCTrie::expirationQueueEmpty() const
{
for (valueQueueType::const_iterator itRow = dirtyExpirationQueueRows.begin(); itRow != dirtyExpirationQueueRows.end(); ++itRow)
{
if (!itRow->second.empty())
return false;
}
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
pcursor->SeekToFirst();
while(pcursor->Valid())
{
try
{
leveldb::Slice slKey = pcursor->key();
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
char chType;
ssKey >> chType;
if (chType == 'e')
{
return false;
}
}
catch (const std::exception& e)
{
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
pcursor->Next();
}
return true;
}
void CNCCTrie::setExpirationTime(int t)
{
nExpirationTime = t;
}
void CNCCTrie::clear()
{
clear(&root);
@ -338,6 +375,17 @@ bool CNCCTrie::getQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
return db.Read(std::make_pair('r', nHeight), row);
}
bool CNCCTrie::getExpirationQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
{
valueQueueType::iterator itQueueRow = dirtyExpirationQueueRows.find(nHeight);
if (itQueueRow != dirtyExpirationQueueRows.end())
{
row = itQueueRow->second;
return true;
}
return db.Read(std::make_pair('e', nHeight), row);
}
void CNCCTrie::updateQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
{
valueQueueType::iterator itQueueRow = dirtyQueueRows.find(nHeight);
@ -352,7 +400,21 @@ void CNCCTrie::updateQueueRow(int nHeight, std::vector<CValueQueueEntry>& row)
itQueueRow->second.swap(row);
}
bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlockIn, valueQueueType& queueCache, int nNewHeight)
void CNCCTrie::updateExpirationRow(int nHeight, std::vector<CValueQueueEntry>& row)
{
valueQueueType::iterator itQueueRow = dirtyExpirationQueueRows.find(nHeight);
if (itQueueRow == dirtyExpirationQueueRows.end())
{
std::vector<CValueQueueEntry> newRow;
std::pair<valueQueueType::iterator, bool> ret;
ret = dirtyExpirationQueueRows.insert(std::pair<int, std::vector<CValueQueueEntry> >(nHeight, newRow));
assert(ret.second);
itQueueRow = ret.first;
}
itQueueRow->second.swap(row);
}
bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlockIn, valueQueueType& queueCache, valueQueueType& expirationQueueCache, int nNewHeight)
{
// General strategy: the cache is ordered by length, ensuring child
// nodes are always inserted after their parents. Insert each node
@ -390,6 +452,10 @@ bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256&
{
updateQueueRow(itQueueCacheRow->first, itQueueCacheRow->second);
}
for (valueQueueType::iterator itExpirationRow = expirationQueueCache.begin(); itExpirationRow != expirationQueueCache.end(); ++itExpirationRow)
{
updateExpirationRow(itExpirationRow->first, itExpirationRow->second);
}
hashBlock = hashBlockIn;
nCurrentHeight = nNewHeight;
return true;
@ -505,6 +571,21 @@ void CNCCTrie::BatchWriteQueueRows(CLevelDBBatch& batch)
}
}
void CNCCTrie::BatchWriteExpirationQueueRows(CLevelDBBatch& batch)
{
for (valueQueueType::iterator itQueue = dirtyExpirationQueueRows.begin(); itQueue != dirtyExpirationQueueRows.end(); ++itQueue)
{
if (itQueue->second.empty())
{
batch.Erase(std::make_pair('e', itQueue->first));
}
else
{
batch.Write(std::make_pair('e', itQueue->first), itQueue->second);
}
}
}
bool CNCCTrie::WriteToDisk()
{
CLevelDBBatch batch;
@ -513,6 +594,8 @@ bool CNCCTrie::WriteToDisk()
dirtyNodes.clear();
BatchWriteQueueRows(batch);
dirtyQueueRows.clear();
BatchWriteExpirationQueueRows(batch);
dirtyExpirationQueueRows.clear();
batch.Write('h', hashBlock);
batch.Write('t', nCurrentHeight);
return db.WriteBatch(batch);
@ -928,7 +1011,7 @@ bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nO
{
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, nHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, nHeight, nCurrentHeight);
assert(nHeight == nCurrentHeight);
return addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nHeight + DEFAULT_DELAY);
return addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nHeight + DEFAULT_DELAY);
}
bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, uint256 prevTxhash, uint32_t nPrevOut) const
@ -941,7 +1024,7 @@ bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nO
if (val.txhash == prevTxhash && val.nOut == nPrevOut)
{
LogPrintf("%s: This is an update to a best claim. Previous claim txhash: %s, nOut: %d\n", __func__, prevTxhash.GetHex(), nPrevOut);
return addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nHeight);
return addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nHeight);
}
}
return addClaim(name, txhash, nOut, nAmount, nHeight);
@ -955,21 +1038,23 @@ bool CNCCTrieCache::undoSpendClaim(const std::string name, uint256 txhash, uint3
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
CValueQueueEntry entry(name, val);
insertClaimIntoTrie(name, CNodeValue(txhash, nOut, nAmount, nHeight, nValidAtHeight));
addToExpirationQueue(entry);
}
else
{
addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nValidAtHeight);
addClaimToQueues(name, txhash, nOut, nAmount, nHeight, nValidAtHeight);
}
return true;
}
bool CNCCTrieCache::addClaimToQueue(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
bool CNCCTrieCache::addClaimToQueues(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
{
LogPrintf("%s: nValidAtHeight: %d\n", __func__, nValidAtHeight);
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
CValueQueueEntry entry(name, val);
valueQueueType::iterator itQueueRow = getQueueCacheRow(nValidAtHeight, true);
itQueueRow->second.push_back(entry);
addToExpirationQueue(entry);
return true;
}
@ -1012,49 +1097,122 @@ bool CNCCTrieCache::spendClaim(const std::string name, uint256 txhash, uint32_t
bool CNCCTrieCache::removeClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const
{
LogPrintf("%s: name: %s, txhash: %s, nOut: %s, nHeight: %s, nCurrentHeight: %s\n", __func__, name, txhash.GetHex(), nOut, nHeight, nCurrentHeight);
bool removed = false;
if (nHeight + DEFAULT_DELAY >= nCurrentHeight)
{
if (removeClaimFromQueue(name, txhash, nOut, nHeight + DEFAULT_DELAY, nValidAtHeight))
return true;
if (removeClaimFromQueue(name, txhash, nOut, nHeight, nValidAtHeight))
return true;
removed = true;
else if (removeClaimFromQueue(name, txhash, nOut, nHeight, nValidAtHeight))
removed = true;
}
if (removeClaimFromQueue(name, txhash, nOut, nHeight, nCurrentHeight))
return true;
return removeClaimFromTrie(name, txhash, nOut, nValidAtHeight);
if (removed == false && removeClaimFromQueue(name, txhash, nOut, nHeight, nCurrentHeight))
removed = true;
if (removed == false && removeClaimFromTrie(name, txhash, nOut, nValidAtHeight))
removed = true;
if (removed == true)
removeFromExpirationQueue(name, txhash, nOut, nHeight);
return removed;
}
bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& undo) const
void CNCCTrieCache::addToExpirationQueue(CValueQueueEntry& entry) const
{
int expirationHeight = entry.val.nHeight + base->nExpirationTime;
valueQueueType::iterator itQueueRow = getExpirationQueueCacheRow(expirationHeight, true);
itQueueRow->second.push_back(entry);
}
void CNCCTrieCache::removeFromExpirationQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeight) const
{
int expirationHeight = nHeight + base->nExpirationTime;
valueQueueType::iterator itQueueRow = getExpirationQueueCacheRow(expirationHeight, false);
std::vector<CValueQueueEntry>::iterator itQueue;
if (itQueueRow != valueQueueCache.end())
{
for (itQueue = itQueueRow->second.begin(); itQueue != itQueueRow->second.end(); ++itQueue)
{
CNodeValue& val = itQueue->val;
if (name == itQueue->name && val.txhash == txhash && val.nOut == nOut)
break;
}
}
if (itQueue != itQueueRow->second.end())
{
itQueueRow->second.erase(itQueue);
}
}
valueQueueType::iterator CNCCTrieCache::getExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const
{
valueQueueType::iterator itQueueRow = expirationQueueCache.find(nHeight);
if (itQueueRow == expirationQueueCache.end())
{
// Have to make a new row it put in the cache, if createIfNotExists is true
std::vector<CValueQueueEntry> queueRow;
// If the row exists in the base, copy its values into the new row.
bool exists = base->getExpirationQueueRow(nHeight, queueRow);
if (!exists)
if (!createIfNotExists)
return itQueueRow;
// Stick the new row in the cache
std::pair<valueQueueType::iterator, bool> ret;
ret = expirationQueueCache.insert(std::pair<int, std::vector<CValueQueueEntry> >(nHeight, queueRow));
assert(ret.second);
itQueueRow = ret.first;
}
return itQueueRow;
}
bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const
{
LogPrintf("%s: nCurrentHeight (before increment): %d\n", __func__, nCurrentHeight);
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
if (itQueueRow != valueQueueCache.end())
{
for (std::vector<CValueQueueEntry>::iterator itEntry = itQueueRow->second.begin(); itEntry != itQueueRow->second.end(); ++itEntry)
{
insertClaimIntoTrie(itEntry->name, itEntry->val);
insertUndo.push_back(*itEntry);
}
itQueueRow->second.clear();
}
valueQueueType::iterator itExpirationRow = getExpirationQueueCacheRow(nCurrentHeight, false);
if (itExpirationRow != expirationQueueCache.end())
{
for (std::vector<CValueQueueEntry>::iterator itEntry = itExpirationRow->second.begin(); itEntry != itExpirationRow->second.end(); ++itEntry)
{
int nValidAtHeight;
assert(base->nExpirationTime > DEFAULT_DELAY);
assert(removeClaimFromTrie(itEntry->name, itEntry->val.txhash, itEntry->val.nOut, nValidAtHeight));
expireUndo.push_back(*itEntry);
}
itExpirationRow->second.clear();
}
nCurrentHeight++;
if (itQueueRow == valueQueueCache.end())
{
return true;
}
for (std::vector<CValueQueueEntry>::iterator itEntry = itQueueRow->second.begin(); itEntry != itQueueRow->second.end(); ++itEntry)
{
insertClaimIntoTrie(itEntry->name, itEntry->val);
undo.push_back(*itEntry);
}
itQueueRow->second.clear();
return true;
}
bool CNCCTrieCache::decrementBlock(CNCCTrieQueueUndo& undo) const
bool CNCCTrieCache::decrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const
{
LogPrintf("%s: nCurrentHeight (before decrement): %d\n", __func__, nCurrentHeight);
nCurrentHeight--;
if (undo.begin() != undo.end())
if (insertUndo.begin() != insertUndo.end())
{
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, true);
for (CNCCTrieQueueUndo::iterator itUndo = undo.begin(); itUndo != undo.end(); ++itUndo)
for (CNCCTrieQueueUndo::iterator itInsertUndo = insertUndo.begin(); itInsertUndo != insertUndo.end(); ++itInsertUndo)
{
int nValidHeightInTrie;
assert(removeClaimFromTrie(itUndo->name, itUndo->val.txhash, itUndo->val.nOut, nValidHeightInTrie));
assert(nValidHeightInTrie == itUndo->val.nValidAtHeight);
itQueueRow->second.push_back(*itUndo);
assert(removeClaimFromTrie(itInsertUndo->name, itInsertUndo->val.txhash, itInsertUndo->val.nOut, nValidHeightInTrie));
assert(nValidHeightInTrie == itInsertUndo->val.nValidAtHeight);
itQueueRow->second.push_back(*itInsertUndo);
}
}
if (expireUndo.begin() != expireUndo.end())
{
valueQueueType::iterator itExpireRow = getExpirationQueueCacheRow(nCurrentHeight, true);
for (CNCCTrieQueueUndo::iterator itExpireUndo = expireUndo.begin(); itExpireUndo != expireUndo.end(); ++itExpireUndo)
{
insertClaimIntoTrie(itExpireUndo->name, itExpireUndo->val);
itExpireRow->second.push_back(*itExpireUndo);
}
}
return true;
@ -1090,7 +1248,7 @@ bool CNCCTrieCache::flush()
{
if (dirty())
getMerkleHash();
bool success = base->update(cache, cacheHashes, getBestBlock(), valueQueueCache, nCurrentHeight);
bool success = base->update(cache, cacheHashes, getBestBlock(), valueQueueCache, expirationQueueCache, nCurrentHeight);
if (success)
{
success = clear();

View file

@ -147,7 +147,7 @@ class CNCCTrieCache;
class CNCCTrie
{
public:
CNCCTrie(bool fMemory = false, bool fWipe = false) : db(GetDataDir() / "ncctrie", 100, fMemory, fWipe), nCurrentHeight(0), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
CNCCTrie(bool fMemory = false, bool fWipe = false) : db(GetDataDir() / "ncctrie", 100, fMemory, fWipe), nCurrentHeight(0), nExpirationTime(262974), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
uint256 getMerkleHash();
CLevelDBWrapper db;
bool empty() const;
@ -159,15 +159,19 @@ public:
bool getInfoForName(const std::string& name, CNodeValue& val) const;
int nCurrentHeight;
bool queueEmpty() const;
bool expirationQueueEmpty() const;
void setExpirationTime(int t);
bool getQueueRow(int nHeight, std::vector<CValueQueueEntry>& row);
bool getExpirationQueueRow(int nHeight, std::vector<CValueQueueEntry>& row);
bool haveClaim(const std::string& name, const uint256& txhash, uint32_t nOut) const;
unsigned int getTotalNamesInTrie() const;
unsigned int getTotalClaimsInTrie() const;
CAmount getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
friend class CNCCTrieCache;
int nExpirationTime;
private:
void clear(CNCCTrieNode* current);
bool update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlock, valueQueueType& queueCache, int nNewHeight);
bool update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlock, valueQueueType& queueCache, valueQueueType& expirationQueueCache, int nNewHeight);
bool updateName(const std::string& name, CNCCTrieNode* updatedNode);
bool updateHash(const std::string& name, uint256& hash);
bool recursiveNullify(CNCCTrieNode* node, std::string& name);
@ -180,14 +184,16 @@ private:
CNCCTrieNode root;
uint256 hashBlock;
valueQueueType dirtyQueueRows;
valueQueueType dirtyExpirationQueueRows;
nodeCacheType dirtyNodes;
void markNodeDirty(const std::string& name, CNCCTrieNode* node);
void deleteQueueRow(int nHeight);
void updateQueueRow(int nHeight, std::vector<CValueQueueEntry>& row);
void updateExpirationRow(int nHeight, std::vector<CValueQueueEntry>& row);
void BatchWriteNode(CLevelDBBatch& batch, const std::string& name, const CNCCTrieNode* pNode) const;
void BatchEraseNode(CLevelDBBatch& batch, const std::string& nome) const;
void BatchWriteQueueRows(CLevelDBBatch& batch);
void BatchWriteExpirationQueueRows(CLevelDBBatch& batch);
};
class CNCCTrieCache
@ -205,8 +211,8 @@ public:
bool undoSpendClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const;
uint256 getBestBlock();
void setBestBlock(const uint256& hashBlock);
bool incrementBlock(CNCCTrieQueueUndo& undo) const;
bool decrementBlock(CNCCTrieQueueUndo& undo) const;
bool incrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const;
bool decrementBlock(CNCCTrieQueueUndo& insertUndo, CNCCTrieQueueUndo& expireUndo) const;
~CNCCTrieCache() { clear(); }
bool insertClaimIntoTrie(const std::string name, CNodeValue val) const;
bool removeClaimFromTrie(const std::string name, uint256 txhash, uint32_t nOut, int& nValidAtHeight) const;
@ -217,6 +223,7 @@ private:
mutable std::set<std::string> dirtyHashes;
mutable hashMapType cacheHashes;
mutable valueQueueType valueQueueCache;
mutable valueQueueType expirationQueueCache;
mutable int nCurrentHeight; // Height of the block that is being worked on, which is
// one greater than the height of the chain's tip
uint256 computeHash() const;
@ -224,9 +231,12 @@ private:
bool recursivePruneName(CNCCTrieNode* tnCurrent, unsigned int nPos, std::string sName, bool* pfNullified = NULL) const;
bool clear() const;
bool removeClaim(const std::string name, uint256 txhash, uint32_t nOut, int nHeight, int& nValidAtHeight) const;
bool addClaimToQueue(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const;
bool addClaimToQueues(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const;
bool removeClaimFromQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeightToCheck, int& nValidAtHeight) const;
void addToExpirationQueue(CValueQueueEntry& entry) const;
void removeFromExpirationQueue(const std::string name, uint256 txhash, uint32_t nOut, int nHeight) const;
valueQueueType::iterator getQueueCacheRow(int nHeight, bool createIfNotExists) const;
valueQueueType::iterator getExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const;
uint256 hashBlock;
};

View file

@ -14,7 +14,7 @@
using namespace std;
const unsigned int nonces[] = {
const unsigned int insert_nonces[] = {
62302, 78404, 42509, 88397, 232147, 34120, 48944, 8449, 3855, 99418,
35007, 36992, 18865, 48021, 117592, 61911, 26614, 26267, 171911, 49917,
68274, 19360, 48650, 22711, 102612, 73362, 7375, 39379, 413, 123283,
@ -83,6 +83,64 @@ const unsigned int nonces[] = {
102894, 41478, 509, 169951, 5571, 28284, 8138, 53248, 47878, 113791,
192277, 73645, 28672, 93670, 30741, 129667};
const unsigned int expire_nonces[] = {
1772, 19895, 52494, 75900, 15954, 92687, 381518, 24750, 131218, 140637,
25151, 4751, 117588, 31281, 741, 13006, 56207, 23174, 32024, 23597,
17093, 22998, 68975, 84976, 47024, 48818, 29830, 28891, 66091, 6304,
117, 253782, 126584, 55982, 43172, 5862, 36712, 289031, 42833, 61902,
81993, 26790, 80145, 111102, 27904, 16188, 55120, 7171, 67694, 214899,
16360, 133920, 31442, 103537, 266284, 4407, 102008, 1149, 156950, 76029,
33751, 20831, 24714, 202595, 9393, 227174, 3357, 70, 45445, 104755,
6024, 13512, 163718, 43755, 17582, 17069, 17355, 38898, 101900, 41342,
20701, 9827, 11663, 146362, 189082, 279537, 79142, 423101, 11154, 103046,
44740, 90350, 41450, 4627, 4685, 14510, 13639, 13705, 2369, 326596,
74814, 15068, 7287, 26685, 41834, 5872, 94033, 77510, 21271, 51233,
687, 84716, 18945, 139111, 11508, 15009, 103492, 25317, 100121, 29105,
26520, 531, 6883, 181308, 161707, 72079, 50032, 65286, 96365, 18280,
21015, 56591, 90913, 3280, 74270, 87610, 85124, 58599, 161342, 36017,
135104, 19625, 114763, 163177, 31400, 99871, 15939, 6822, 51007, 33240,
15449, 28232, 242057, 45744, 253284, 218826, 25843, 118582, 228181, 7592,
3398, 23637, 46762, 22853, 7669, 358599, 99238, 32782, 46407, 36545,
28976, 34995, 23564, 60624, 45957, 162829, 7055, 184611, 69270, 22560,
17314, 24374, 67156, 44705, 9482, 17611, 92669, 22471, 47688, 110960,
18595, 46376, 23989, 47847, 41231, 2937, 34056, 61839, 9393, 122723,
119967, 41795, 13244, 22081, 41407, 65568, 120355, 228591, 3763, 23561,
78832, 20110, 3849, 162319, 9699, 153960, 60013, 22063, 22895, 84997,
20008, 6201, 18985, 7065, 63655, 35849, 19788, 69977, 45664, 15647,
111735, 1372, 2487, 38856, 39081, 74496, 71062, 20232, 33091, 26777,
155180, 149434, 35380, 102844, 46709, 3373, 137389, 33273, 13194, 5106,
69109, 21599, 24896, 16688, 101584, 567, 61253, 125648, 30825, 38976,
88494, 82214, 84079, 52761, 16392, 206857, 19856, 48376, 11820, 21296,
12707, 94783, 31272, 113581, 40682, 143247, 1206, 21720, 40627, 131077,
78794, 9026, 38830, 39757, 94577, 20134, 15904, 185817, 35595, 21609,
15868, 187480, 62515, 36383, 12797, 101029, 17979, 48892, 59215, 197023,
217536, 295885, 5639, 24470, 440, 96896, 3113, 74270, 8773, 89871,
41807, 33896, 41053, 87038, 64666, 2642, 39880, 113389, 51922, 64364,
46026, 34424, 6856, 51050, 48871, 43033, 95444, 68098, 10463, 27119,
101386, 28555, 94429, 38046, 13110, 39449, 976, 12015, 32827, 20156,
79086, 90632, 24716, 11632, 27225, 11563, 45437, 41804, 240056, 26298,
7089, 119823, 87043, 46315, 108722, 24002, 109328, 32013, 47232, 243845,
9604, 158119, 189402, 124127, 89656, 39496, 63807, 83836, 80843, 2261,
103229, 24028, 299032, 43513, 8506, 362389, 14113, 47973, 145654, 23170,
23272, 35090, 17628, 28197, 96581, 84151, 694, 182728, 86514, 129029,
4509, 48647, 63280, 86829, 138046, 8075, 59670, 53232, 37353, 51966,
62110, 66890, 75512, 42296, 240099, 64624, 98903, 29189, 2593, 17376,
11417, 2982, 3273, 40001, 468410, 29603, 111819, 36878, 6710, 14350,
87778, 69800, 18820, 75880, 26049, 36685, 8500, 189289, 186944, 100520,
167630, 7170, 115904, 79212, 4792, 82507, 13634, 71118, 27066, 66914,
44963, 58999, 153183, 184462, 65596, 102627, 333388, 164930, 6664, 120605,
141, 122317, 162948, 93160, 216861, 68595, 67370, 15526, 4320, 45961,
86806, 61077, 61730, 117548, 127472, 1191, 15735, 133987, 16288, 4652,
83674, 21872, 21351, 35691, 11584, 85669, 196, 75276, 45275, 55828,
46586, 153482, 6183, 386, 28729, 111942, 2847, 10584, 207349, 57260,
12075, 27552, 129129, 282325, 11954, 28300, 175155, 31256, 12953, 16345,
34101, 57962, 16950, 9103, 94414, 1918, 69031, 151629, 41281, 85752,
66681, 31646, 12396, 167, 72005, 3936, 27566, 5663, 24098, 73350,
19076, 179631, 36500, 152550, 56501, 81202, 77561, 134713, 81130, 22321,
112081, 32992, 144573, 21369, 2471, 18371, 63050, 44211, 6147, 206052,
34252, 534, 20176, 58035, 24268, 19608, 37770, 57588, 120961, 58415,
4780, 4614, 229320, 42279, 41295, 23501, 78183};
BOOST_FIXTURE_TEST_SUITE(ncctrie_tests, TestingSetup)
CMutableTransaction BuildTransaction(const uint256& prevhash)
@ -129,7 +187,7 @@ void AddToMempool(CMutableTransaction& tx)
mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, GetTime(), 111.0, chainActive.Height()));
}
bool CreateBlock(CBlockTemplate* pblocktemplate, bool f = false)
bool CreateBlock(CBlockTemplate* pblocktemplate, int nonce)
{
static int unique_block_counter = 0;
CBlock* pblock = &pblocktemplate->block;
@ -140,18 +198,24 @@ bool CreateBlock(CBlockTemplate* pblocktemplate, bool f = false)
txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height(), Params().GetConsensus());
pblock->vtx[0] = CTransaction(txCoinbase);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nNonce = nonces[unique_block_counter - 1];
/*for (int i = 0; ; ++i)
//if (nonce != -1)
//{
pblock->nNonce = nonce;
//}
/*else
{
pblock->nNonce = i;
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()))
for (int i = 0; ; ++i)
{
std::cout << pblock->nNonce << ",";
if (unique_block_counter % 10 == 0)
std::cout << std::endl;
else
std::cout << " ";
break;
pblock->nNonce = i;
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()))
{
std::cout << pblock->nNonce << ",";
if (unique_block_counter % 10 == 0)
std::cout << std::endl;
else
std::cout << " ";
break;
}
}
}*/
CValidationState state;
@ -290,6 +354,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_merkle_hash)
BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
{
int block_counter = 0;
BOOST_CHECK(pnccTrie->nCurrentHeight == chainActive.Height() + 1);
CBlockTemplate *pblocktemplate;
@ -315,7 +380,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
for (unsigned int i = 0; i < 103; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
if (coinbases.size() < 3)
coinbases.push_back(CTransaction(pblocktemplate->block.vtx[0]));
}
@ -352,7 +417,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 3);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -363,7 +428,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
@ -372,7 +437,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
delete pblocktemplate;
// Verify tx1 and tx2 are in the trie
@ -389,7 +454,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 4);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -429,7 +494,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, true));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -451,7 +516,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -462,7 +527,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
@ -471,7 +536,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
@ -497,7 +562,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 3);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -519,7 +584,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
@ -529,7 +594,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 50; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
@ -542,7 +607,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
@ -552,7 +617,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 51; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
@ -571,7 +636,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 0; i < 50; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
@ -580,7 +645,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
@ -596,7 +661,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -628,7 +693,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, true));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -641,7 +706,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 50; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
@ -654,7 +719,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -668,7 +733,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -689,7 +754,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate, true));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
@ -698,7 +763,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
@ -720,7 +785,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 0; i < 50; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
}
delete pblocktemplate;
@ -729,7 +794,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
@ -744,7 +809,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
@ -759,7 +824,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate));
BOOST_CHECK(CreateBlock(pblocktemplate, insert_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
@ -783,6 +848,279 @@ BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
BOOST_CHECK(pnccTrie->queueEmpty());
}
BOOST_AUTO_TEST_CASE(ncctrie_claim_expiration)
{
int block_counter = 0;
BOOST_CHECK(pnccTrie->nCurrentHeight == chainActive.Height() + 1);
CBlockTemplate *pblocktemplate;
LOCK(cs_main);
CScript scriptPubKey = CScript() << OP_TRUE;
std::string sName("atest");
std::string sValue("testa");
std::vector<unsigned char> vchName(sName.begin(), sName.end());
std::vector<unsigned char> vchValue(sValue.begin(), sValue.end());
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
std::vector<CTransaction> coinbases;
for (unsigned int i = 0; i < 102; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
if (coinbases.size() < 2)
coinbases.push_back(CTransaction(pblocktemplate->block.vtx[0]));
}
delete pblocktemplate;
CMutableTransaction tx1 = BuildTransaction(coinbases[0]);
tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << OP_TRUE;
CMutableTransaction tx2 = BuildTransaction(tx1);
tx2.vout[0].scriptPubKey = CScript() << OP_TRUE;
std::vector<uint256> blocks_to_invalidate;
// set expiration time to 100 blocks after the block becomes valid.
pnccTrie->setExpirationTime(200);
// create a claim. verify no expiration event has been scheduled.
AddToMempool(tx1);
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(!pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// advance until the claim is valid. verify the expiration event is scheduled.
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
}
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// advance until the expiration event occurs. verify the expiration event occurs on time.
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
}
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
// roll forward a bit and then roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 0; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
}
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// advance until the expiration event occurs. verify the expiration event occurs on time.
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// roll back to before the claim is valid. verify the claim is removed but the expiration event still exists.
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(!pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// advance until the claim is valid again. verify the expiration event is scheduled.
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// advance until the expiration event occurs. verify the expiration event occurs on time.
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 1; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
if (i == 50)
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
}
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
// roll back to before the expiration event. verify the expiration event is scheduled.
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// roll back some.
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// spend the claim. verify the expiration event is removed.
AddToMempool(tx2);
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
// roll back the spend. verify the expiration event is returned.
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// advance until the expiration event occurs. verify the event occurs on time.
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
for (unsigned int i = 50; i < 100; ++i)
{
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
}
delete pblocktemplate;
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
BOOST_CHECK(CreateBlock(pblocktemplate, expire_nonces[block_counter++]));
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
delete pblocktemplate;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// roll back to before the claim is valid. verify the claim is removed but the expiration event is not.
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(!pnccTrie->queueEmpty());
BOOST_CHECK(!pnccTrie->expirationQueueEmpty());
// roll all the way back
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
blocks_to_invalidate.pop_back();
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(pnccTrie->queueEmpty());
BOOST_CHECK(pnccTrie->expirationQueueEmpty());
BOOST_CHECK(blocks_to_invalidate.empty());
}
BOOST_AUTO_TEST_CASE(ncctrienode_serialize_unserialize)
{
CDataStream ss(SER_DISK, 0);

View file

@ -80,14 +80,16 @@ class CBlockUndo
{
public:
std::vector<CTxUndo> vtxundo; // for all but the coinbase
CNCCTrieQueueUndo queueUndo; // any claims that went from the queue to the trie
CNCCTrieQueueUndo insertUndo; // any claims that went from the queue to the trie
CNCCTrieQueueUndo expireUndo; // any claims that expired
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(vtxundo);
READWRITE(queueUndo);
READWRITE(insertUndo);
READWRITE(expireUndo);
}
};

View file

@ -665,7 +665,19 @@ void ListNameClaims(const CWalletTx& wtx, const string& strAccount, int nMinDept
{
CBlockIndex* pindex = it->second;
if (pindex)
{
entry.push_back(Pair("height", pindex->nHeight));
entry.push_back(Pair("expiration height", pindex->nHeight + pnccTrie->nExpirationTime));
if (pindex->nHeight + pnccTrie->nExpirationTime > chainActive.Height())
{
entry.push_back(Pair("expired", false));
entry.push_back(Pair("blocks to expiration", pindex->nHeight + pnccTrie->nExpirationTime - chainActive.Height()));
}
else
{
entry.push_back(Pair("expired", true));
}
}
}
entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
entry.push_back(Pair("is spent", pwalletMain->IsSpent(wtx.GetHash(), s.vout)));