finish enabling delayed ncc trie claim insertions, and rewrite the test for the delays so that it uses the actual block processing system
This commit is contained in:
parent
f2a7a5c401
commit
c8834c5551
7 changed files with 582 additions and 332 deletions
|
@ -123,7 +123,7 @@ public:
|
|||
nRejectBlockOutdatedMajority = 950;
|
||||
nToCheckBlockUpgradeMajority = 1000;
|
||||
nMinerThreads = 2;
|
||||
nTargetTimespan = 30 * 60 * 10;//14 * 24 * 60 * 60; // two weeks
|
||||
nTargetTimespan = 30 * 60 * 12;//14 * 24 * 60 * 60; // two weeks
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
if (!trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, nValidAtHeight))
|
||||
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);
|
||||
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);
|
||||
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__);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -281,6 +281,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
|||
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
|
||||
continue;
|
||||
|
||||
typedef std::map<std::string, std::pair<uint256, unsigned int> > spentClaimsType;
|
||||
spentClaimsType spentClaims;
|
||||
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
{
|
||||
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
||||
|
@ -303,6 +306,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
|||
int throwaway;
|
||||
if (!trieCache.spendClaim(name, txin.prevout.hash, txin.prevout.n, coins->nHeight, throwaway))
|
||||
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);
|
||||
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__);
|
||||
}
|
||||
}
|
||||
|
@ -372,6 +387,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
|||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
|
||||
pblock->nNonce = 0;
|
||||
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
|
||||
CNCCTrieQueueUndo dummyundo;
|
||||
trieCache.incrementBlock(dummyundo);
|
||||
pblock->hashNCCTrie = trieCache.getMerkleHash();
|
||||
|
||||
CValidationState state;
|
||||
|
|
|
@ -417,7 +417,8 @@ bool CNCCTrie::ReadFromDisk(bool check)
|
|||
{
|
||||
if (!db.Read('h', hashBlock))
|
||||
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());
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
CNodeValue val;
|
||||
if (getInfoForName(name, val))
|
||||
{
|
||||
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 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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
LogPrintf("%s: nValidAtHeight: %d\n", __func__, nValidAtHeight);
|
||||
CNodeValue val(txhash, nOut, nAmount, nHeight, nValidAtHeight);
|
||||
CValueQueueEntry entry(name, val);
|
||||
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
|
||||
{
|
||||
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 (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
|
||||
{
|
||||
LogPrintf("%s: nCurrentHeight (before increment): %d\n", __func__, nCurrentHeight);
|
||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, false);
|
||||
nCurrentHeight++;
|
||||
if (itQueueRow == valueQueueCache.end())
|
||||
|
@ -924,6 +934,7 @@ bool CNCCTrieCache::incrementBlock(CNCCTrieQueueUndo& undo) const
|
|||
|
||||
bool CNCCTrieCache::decrementBlock(CNCCTrieQueueUndo& undo) const
|
||||
{
|
||||
LogPrintf("%s: nCurrentHeight (before decrement): %d\n", __func__, nCurrentHeight);
|
||||
nCurrentHeight--;
|
||||
valueQueueType::iterator itQueueRow = getQueueCacheRow(nCurrentHeight, true);
|
||||
for (CNCCTrieQueueUndo::iterator itUndo = undo.begin(); itUndo != undo.end(); ++itUndo)
|
||||
|
@ -966,7 +977,7 @@ bool CNCCTrieCache::flush()
|
|||
{
|
||||
if (dirty())
|
||||
getMerkleHash();
|
||||
bool success = base->update(cache, cacheHashes, hashBlock, valueQueueCache, nCurrentHeight);
|
||||
bool success = base->update(cache, cacheHashes, getBestBlock(), valueQueueCache, nCurrentHeight);
|
||||
if (success)
|
||||
{
|
||||
success = clear();
|
||||
|
|
|
@ -149,7 +149,7 @@ class CNCCTrieCache;
|
|||
class CNCCTrie
|
||||
{
|
||||
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();
|
||||
CLevelDBWrapper db;
|
||||
bool empty() const;
|
||||
|
@ -207,7 +207,8 @@ private:
|
|||
mutable std::set<std::string> dirtyHashes;
|
||||
mutable hashMapType cacheHashes;
|
||||
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;
|
||||
bool recursiveComputeMerkleHash(CNCCTrieNode* tnCurrent, std::string sPos) 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;
|
||||
mempool.clear();
|
||||
|
||||
/* TODO: fix this
|
||||
// subsidy changing
|
||||
int nHeight = chainActive.Height();
|
||||
chainActive.Tip()->nHeight = 209999;
|
||||
chainActive.Tip()->nHeight = 2099999;
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
delete pblocktemplate;
|
||||
chainActive.Tip()->nHeight = 210000;
|
||||
chainActive.Tip()->nHeight = 2100000;
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
delete pblocktemplate;
|
||||
chainActive.Tip()->nHeight = nHeight;
|
||||
*/
|
||||
|
||||
// non-final txs in mempool
|
||||
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "main.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "miner.h"
|
||||
#include "ncctrie.h"
|
||||
#include "coins.h"
|
||||
#include "streams.h"
|
||||
|
@ -31,18 +32,69 @@ CMutableTransaction BuildTransaction(const uint256& prevhash)
|
|||
return tx;
|
||||
}
|
||||
|
||||
void AttachBlock(CNCCTrieCache& cache, std::vector<CNCCTrieQueueUndo>& block_undos)
|
||||
CMutableTransaction BuildTransaction(const CMutableTransaction& prev)
|
||||
{
|
||||
CNCCTrieQueueUndo undo;
|
||||
cache.incrementBlock(undo);
|
||||
block_undos.push_back(undo);
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 1;
|
||||
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();
|
||||
cache.decrementBlock(undo);
|
||||
block_undos.pop_back();
|
||||
return BuildTransaction(CMutableTransaction(prev));
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -160,357 +212,497 @@ BOOST_AUTO_TEST_CASE(ncctrie_merkle_hash)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(ncctrie_insert_update_claim)
|
||||
{
|
||||
std::vector<CNCCTrieQueueUndo> block_undos;
|
||||
int start_block = pnccTrie->nCurrentHeight;
|
||||
int current_block = start_block;
|
||||
BOOST_CHECK(pnccTrie->nCurrentHeight == chainActive.Height() + 1);
|
||||
|
||||
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"));
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||
CMutableTransaction tx1 = BuildTransaction(hash0);
|
||||
CMutableTransaction tx2 = BuildTransaction(tx1.GetHash());
|
||||
int tx1_height, tx2_height;
|
||||
int tx1_undo_height, tx2_undo_height;
|
||||
std::vector<uint256> blocks_to_invalidate;
|
||||
|
||||
// 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->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
|
||||
tx1_height = current_block;
|
||||
ntState.addClaim(name, tx1.GetHash(), 0, 50, tx1_height);
|
||||
AttachBlock(ntState, block_undos);
|
||||
current_block++;
|
||||
ntState.flush();
|
||||
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(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());
|
||||
|
||||
// undo block and remove claim
|
||||
DetachBlock(ntState, block_undos);
|
||||
current_block--;
|
||||
ntState.undoAddClaim(name, tx1.GetHash(), 0, tx1_height);
|
||||
ntState.flush();
|
||||
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->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());
|
||||
|
||||
/* 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
|
||||
tx1_height = current_block;
|
||||
ntState.addClaim(name, tx1.GetHash(), 0, 50, tx1_height);
|
||||
AttachBlock(ntState, block_undos);
|
||||
current_block++;
|
||||
ntState.flush();
|
||||
// Test undoing a spend which involves a claim inserted into the queue by a previous block
|
||||
|
||||
// Put tx2 into the chain, and then advance a few blocks but not far enough for it to get into the trie
|
||||
|
||||
AddToMempool(tx2);
|
||||
|
||||
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());
|
||||
|
||||
// move to block start_block + 101
|
||||
for (; current_block < start_block + 101; ++current_block)
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 1; i < 50; ++i)
|
||||
{
|
||||
AttachBlock(ntState, block_undos);
|
||||
ntState.flush();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
}
|
||||
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->queueEmpty());
|
||||
|
||||
// undo block and remove claim
|
||||
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());
|
||||
// undo updating the original claim (tx3 spends tx1)
|
||||
|
||||
/* Test undoing a spend which involves a claim just inserted into the queue */
|
||||
|
||||
// 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(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||
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());
|
||||
mempool.clear();
|
||||
|
||||
// attach block start_block + 100 and make sure nothing is inserted
|
||||
for (; current_block < start_block + 101; ++current_block)
|
||||
{
|
||||
AttachBlock(ntState, block_undos);
|
||||
ntState.flush();
|
||||
}
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(pnccTrie->queueEmpty());
|
||||
// Test undoing an spent update which updated the best claim to a name
|
||||
|
||||
// roll back to block start_block + 50 and undo the spend
|
||||
for (; current_block > start_block + 50; --current_block)
|
||||
// move forward until the original claim is inserted into the trie
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
|
||||
for (unsigned int i = 0; i < 50; ++i)
|
||||
{
|
||||
DetachBlock(ntState, block_undos);
|
||||
ntState.flush();
|
||||
BOOST_CHECK(CreateBlock(pblocktemplate));
|
||||
}
|
||||
ntState.undoSpendClaim(name, tx1.GetHash(), 0, 50, tx1_height, tx1_undo_height);
|
||||
ntState.flush();
|
||||
delete pblocktemplate;
|
||||
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
BOOST_CHECK(!pnccTrie->queueEmpty());
|
||||
|
||||
// make sure it still gets inserted at block start_block + 100
|
||||
for (; current_block < start_block + 100; ++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(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());
|
||||
|
||||
/* 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->queueEmpty());
|
||||
ntState.spendClaim(name, tx1.GetHash(), 0, tx1_height, tx1_undo_height);
|
||||
AttachBlock(ntState, block_undos);
|
||||
++current_block;
|
||||
ntState.flush();
|
||||
BOOST_CHECK(pnccTrie->getInfoForName(sName1, val));
|
||||
BOOST_CHECK(val.txhash == tx3.GetHash());
|
||||
|
||||
// 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());
|
||||
|
||||
// roll back the block
|
||||
DetachBlock(ntState, block_undos);
|
||||
--current_block;
|
||||
ntState.undoSpendClaim(name, tx1.GetHash(), 0, 50, tx1_height, tx1_undo_height);
|
||||
ntState.flush();
|
||||
// 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());
|
||||
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
|
||||
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());
|
||||
|
||||
// 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(RemoveBlock(blocks_to_invalidate.back()));
|
||||
blocks_to_invalidate.pop_back();
|
||||
BOOST_CHECK(pnccTrie->empty());
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue