Rename CClaimTrieCache to CClaimTrieUpdateBuffer #156
7 changed files with 582 additions and 332 deletions
|
@ -123,7 +123,7 @@ public:
|
||||||
nRejectBlockOutdatedMajority = 950;
|
nRejectBlockOutdatedMajority = 950;
|
||||||
nToCheckBlockUpgradeMajority = 1000;
|
nToCheckBlockUpgradeMajority = 1000;
|
||||||
nMinerThreads = 2;
|
nMinerThreads = 2;
|
||||||
nTargetTimespan = 30 * 60 * 10;//14 * 24 * 60 * 60; // two weeks
|
nTargetTimespan = 30 * 60 * 12;//14 * 24 * 60 * 60; // two weeks
|
||||||
nTargetSpacing = 30;
|
nTargetSpacing = 30;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
35
src/main.cpp
35
src/main.cpp
|
@ -1879,8 +1879,25 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
return false;
|
return false;
|
||||||
control.Add(vChecks);
|
control.Add(vChecks);
|
||||||
|
|
||||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
// To handle NCC updates, stick all NCC claims found in the inputs into a map of
|
||||||
|
// name: (txhash, nOut). When running through the outputs, if any NCC claim's
|
||||||
|
// name is found in the map, send the name's txhash and nOut to the trie cache,
|
||||||
|
// and then remove the name: (txhash, nOut) mapping from the map.
|
||||||
|
// If there are two or more NCC claims in the inputs with the same name, only
|
||||||
|
// use the first.
|
||||||
|
// TODO: before releasing, see if it's a better idea to make an explicit
|
||||||
|
// operation for updating, like OP_UPDATE_NAME, which directly references
|
||||||
|
// the claim to be updated. It would only be necessary to add a single extra
|
||||||
|
// parameter to the operation, the input number, to exactly specify which
|
||||||
|
// claim is being updated. Then here it would just need to be checked if that
|
||||||
|
// input number was already used by an earlier tx.vout in the transaction.
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::pair<uint256, unsigned int> > spentClaimsType;
|
||||||
|
spentClaimsType spentClaims;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < tx.vin.size(); ++i)
|
||||||
{
|
{
|
||||||
|
const CTxIn& txin = tx.vin[i];
|
||||||
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
||||||
assert(coins);
|
assert(coins);
|
||||||
|
|
||||||
|
@ -1894,6 +1911,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
LogPrintf("%s: Removing %s from the ncc trie. Tx: %s, nOut: %d\n", __func__, name, txin.prevout.hash.GetHex(), txin.prevout.n);
|
LogPrintf("%s: Removing %s from the ncc trie. Tx: %s, nOut: %d\n", __func__, name, txin.prevout.hash.GetHex(), txin.prevout.n);
|
||||||
if (!trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, nValidAtHeight))
|
if (!trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, nValidAtHeight))
|
||||||
LogPrintf("%s: Something went wrong removing the name\n", __func__);
|
LogPrintf("%s: Something went wrong removing the name\n", __func__);
|
||||||
|
mNCCUndoHeights[i] = nValidAtHeight;
|
||||||
|
std::pair<uint256, unsigned int> val(txin.prevout.hash, txin.prevout.n);
|
||||||
|
std::pair<std::string, std::pair<uint256, unsigned int> > entry(name, val);
|
||||||
|
spentClaims.insert(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1908,7 +1929,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
assert(vvchParams.size() == 2);
|
assert(vvchParams.size() == 2);
|
||||||
std::string name(vvchParams[0].begin(), vvchParams[0].end());
|
std::string name(vvchParams[0].begin(), vvchParams[0].end());
|
||||||
LogPrintf("%s: Inserting %s into the ncc trie. Tx: %s, nOut: %d\n", __func__, name, tx.GetHash().GetHex(), i);
|
LogPrintf("%s: Inserting %s into the ncc trie. Tx: %s, nOut: %d\n", __func__, name, tx.GetHash().GetHex(), i);
|
||||||
if (!trieCache.addClaim(name, tx.GetHash(), i, txout.nValue, pindex->nHeight))
|
spentClaimsType::iterator itSpent = spentClaims.find(name);
|
||||||
|
bool success;
|
||||||
|
if (itSpent != spentClaims.end())
|
||||||
|
{
|
||||||
|
LogPrintf("%s: Updating a previous transaction. Old tx: %s, old nOut: %d\n", __func__, itSpent->second.first.GetHex(), itSpent->second.second);
|
||||||
|
success = trieCache.addClaim(name, tx.GetHash(), i, txout.nValue, pindex->nHeight, itSpent->second.first, itSpent->second.second);
|
||||||
|
spentClaims.erase(itSpent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
success = trieCache.addClaim(name, tx.GetHash(), i, txout.nValue, pindex->nHeight);
|
||||||
|
if (!success)
|
||||||
LogPrintf("%s: Something went wrong inserting the name\n", __func__);
|
LogPrintf("%s: Something went wrong inserting the name\n", __func__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,6 +281,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
|
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::pair<uint256, unsigned int> > spentClaimsType;
|
||||||
|
spentClaimsType spentClaims;
|
||||||
|
|
||||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||||
{
|
{
|
||||||
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
||||||
|
@ -303,6 +306,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
int throwaway;
|
int throwaway;
|
||||||
if (!trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, throwaway))
|
if (!trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, throwaway))
|
||||||
LogPrintf("%s: Something went wrong removing the name\n", __func__);
|
LogPrintf("%s: Something went wrong removing the name\n", __func__);
|
||||||
|
std::pair<uint256, unsigned int> val(txin.prevout.hash, txin.prevout.n);
|
||||||
|
std::pair<std::string, std::pair<uint256, unsigned int> >entry(name, val);
|
||||||
|
spentClaims.insert(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +324,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
{
|
{
|
||||||
assert(vvchParams.size() == 2);
|
assert(vvchParams.size() == 2);
|
||||||
std::string name(vvchParams[0].begin(), vvchParams[0].end());
|
std::string name(vvchParams[0].begin(), vvchParams[0].end());
|
||||||
if (!trieCache.addClaim(name, tx.GetHash(), i, txout.nValue, nHeight))
|
spentClaimsType::iterator itSpent = spentClaims.find(name);
|
||||||
|
bool success;
|
||||||
|
if (itSpent != spentClaims.end())
|
||||||
|
{
|
||||||
|
success = trieCache.addClaim(name, tx.GetHash(), i, txout.nValue, nHeight, itSpent->second.first, itSpent->second.second);
|
||||||
|
spentClaims.erase(itSpent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
success = trieCache.addClaim(name, tx.GetHash(), i, txout.nValue, nHeight);
|
||||||
|
if (!success)
|
||||||
LogPrintf("%s: Something went wrong inserting the name\n", __func__);
|
LogPrintf("%s: Something went wrong inserting the name\n", __func__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -372,6 +387,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
|
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
|
||||||
pblock->nNonce = 0;
|
pblock->nNonce = 0;
|
||||||
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
|
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
|
||||||
|
CNCCTrieQueueUndo dummyundo;
|
||||||
|
trieCache.incrementBlock(dummyundo);
|
||||||
pblock->hashNCCTrie = trieCache.getMerkleHash();
|
pblock->hashNCCTrie = trieCache.getMerkleHash();
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
|
@ -417,7 +417,8 @@ bool CNCCTrie::ReadFromDisk(bool check)
|
||||||
{
|
{
|
||||||
if (!db.Read('h', hashBlock))
|
if (!db.Read('h', hashBlock))
|
||||||
LogPrintf("%s: Couldn't read the best block's hash\n", __func__);
|
LogPrintf("%s: Couldn't read the best block's hash\n", __func__);
|
||||||
|
if (!db.Read('t', nCurrentHeight))
|
||||||
|
LogPrintf("%s: Couldn't read the current height\n", __func__);
|
||||||
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
|
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
|
||||||
pcursor->SeekToFirst();
|
pcursor->SeekToFirst();
|
||||||
|
|
||||||
|
@ -815,24 +816,30 @@ bool CNCCTrieCache::getInfoForName(const std::string name, CNodeValue& val) cons
|
||||||
|
|
||||||
bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight) const
|
bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight) const
|
||||||
{
|
{
|
||||||
|
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);
|
assert(nHeight == nCurrentHeight);
|
||||||
return addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nHeight + DEFAULT_DELAY);
|
return addClaimToQueue(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
|
bool CNCCTrieCache::addClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, uint256 prevTxhash, uint32_t nPrevOut) const
|
||||||
{
|
{
|
||||||
|
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);
|
assert(nHeight == nCurrentHeight);
|
||||||
CNodeValue val;
|
CNodeValue val;
|
||||||
if (getInfoForName(name, val))
|
if (getInfoForName(name, val))
|
||||||
{
|
{
|
||||||
if (val.txhash == prevTxhash && val.nOut == nPrevOut)
|
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 addClaimToQueue(name, txhash, nOut, nAmount, nHeight, nHeight);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return addClaim(name, txhash, nOut, nAmount, nHeight);
|
return addClaim(name, txhash, nOut, nAmount, nHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CNCCTrieCache::undoSpendClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
|
bool CNCCTrieCache::undoSpendClaim(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
|
||||||
{
|
{
|
||||||
|
LogPrintf("%s: name: %s, txhash: %s, nOut: %d, nAmount: %d, nHeight: %d, nValidAtHeight: %d, nCurrentHeight: %d\n", __func__, name, txhash.GetHex(), nOut, nAmount, nHeight, nValidAtHeight, nCurrentHeight);
|
||||||
if (nValidAtHeight < nCurrentHeight)
|
if (nValidAtHeight < nCurrentHeight)
|
||||||
{
|
{
|
||||||
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
||||||
|
@ -848,6 +855,7 @@ bool CNCCTrieCache::undoSpendClaim(const std::string name, uint256 txhash, uint3
|
||||||
|
|
||||||
bool CNCCTrieCache::addClaimToQueue(const std::string name, uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight, int nValidAtHeight) const
|
bool CNCCTrieCache::addClaimToQueue(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);
|
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
||||||
CValueQueueEntry entry(name, val);
|
CValueQueueEntry entry(name, val);
|
||||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nValidAtHeight, true);
|
valueQueueType::iterator itQueueRow = getQueueCacheRow(nValidAtHeight, true);
|
||||||
|
@ -893,6 +901,7 @@ 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
|
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);
|
||||||
if (nHeight + DEFAULT_DELAY >= nCurrentHeight)
|
if (nHeight + DEFAULT_DELAY >= nCurrentHeight)
|
||||||
{
|
{
|
||||||
if (removeClaimFromQueue(name, txhash, nOut, nHeight + DEFAULT_DELAY, nValidAtHeight))
|
if (removeClaimFromQueue(name, txhash, nOut, nHeight + DEFAULT_DELAY, nValidAtHeight))
|
||||||
|
@ -907,6 +916,7 @@ bool CNCCTrieCache::removeClaim(const std::string name, uint256 txhash, uint32_t
|
||||||
|
|
||||||
bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& undo) const
|
bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& undo) const
|
||||||
{
|
{
|
||||||
|
LogPrintf("%s: nCurrentHeight (before increment): %d\n", __func__, nCurrentHeight);
|
||||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
|
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
|
||||||
nCurrentHeight++;
|
nCurrentHeight++;
|
||||||
if (itQueueRow == valueQueueCache.end())
|
if (itQueueRow == valueQueueCache.end())
|
||||||
|
@ -924,6 +934,7 @@ bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& undo) const
|
||||||
|
|
||||||
bool CNCCTrieCache::decrementBlock(CNCCTrieQueueUndo& undo) const
|
bool CNCCTrieCache::decrementBlock(CNCCTrieQueueUndo& undo) const
|
||||||
{
|
{
|
||||||
|
LogPrintf("%s: nCurrentHeight (before decrement): %d\n", __func__, nCurrentHeight);
|
||||||
nCurrentHeight--;
|
nCurrentHeight--;
|
||||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, true);
|
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, true);
|
||||||
for (CNCCTrieQueueUndo::iterator itUndo = undo.begin(); itUndo != undo.end(); ++itUndo)
|
for (CNCCTrieQueueUndo::iterator itUndo = undo.begin(); itUndo != undo.end(); ++itUndo)
|
||||||
|
@ -966,7 +977,7 @@ bool CNCCTrieCache::flush()
|
||||||
{
|
{
|
||||||
if (dirty())
|
if (dirty())
|
||||||
getMerkleHash();
|
getMerkleHash();
|
||||||
bool success = base->update(cache, cacheHashes, hashBlock, valueQueueCache, nCurrentHeight);
|
bool success = base->update(cache, cacheHashes, getBestBlock(), valueQueueCache, nCurrentHeight);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
success = clear();
|
success = clear();
|
||||||
|
|
|
@ -149,7 +149,7 @@ class CNCCTrieCache;
|
||||||
class CNCCTrie
|
class CNCCTrie
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CNCCTrie() : db(GetDataDir() / "ncctrie", 100, false, false), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
|
CNCCTrie() : db(GetDataDir() / "ncctrie", 100, false, false), nCurrentHeight(1), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
|
||||||
uint256 getMerkleHash();
|
uint256 getMerkleHash();
|
||||||
CLevelDBWrapper db;
|
CLevelDBWrapper db;
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
@ -207,7 +207,8 @@ private:
|
||||||
mutable std::set<std::string> dirtyHashes;
|
mutable std::set<std::string> dirtyHashes;
|
||||||
mutable hashMapType cacheHashes;
|
mutable hashMapType cacheHashes;
|
||||||
mutable valueQueueType valueQueueCache;
|
mutable valueQueueType valueQueueCache;
|
||||||
mutable int nCurrentHeight;
|
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;
|
uint256 computeHash() const;
|
||||||
bool recursiveComputeMerkleHash(CNCCTrieNode* tnCurrent, std::string sPos) const;
|
bool recursiveComputeMerkleHash(CNCCTrieNode* tnCurrent, std::string sPos) const;
|
||||||
bool recursivePruneName(CNCCTrieNode* tnCurrent, unsigned int nPos, std::string sName, bool* pfNullified = NULL) const;
|
bool recursivePruneName(CNCCTrieNode* tnCurrent, unsigned int nPos, std::string sName, bool* pfNullified = NULL) const;
|
||||||
|
|
|
@ -246,17 +246,15 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
mempool.clear();
|
mempool.clear();
|
||||||
|
|
||||||
/* TODO: fix this
|
|
||||||
// subsidy changing
|
// subsidy changing
|
||||||
int nHeight = chainActive.Height();
|
int nHeight = chainActive.Height();
|
||||||
chainActive.Tip()->nHeight = 209999;
|
chainActive.Tip()->nHeight = 2099999;
|
||||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
chainActive.Tip()->nHeight = 210000;
|
chainActive.Tip()->nHeight = 2100000;
|
||||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
chainActive.Tip()->nHeight = nHeight;
|
chainActive.Tip()->nHeight = nHeight;
|
||||||
*/
|
|
||||||
|
|
||||||
// non-final txs in mempool
|
// non-final txs in mempool
|
||||||
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
|
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
#include "miner.h"
|
||||||
#include "ncctrie.h"
|
#include "ncctrie.h"
|
||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
#include "streams.h"
|
#include "streams.h"
|
||||||
|
@ -31,18 +32,69 @@ CMutableTransaction BuildTransaction(const uint256& prevhash)
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachBlock(CNCCTrieCache& cache, std::vector<CNCCTrieQueueUndo>& block_undos)
|
CMutableTransaction BuildTransaction(const CMutableTransaction& prev)
|
||||||
{
|
{
|
||||||
CNCCTrieQueueUndo undo;
|
CMutableTransaction tx;
|
||||||
cache.incrementBlock(undo);
|
tx.nVersion = 1;
|
||||||
block_undos.push_back(undo);
|
tx.nLockTime = 0;
|
||||||
|
tx.vin.resize(1);
|
||||||
|
tx.vout.resize(1);
|
||||||
|
tx.vin[0].prevout.hash = prev.GetHash();
|
||||||
|
tx.vin[0].prevout.n = 0;
|
||||||
|
tx.vin[0].scriptSig = CScript();
|
||||||
|
tx.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
|
||||||
|
tx.vout[0].scriptPubKey = CScript();
|
||||||
|
tx.vout[0].nValue = prev.vout[0].nValue;
|
||||||
|
|
||||||
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetachBlock(CNCCTrieCache& cache, std::vector<CNCCTrieQueueUndo>& block_undos)
|
CMutableTransaction BuildTransaction(const CTransaction& prev)
|
||||||
{
|
{
|
||||||
CNCCTrieQueueUndo& undo = block_undos.back();
|
return BuildTransaction(CMutableTransaction(prev));
|
||||||
cache.decrementBlock(undo);
|
}
|
||||||
block_undos.pop_back();
|
|
||||||
|
void AddToMempool(CMutableTransaction& tx)
|
||||||
|
{
|
||||||
|
mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, GetTime(), 111.0, chainActive.Height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateBlock(CBlockTemplate* pblocktemplate, bool f = false)
|
||||||
|
{
|
||||||
|
static int unique_block_counter = 0;
|
||||||
|
CBlock* pblock = &pblocktemplate->block;
|
||||||
|
pblock->nVersion = 1;
|
||||||
|
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
|
||||||
|
CMutableTransaction txCoinbase(pblock->vtx[0]);
|
||||||
|
txCoinbase.vin[0].scriptSig = CScript() << CScriptNum(unique_block_counter++) << CScriptNum(chainActive.Height());
|
||||||
|
txCoinbase.vout[0].nValue = GetBlockValue(chainActive.Height(), 0);
|
||||||
|
pblock->vtx[0] = CTransaction(txCoinbase);
|
||||||
|
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
||||||
|
for (int i = 0; ; ++i)
|
||||||
|
{
|
||||||
|
pblock->nNonce = i;
|
||||||
|
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CValidationState state;
|
||||||
|
bool success = (ProcessNewBlock(state, NULL, pblock) && state.IsValid() && pblock->GetHash() == chainActive.Tip()->GetBlockHash());
|
||||||
|
pblock->hashPrevBlock = pblock->GetHash();
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoveBlock(uint256& blockhash)
|
||||||
|
{
|
||||||
|
CValidationState state;
|
||||||
|
if (mapBlockIndex.count(blockhash) == 0)
|
||||||
|
return false;
|
||||||
|
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
|
||||||
|
InvalidateBlock(state, pblockindex);
|
||||||
|
if (state.IsValid())
|
||||||
|
{
|
||||||
|
ActivateBestChain(state);
|
||||||
|
}
|
||||||
|
return state.IsValid();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ncctrie_merkle_hash)
|
BOOST_AUTO_TEST_CASE(ncctrie_merkle_hash)
|
||||||
|
@ -160,357 +212,497 @@ BOOST_AUTO_TEST_CASE(ncctrie_merkle_hash)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
||||||
{
|
{
|
||||||
std::vector<CNCCTrieQueueUndo> block_undos;
|
BOOST_CHECK(pnccTrie->nCurrentHeight == chainActive.Height() + 1);
|
||||||
int start_block = pnccTrie->nCurrentHeight;
|
|
||||||
int current_block = start_block;
|
CBlockTemplate *pblocktemplate;
|
||||||
|
LOCK(cs_main);
|
||||||
|
Checkpoints::fEnabled = false;
|
||||||
|
|
||||||
|
CScript scriptPubKey = CScript() << OP_TRUE;
|
||||||
|
|
||||||
|
std::string sName1("atest");
|
||||||
|
std::string sName2("btest");
|
||||||
|
std::string sValue1("testa");
|
||||||
|
std::string sValue2("testb");
|
||||||
|
|
||||||
|
std::vector<unsigned char> vchName1(sName1.begin(), sName1.end());
|
||||||
|
std::vector<unsigned char> vchName2(sName2.begin(), sName2.end());
|
||||||
|
std::vector<unsigned char> vchValue1(sValue1.begin(), sValue1.end());
|
||||||
|
std::vector<unsigned char> vchValue2(sValue2.begin(), sValue2.end());
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
std::vector<CTransaction> coinbases;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 103; ++i)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
if (coinbases.size() < 3)
|
||||||
|
coinbases.push_back(CTransaction(pblocktemplate->block.vtx[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
CMutableTransaction tx1 = BuildTransaction(hash0);
|
|
||||||
CMutableTransaction tx2 = BuildTransaction(tx1.GetHash());
|
|
||||||
CMutableTransaction tx3 = BuildTransaction(tx2.GetHash());
|
|
||||||
CMutableTransaction tx4 = BuildTransaction(tx3.GetHash());
|
|
||||||
int tx1_height, tx2_height, tx3_height, tx4_height, tx1_undo_height, tx3_undo_height;
|
|
||||||
|
|
||||||
BOOST_CHECK(pnccTrie->getMerkleHash() == hash0);
|
BOOST_CHECK(pnccTrie->getMerkleHash() == hash0);
|
||||||
|
|
||||||
CNCCTrieCache ntState(pnccTrie);
|
CMutableTransaction tx1 = BuildTransaction(coinbases[0]);
|
||||||
|
tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue1 << OP_2DROP << OP_DROP << OP_TRUE;
|
||||||
|
CMutableTransaction tx2 = BuildTransaction(coinbases[1]);
|
||||||
|
tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName2 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE;
|
||||||
|
CMutableTransaction tx3 = BuildTransaction(tx1);
|
||||||
|
tx3.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue1 << OP_2DROP << OP_DROP << OP_TRUE;
|
||||||
|
CMutableTransaction tx4 = BuildTransaction(tx2);
|
||||||
|
tx4.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||||
|
CMutableTransaction tx5 = BuildTransaction(coinbases[2]);
|
||||||
|
tx5.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName2 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE;
|
||||||
|
CMutableTransaction tx6 = BuildTransaction(tx3);
|
||||||
|
tx6.vout[0].scriptPubKey = CScript() << OP_TRUE;
|
||||||
|
|
||||||
tx1_height = current_block;
|
|
||||||
ntState.addClaim(std::string("atest"), tx1.GetHash(), 0, 50, tx1_height);
|
|
||||||
tx3_height = current_block;
|
|
||||||
ntState.addClaim(std::string("btest"), tx3.GetHash(), 0, 50, tx3_height);
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
current_block++;
|
|
||||||
ntState.flush();
|
|
||||||
for (; current_block < start_block + 100; ++current_block)
|
|
||||||
{
|
|
||||||
CNCCTrieCache s(pnccTrie);
|
|
||||||
AttachBlock(s, block_undos);
|
|
||||||
s.flush();
|
|
||||||
}
|
|
||||||
CNodeValue v;
|
|
||||||
BOOST_CHECK(!pnccTrie->getInfoForName(std::string("atest"), v));
|
|
||||||
BOOST_CHECK(!pnccTrie->getInfoForName(std::string("btest"), v));
|
|
||||||
|
|
||||||
CNCCTrieCache ntState1(pnccTrie);
|
|
||||||
AttachBlock(ntState1, block_undos);
|
|
||||||
ntState1.flush();
|
|
||||||
current_block++;
|
|
||||||
|
|
||||||
CNCCTrieCache ntState2(pnccTrie);
|
|
||||||
BOOST_CHECK(pnccTrie->getInfoForName(std::string("atest"), v));
|
|
||||||
BOOST_CHECK(pnccTrie->getInfoForName(std::string("btest"), v));
|
|
||||||
|
|
||||||
BOOST_CHECK(ntState2.spendClaim(std::string("atest"), tx1.GetHash(), 0, tx1_height, tx1_undo_height));
|
|
||||||
BOOST_CHECK(ntState2.spendClaim(std::string("btest"), tx3.GetHash(), 0, tx3_height, tx3_undo_height));
|
|
||||||
|
|
||||||
tx2_height = current_block;
|
|
||||||
ntState2.addClaim(std::string("atest"), tx2.GetHash(), 0, 50, tx2_height, tx1.GetHash(), 0);
|
|
||||||
tx4_height = current_block;
|
|
||||||
ntState2.addClaim(std::string("btest"), tx4.GetHash(), 0, 50, tx4_height);
|
|
||||||
|
|
||||||
AttachBlock(ntState2, block_undos);
|
|
||||||
current_block++;
|
|
||||||
ntState2.flush();
|
|
||||||
|
|
||||||
BOOST_CHECK(pnccTrie->getInfoForName(std::string("atest"), v));
|
|
||||||
BOOST_CHECK(!pnccTrie->getInfoForName(std::string("btest"), v));
|
|
||||||
BOOST_CHECK(v.txhash == tx2.GetHash());
|
|
||||||
|
|
||||||
CNCCTrieCache ntState3(pnccTrie);
|
|
||||||
DetachBlock(ntState3, block_undos);
|
|
||||||
current_block--;
|
|
||||||
BOOST_CHECK(ntState3.undoAddClaim(std::string("atest"), tx2.GetHash(), 0, tx2_height));
|
|
||||||
BOOST_CHECK(ntState3.undoAddClaim(std::string("btest"), tx4.GetHash(), 0, tx4_height));
|
|
||||||
ntState3.undoSpendClaim(std::string("atest"), tx1.GetHash(), 0, 50, tx1_height, tx1_undo_height);
|
|
||||||
ntState3.undoSpendClaim(std::string("btest"), tx3.GetHash(), 0, 50, tx3_height, tx3_undo_height);
|
|
||||||
ntState3.flush();
|
|
||||||
|
|
||||||
for (; current_block > start_block; --current_block)
|
|
||||||
{
|
|
||||||
CNCCTrieCache s(pnccTrie);
|
|
||||||
DetachBlock(s, block_undos);
|
|
||||||
s.flush();
|
|
||||||
}
|
|
||||||
CNCCTrieCache ntState4(pnccTrie);
|
|
||||||
BOOST_CHECK(ntState4.undoAddClaim(std::string("atest"), tx1.GetHash(), 0, tx1_height));
|
|
||||||
BOOST_CHECK(ntState4.undoAddClaim(std::string("btest"), tx3.GetHash(), 0, tx3_height));
|
|
||||||
ntState4.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->getMerkleHash() == hash0);
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ncctrie_undo)
|
|
||||||
{
|
|
||||||
std::vector<CNCCTrieQueueUndo> block_undos;
|
|
||||||
int start_block = pnccTrie->nCurrentHeight;
|
|
||||||
int current_block = start_block;
|
|
||||||
CNodeValue val;
|
CNodeValue val;
|
||||||
|
|
||||||
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
std::vector<uint256> blocks_to_invalidate;
|
||||||
CMutableTransaction tx1 = BuildTransaction(hash0);
|
|
||||||
CMutableTransaction tx2 = BuildTransaction(tx1.GetHash());
|
|
||||||
int tx1_height, tx2_height;
|
|
||||||
int tx1_undo_height, tx2_undo_height;
|
|
||||||
|
|
||||||
|
// Verify updates to the best claim get inserted immediately, and others don't.
|
||||||
|
|
||||||
|
// Put tx1 and tx2 into the blockchain, and then advance 100 blocks to put them in the trie
|
||||||
|
|
||||||
|
AddToMempool(tx1);
|
||||||
|
AddToMempool(tx2);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 3);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pcoinsTip->HaveCoins(tx1.GetHash()));
|
||||||
|
BOOST_CHECK(pcoinsTip->HaveCoins(tx2.GetHash()));
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
for (unsigned int i = 1; i < 100; ++i)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
}
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(!pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(!pnccTrie->getInfoForName(sName2, val));
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
// Verify tx1 and tx2 are in the trie
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName2, val));
|
||||||
|
|
||||||
|
// Spend tx1 with tx3, tx2 with tx4, and put in tx5.
|
||||||
|
|
||||||
|
AddToMempool(tx3);
|
||||||
|
AddToMempool(tx4);
|
||||||
|
AddToMempool(tx5);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 4);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
// Verify tx1, tx2, and tx5 are not in the trie, but tx3 is in the trie.
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(val.txhash == tx3.GetHash());
|
||||||
|
BOOST_CHECK(!pnccTrie->getInfoForName(sName2, val));
|
||||||
|
|
||||||
|
// Roll back the last block, make sure tx1 and tx2 are put back in the trie
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(val.txhash == tx1.GetHash());
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName2, val));
|
||||||
|
BOOST_CHECK(val.txhash == tx2.GetHash());
|
||||||
|
|
||||||
|
// Roll all the way back, make sure all txs are out of the trie
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(!pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(!pnccTrie->getInfoForName(sName2, val));
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->getMerkleHash() == hash0);
|
BOOST_CHECK(pnccTrie->getMerkleHash() == hash0);
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
CNCCTrieCache ntState(pnccTrie);
|
// Test undoing a claim before the claim gets into the trie
|
||||||
|
|
||||||
std::string name("a");
|
// Put tx1 in the chain, and then undo that block.
|
||||||
|
|
||||||
/* Test undoing a claim before the claim gets into the trie */
|
AddToMempool(tx1);
|
||||||
|
|
||||||
// make claim at start_block
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
tx1_height = current_block;
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
ntState.addClaim(name, tx1.GetHash(), 0, 50, tx1_height);
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
AttachBlock(ntState, block_undos);
|
BOOST_CHECK(CreateBlock(pblocktemplate, true));
|
||||||
current_block++;
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
ntState.flush();
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
|
||||||
|
// Make sure it's not in the queue
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
|
// Test undoing a claim that has gotten into the trie
|
||||||
|
|
||||||
|
// Put tx1 in the chain, and then advance until it's in the trie
|
||||||
|
|
||||||
|
AddToMempool(tx1);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
// undo block and remove claim
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
DetachBlock(ntState, block_undos);
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
current_block--;
|
for (unsigned int i = 1; i < 100; ++i)
|
||||||
ntState.undoAddClaim(name, tx1.GetHash(), 0, tx1_height);
|
{
|
||||||
ntState.flush();
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
}
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(!pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(val.txhash == tx1.GetHash());
|
||||||
|
|
||||||
|
// Remove it from the trie
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
|
// Test undoing a spend which involves a claim just inserted into the queue
|
||||||
|
|
||||||
|
// Immediately spend tx2 with tx4, verify nothing gets put in the trie
|
||||||
|
|
||||||
|
AddToMempool(tx2);
|
||||||
|
AddToMempool(tx4);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 3);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
/* Test undoing a claim that has gotten into the trie */
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
// make claim at start_block
|
// Test undoing a spend which involves a claim inserted into the queue by a previous block
|
||||||
tx1_height = current_block;
|
|
||||||
ntState.addClaim(name, tx1.GetHash(), 0, 50, tx1_height);
|
// Put tx2 into the chain, and then advance a few blocks but not far enough for it to get into the trie
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
current_block++;
|
AddToMempool(tx2);
|
||||||
ntState.flush();
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
// move to block start_block + 101
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
for (; current_block < start_block + 101; ++current_block)
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
for (unsigned int i = 1; i < 50; ++i)
|
||||||
{
|
{
|
||||||
AttachBlock(ntState, block_undos);
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
ntState.flush();
|
|
||||||
}
|
}
|
||||||
|
delete pblocktemplate;
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
// Spend tx2 with tx4, and then advance to where tx2 would be inserted into the trie and verify it hasn't happened
|
||||||
|
|
||||||
|
AddToMempool(tx4);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
for (unsigned int i = 1; i < 51; ++i)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
}
|
||||||
|
delete pblocktemplate;
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
// Undo spending tx2 with tx4, and then advance and verify tx2 is inserted into the trie when it should be
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
for (unsigned int i = 0; i < 50; ++i)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
}
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
delete pblocktemplate;
|
||||||
|
BOOST_CHECK(!pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName2, val));
|
||||||
|
BOOST_CHECK(val.txhash == tx2.GetHash());
|
||||||
|
|
||||||
|
// Test undoing a spend which involves a claim in the trie
|
||||||
|
|
||||||
|
// spend tx2, which is in the trie, with tx4
|
||||||
|
|
||||||
|
AddToMempool(tx4);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
// undo spending tx2 with tx4, and verify tx2 is back in the trie
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(!pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
|
// roll back to the beginning
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
|
// Test undoing a spent update which updated a claim still in the queue
|
||||||
|
|
||||||
|
// Create the original claim (tx1)
|
||||||
|
|
||||||
|
AddToMempool(tx1);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate, true));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
// move forward some, but not far enough for the claim to get into the trie
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
for (unsigned int i = 1; i < 50; ++i)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
}
|
||||||
|
delete pblocktemplate;
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
// update the original claim (tx3 spends tx1)
|
||||||
|
|
||||||
|
AddToMempool(tx3);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
// spend the update (tx6 spends tx3)
|
||||||
|
|
||||||
|
AddToMempool(tx6);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
// undo spending the update (undo tx6 spending tx3)
|
||||||
|
|
||||||
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
mempool.clear();
|
||||||
|
|
||||||
|
// make sure the update (tx3) still goes into effect in 100 blocks
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
for (unsigned int i = 1; i < 100; ++i)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate, true));
|
||||||
|
}
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
BOOST_CHECK(!pnccTrie->empty());
|
BOOST_CHECK(!pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
// undo block and remove claim
|
// undo updating the original claim (tx3 spends tx1)
|
||||||
for (; current_block > start_block; --current_block)
|
|
||||||
{
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
ntState.undoAddClaim(name, tx1.GetHash(), 0, tx1_height);
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
/* Test undoing a spend which involves a claim just inserted into the queue */
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
|
blocks_to_invalidate.pop_back();
|
||||||
// make and spend claim at start_block
|
|
||||||
tx1_height = current_block;
|
|
||||||
ntState.addClaim(name, tx1.GetHash(), 0, 50, tx1_height);
|
|
||||||
ntState.spendClaim(name, tx1.GetHash(), 0, tx1_height, tx1_undo_height);
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
current_block++;
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
// roll back the block
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
current_block--;
|
|
||||||
ntState.undoSpendClaim(name, tx1.GetHash(), 0, 50, tx1_height, tx1_undo_height);
|
|
||||||
ntState.undoAddClaim(name, tx1.GetHash(), 0, tx1_height);
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
/* Test undoing a spend which involves a claim inserted into the queue by a previous block*/
|
|
||||||
|
|
||||||
// make claim at block start_block
|
|
||||||
tx1_height = current_block;
|
|
||||||
ntState.addClaim(name, tx1.GetHash(), 0, 50, tx1_height);
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
current_block++;
|
|
||||||
ntState.flush();
|
|
||||||
|
|
||||||
// spend the claim in block start_block + 50
|
|
||||||
for (; current_block < start_block + 50; ++current_block)
|
|
||||||
{
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
ntState.spendClaim(name, tx1.GetHash(), 0, tx1_height, tx1_undo_height);
|
mempool.clear();
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
++current_block;
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
// attach block start_block + 100 and make sure nothing is inserted
|
// Test undoing an spent update which updated the best claim to a name
|
||||||
for (; current_block < start_block + 101; ++current_block)
|
|
||||||
{
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
// roll back to block start_block + 50 and undo the spend
|
// move forward until the original claim is inserted into the trie
|
||||||
for (; current_block > start_block + 50; --current_block)
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
for (unsigned int i = 0; i < 50; ++i)
|
||||||
{
|
{
|
||||||
DetachBlock(ntState, block_undos);
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
ntState.flush();
|
|
||||||
}
|
}
|
||||||
ntState.undoSpendClaim(name, tx1.GetHash(), 0, 50, tx1_height, tx1_undo_height);
|
delete pblocktemplate;
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||||
|
|
||||||
// make sure it still gets inserted at block start_block + 100
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
for (; current_block < start_block + 100; ++current_block)
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
{
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
AttachBlock(ntState, block_undos);
|
delete pblocktemplate;
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
++current_block;
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(!pnccTrie->empty());
|
BOOST_CHECK(!pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(val.txhash == tx1.GetHash());
|
||||||
|
|
||||||
/* Test undoing a spend which involves a claim in the trie */
|
// update the original claim (tx3 spends tx1)
|
||||||
|
|
||||||
|
AddToMempool(tx3);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
// spend the claim at block start_block + 150
|
|
||||||
for (; current_block < start_block + 150; ++current_block)
|
|
||||||
{
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
BOOST_CHECK(!pnccTrie->empty());
|
BOOST_CHECK(!pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
ntState.spendClaim(name, tx1.GetHash(), 0, tx1_height, tx1_undo_height);
|
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||||
AttachBlock(ntState, block_undos);
|
BOOST_CHECK(val.txhash == tx3.GetHash());
|
||||||
++current_block;
|
|
||||||
ntState.flush();
|
// spend the update (tx6 spends tx3)
|
||||||
|
|
||||||
|
AddToMempool(tx6);
|
||||||
|
|
||||||
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
|
BOOST_CHECK(pblocktemplate->block.vtx.size() == 2);
|
||||||
|
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||||
|
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||||
|
blocks_to_invalidate.push_back(pblocktemplate->block.hashPrevBlock);
|
||||||
|
delete pblocktemplate;
|
||||||
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
// roll back the block
|
// undo spending the update (undo tx6 spending tx3)
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
--current_block;
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
ntState.undoSpendClaim(name, tx1.GetHash(), 0, 50, tx1_height, tx1_undo_height);
|
blocks_to_invalidate.pop_back();
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(!pnccTrie->empty());
|
BOOST_CHECK(!pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||||
|
BOOST_CHECK(val.txhash == tx3.GetHash());
|
||||||
|
|
||||||
/* Test undoing an spent update which updated the best claim to a name*/
|
// roll all the way back
|
||||||
|
|
||||||
// update the claim at block start_block + 150
|
BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back()));
|
||||||
tx2_height = current_block;
|
blocks_to_invalidate.pop_back();
|
||||||
ntState.spendClaim(name, tx1.GetHash(), 0, tx1_height, tx1_undo_height);
|
|
||||||
ntState.addClaim(name, tx2.GetHash(), 0, 75, tx2_height, tx1.GetHash(), 0);
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
++current_block;
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(!pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
// move forward a bit
|
|
||||||
for (; current_block < start_block + 200; ++current_block)
|
|
||||||
{
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
// spend the update
|
|
||||||
ntState.spendClaim(name, tx2.GetHash(), 0, tx2_height, tx2_undo_height);
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
++current_block;
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
BOOST_CHECK(pnccTrie->empty());
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||||
|
|
||||||
// undo the spend
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
--current_block;
|
|
||||||
ntState.undoSpendClaim(name, tx2.GetHash(), 0, 75, tx2_height, tx2_undo_height);
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(!pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
/* Test undoing a spent update which updated a claim still in the queue */
|
|
||||||
|
|
||||||
// roll everything back to block start_block + 50
|
|
||||||
for (; current_block > start_block + 151; --current_block)
|
|
||||||
{
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
--current_block;
|
|
||||||
ntState.undoAddClaim(name, tx2.GetHash(), 0, tx2_height);
|
|
||||||
ntState.undoSpendClaim(name, tx1.GetHash(), 0, 50, tx1_height, tx1_undo_height);
|
|
||||||
ntState.flush();
|
|
||||||
for (; current_block > start_block + 50; --current_block)
|
|
||||||
{
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
// update the claim at block start_block + 50
|
|
||||||
tx2_height = current_block;
|
|
||||||
ntState.spendClaim(name, tx1.GetHash(), 0, tx1_height, tx1_undo_height);
|
|
||||||
ntState.addClaim(name, tx2.GetHash(), 0, 75, tx2_height, tx1.GetHash(), 0);
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
++current_block;
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
// check that it gets inserted at block start_block + 150
|
|
||||||
for (; current_block < start_block + 150; ++current_block)
|
|
||||||
{
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
|
||||||
AttachBlock(ntState, block_undos);
|
|
||||||
++current_block;
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(!pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
|
|
||||||
// roll back to start_block
|
|
||||||
for (; current_block > start_block + 50; --current_block)
|
|
||||||
{
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
ntState.undoAddClaim(name, tx2.GetHash(), 0, tx2_height);
|
|
||||||
ntState.undoSpendClaim(name, tx1.GetHash(), 0, 75, tx1_height, tx1_undo_height);
|
|
||||||
ntState.flush();
|
|
||||||
for (; current_block > start_block; --current_block)
|
|
||||||
{
|
|
||||||
DetachBlock(ntState, block_undos);
|
|
||||||
ntState.flush();
|
|
||||||
}
|
|
||||||
ntState.undoAddClaim(name, tx1.GetHash(), 0, tx1_height);
|
|
||||||
ntState.flush();
|
|
||||||
BOOST_CHECK(pnccTrie->empty());
|
|
||||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
|
||||||
BOOST_CHECK(pnccTrie->nCurrentHeight == start_block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ncctrienode_serialize_unserialize)
|
BOOST_AUTO_TEST_CASE(ncctrienode_serialize_unserialize)
|
||||||
|
|
Loading…
Reference in a new issue