Rename CClaimTrieCache to CClaimTrieUpdateBuffer #156

Closed
kaykurokawa wants to merge 276 commits from cclaimtriecache_change into master
11 changed files with 268 additions and 74 deletions
Showing only changes of commit b2b0bd5bb5 - Show all commits

View file

@ -55,7 +55,7 @@ static void convertSeed6(std::vector<CAddress> &vSeedsOut, const SeedSpec6 *data
static Checkpoints::MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 0, uint256S("0x008c55867210a8154af697b7776c6b6cdb26972381eac9f84d18a491374464a3"));
( 0, uint256S("0x00ef6ded2b610fc5e4f06d187d12136bd5fba7b932fa0b66bf353c7c1648ec9c"));
/*static Checkpoints::MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
@ -148,10 +148,11 @@ public:
genesis.vtx.push_back(txNew);
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = genesis.BuildMerkleTree();
genesis.hashNCCTrie = uint256S("0x0000000000000000000000000000000000000000000000000000000000000001");
genesis.nVersion = 1;
genesis.nTime = 1417453734;
genesis.nBits = 0x207fffff;//0x1d00ffff;
genesis.nNonce = 110;
genesis.nNonce = 601;
/*bool found = false;
while (!found)
@ -170,7 +171,7 @@ public:
hashGenesisBlock = genesis.GetHash();
//printf("%s\n", hashGenesisBlock.GetHex().c_str());
//assert(hashGenesisBlock == uint256("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(hashGenesisBlock == uint256S("0x008c55867210a8154af697b7776c6b6cdb26972381eac9f84d18a491374464a3"));
assert(hashGenesisBlock == uint256S("0x00ef6ded2b610fc5e4f06d187d12136bd5fba7b932fa0b66bf353c7c1648ec9c"));
//printf("%s\n", genesis.hashMerkleRoot.GetHex().c_str());
//assert(genesis.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
assert(genesis.hashMerkleRoot == uint256S("0xa7d51d407092059a2beeffab22e65d6176cfb3c33b93515109480aa7c81c9141"));

View file

@ -181,6 +181,8 @@ void Shutdown()
pcoinsdbview = NULL;
delete pblocktree;
pblocktree = NULL;
delete pnccTrie;
pnccTrie = NULL;
}
#ifdef ENABLE_WALLET
if (pwalletMain)
@ -1016,11 +1018,13 @@ bool AppInit2(boost::thread_group& threadGroup)
delete pcoinsdbview;
delete pcoinscatcher;
delete pblocktree;
delete pnccTrie;
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
pnccTrie = new CNCCTrie();
if (fReindex)
pblocktree->WriteReindexing(true);
@ -1053,6 +1057,11 @@ bool AppInit2(boost::thread_group& threadGroup)
strLoadError = _("Corrupted block database detected");
break;
}
if (!pnccTrie->ReadFromDisk(true))
{
strLoadError = _("Error loading the ncc trie from disk");
break;
}
} catch (const std::exception& e) {
if (fDebug) LogPrintf("%s\n", e.what());
strLoadError = _("Error opening block database");

View file

@ -13,6 +13,7 @@
#include "checkqueue.h"
#include "init.h"
#include "merkleblock.h"
#include "ncc.h"
#include "net.h"
#include "pow.h"
#include "txdb.h"
@ -538,6 +539,7 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
}
CCoinsViewCache *pcoinsTip = NULL;
CNCCTrie *pnccTrie = NULL;
CBlockTreeDB *pblocktree = NULL;
//////////////////////////////////////////////////////////////////////////////
@ -1590,7 +1592,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
} // anon namespace
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, CNCCTrieCache& trieCache, bool* pfClean)
{
assert(pindex->GetBlockHash() == view.GetBestBlock());
@ -1632,6 +1634,22 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (*outs != outsBlock)
fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted");
// remove any NCC claims
for (unsigned int i = 0; i < tx.vout.size(); ++i)
{
const CTxOut& txout = tx.vout[i];
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeNCCScript(txout.scriptPubKey, op, vvchParams))
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.removeName(name, hash, i))
LogPrintf("Something went wrong removing the name");
}
}
// remove outputs
outs->Clear();
}
@ -1661,6 +1679,18 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output");
if (coins->vout.size() < out.n+1)
coins->vout.resize(out.n+1);
// restore NCC claim if applicable
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeNCCScript(undo.txout.scriptPubKey, op, vvchParams))
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.insertName(name, out.hash, out.n, undo.txout.nValue, undo.nHeight))
LogPrintf("Something went wrong inserting the name");
}
coins->vout[out.n] = undo.txout;
}
}
@ -1715,7 +1745,7 @@ static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 0;
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, CNCCTrieCache& trieCache, bool fJustCheck)
{
AssertLockHeld(cs_main);
// Check it again in case a previous version let a bad block in
@ -1811,6 +1841,37 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
assert(coins);
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeNCCScript(coins->vout[txin.prevout.n].scriptPubKey, op, vvchParams))
{
assert(vvchParams.size() == 1);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.removeName(name, txin.prevout.hash, txin.prevout.n))
LogPrintf("Something went wrong removing the name");
}
}
for (unsigned int i = 0; i < tx.vout.size(); ++i)
{
const CTxOut& txout = tx.vout[i];
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeNCCScript(txout.scriptPubKey, op, vvchParams))
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.insertName(name, tx.GetHash(), i, txout.nValue, pindex->nHeight))
LogPrintf("Something went wrong inserting the name");
}
}
}
CTxUndo undoDummy;
@ -1819,12 +1880,22 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
}
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
// TODO: This seems like a good place to actually change the
// TODO: tree of NCCs and make the CUndo vector for those changes.
// The CUndo vector contains all of the
// necessary information for putting NCC claims
// removed by this block back into the trie.
// (As long as the coinbase can't remove any
// NCC claims from the trie.)
vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
if (trieCache.getMerkleHash() != block.hashNCCTrie)
return state.DoS(100,
error("ConnectBlock() : the merkle root of the NCC trie does not match "
"(actual=%s vs block=%s)", trieCache.getMerkleHash().GetHex(),
block.hashNCCTrie.GetHex()), REJECT_INVALID, "bad-ncc-merkle-hash");
int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001);
@ -1999,9 +2070,11 @@ bool static DisconnectTip(CValidationState &state) {
int64_t nStart = GetTimeMicros();
{
CCoinsViewCache view(pcoinsTip);
if (!DisconnectBlock(block, state, pindexDelete, view))
CNCCTrieCache trieCache(pnccTrie);
if (!DisconnectBlock(block, state, pindexDelete, view, trieCache))
return error("DisconnectTip() : DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
assert(view.Flush());
assert(trieCache.flush());
}
LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
// Write the chain state to disk, if necessary.
@ -2054,8 +2127,9 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
{
CCoinsViewCache view(pcoinsTip);
CNCCTrieCache trieCache(pnccTrie);
CInv inv(MSG_BLOCK, pindexNew->GetBlockHash());
bool rv = ConnectBlock(*pblock, state, pindexNew, view);
bool rv = ConnectBlock(*pblock, state, pindexNew, view, trieCache);
g_signals.BlockChecked(*pblock, state);
if (!rv) {
if (state.IsInvalid())
@ -2066,6 +2140,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
assert(view.Flush());
assert(trieCache.flush());
}
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
LogPrint("bench", " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001);
@ -2630,9 +2705,13 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
}
}
// TODO: This looks like a good place to check the "merkle" root of the
// TODO: NCC tree that will result from applying this block
// TODO: ~~This looks like a good place to check the "merkle" root of the
// TODO: NCC tree that will result from applying this block.~~
// TODO: Actually, it's not, because the merkle root needs access to
// TODO: all of the coins spent by the new transactions, to check if
// TODO: they're NCC transactions. So the better place is in
// TODO: ConnectBlock, where inputs are checked against the coins
// TODO: they are spending.
return true;
}
@ -2772,6 +2851,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
assert(pindexPrev == chainActive.Tip());
CCoinsViewCache viewNew(pcoinsTip);
CNCCTrieCache trieCache(pnccTrie);
CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
@ -2783,7 +2863,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
return false;
if (!ContextualCheckBlock(block, state, pindexPrev))
return false;
if (!ConnectBlock(block, state, &indexDummy, viewNew, true))
if (!ConnectBlock(block, state, &indexDummy, viewNew, trieCache, true))
return false;
assert(state.IsValid());
@ -3000,6 +3080,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
CCoinsViewCache coins(coinsview);
CNCCTrieCache trieCache(pnccTrie);
CBlockIndex* pindexState = chainActive.Tip();
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
@ -3029,7 +3110,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= nCoinCacheSize) {
bool fClean = true;
if (!DisconnectBlock(block, state, pindex, coins, &fClean))
if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean))
return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
pindexState = pindex->pprev;
if (!fClean) {
@ -3054,7 +3135,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
CBlock block;
if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
if (!ConnectBlock(block, state, pindex, coins))
if (!ConnectBlock(block, state, pindex, coins, trieCache))
return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
}

View file

@ -16,6 +16,7 @@
#include "coins.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "ncctrie.h"
#include "net.h"
#include "pow.h"
#include "script/script.h"
@ -348,10 +349,10 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
* In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
* will be true if no problems were found. Otherwise, the return value will be false in case
* of problems. Note that in any case, coins may be modified. */
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, CNCCTrieCache& trieCache, bool* pfClean = NULL);
/** Apply the effects of this block (with given index) on the UTXO set represented by coins */
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, CNCCTrieCache& trieCache, bool fJustCheck = false);
/** Context-independent validity checks */
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
@ -510,6 +511,9 @@ extern CChain chainActive;
/** Global variable that points to the active CCoinsView (protected by cs_main) */
extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active CNCCTrie (protected by cs_main) */
extern CNCCTrie *pnccTrie;
/** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree;

View file

@ -9,6 +9,8 @@
#include "primitives/transaction.h"
#include "hash.h"
#include "main.h"
#include "ncc.h"
#include "ncctrie.h"
#include "net.h"
#include "pow.h"
#include "timedata.h"
@ -135,6 +137,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
CCoinsViewCache view(pcoinsTip);
CNCCTrieCache trieCache(pnccTrie);
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
@ -280,6 +283,43 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
UpdateCoins(tx, state, view, nHeight);
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
// This seems to happen during testing, and should never happen otherwise
if (!coins || txin.prevout.n >= coins->vout.size())
{
LogPrintf("!coins || txin.prevout.n >= coins->vout.size()");
continue;
}
std::vector<std::vector<unsigned char> > vvchParams;
int op;
if (DecodeNCCScript(coins->vout[txin.prevout.n].scriptPubKey, op, vvchParams))
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.removeName(name, txin.prevout.hash, txin.prevout.n))
LogPrintf("Something went wrong removing the name");
}
}
for (unsigned int i = 0; i < tx.vout.size(); ++i)
{
const CTxOut& txout = tx.vout[i];
std::vector<std::vector<unsigned char> > vvchParams;
int op;
if (DecodeNCCScript(txout.scriptPubKey, op, vvchParams))
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.insertName(name, tx.GetHash(), i, txout.nValue, nHeight))
LogPrintf("Something went wrong inserting the name");
}
}
// Added
pblock->vtx.push_back(tx);
pblocktemplate->vTxFees.push_back(nTxFees);
@ -329,6 +369,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
pblock->nNonce = 0;
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
pblock->hashNCCTrie = trieCache.getMerkleHash();
CValidationState state;
if (!TestBlockValidity(state, *pblock, pindexPrev, false, false))

View file

@ -1,4 +1,7 @@
#include "ncctrie.h"
#include "leveldbwrapper.h"
#include <boost/scoped_ptr.hpp>
std::string CNodeValue::ToString()
{
@ -79,6 +82,8 @@ bool CNCCTrie::empty() const
bool CNCCTrie::checkConsistency()
{
if (empty())
return true;
return recursiveCheckConsistency(&root);
}
@ -114,11 +119,6 @@ bool CNCCTrie::recursiveCheckConsistency(CNCCTrieNode* node)
return calculatedHash == node->hash;
}
/*bool cachesort (std::pair<std::string, CNCCTrieNode*>& i, std::pair<std::string, CNCCTrieNode*>& j)
{
return i.first.size() < j.first.size();
}*/
bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes)
{
// General strategy: the cache is ordered by length, ensuring child
@ -144,7 +144,6 @@ bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes)
{
return true;
}
//std::sort(cache.begin(), cache.end(), cachesort);
bool success = true;
std::vector<std::string> deletedNames;
for (nodeCacheType::iterator itcache = cache.begin(); itcache != cache.end(); ++itcache)
@ -263,6 +262,54 @@ bool CNCCTrie::BatchWrite(nodeCacheType& changedNodes, std::vector<std::string>&
return db.WriteBatch(batch);
}
bool CNCCTrie::InsertFromDisk(const std::string& name, CNCCTrieNode* node)
{
if (name.size() == 0)
root = *node;
return true;
CNCCTrieNode* current = &root;
for (std::string::const_iterator itname = name.begin(); itname + 1 != name.end(); ++itname)
{
nodeMapType::iterator itchild = current->children.find(*itname);
if (itchild == current->children.end())
return false;
current = itchild->second;
}
current->children[name[name.size()-1]] = node;
return true;
}
bool CNCCTrie::ReadFromDisk(bool check)
{
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
pcursor->SeekToFirst();
while (pcursor->Valid())
{
//TODO: make try statement here
{
leveldb::Slice slKey = pcursor->key();
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
char chType;
ssKey >> chType;
if (chType == 'n')
{
leveldb::Slice slValue = pcursor->value();
std::string name;
ssKey >> name;
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
CNCCTrieNode* node = new CNCCTrieNode();
ssValue >> *node;
if (!InsertFromDisk(name, node))
return false;
}
}
}
if (check)
return checkConsistency();
return true;
}
bool CNCCTrieCache::recursiveComputeMerkleHash(CNCCTrieNode* tnCurrent, std::string sPos) const
{
std::string stringToHash;
@ -334,11 +381,12 @@ uint256 CNCCTrieCache::getMerkleHash() const
bool CNCCTrieCache::empty() const
{
return base->empty() && cache.empty();
return !base || (base->empty() && cache.empty());
}
bool CNCCTrieCache::insertName(const std::string name, uint256 txhash, int nOut, CAmount nAmount, int nHeight) const
{
assert(base);
CNCCTrieNode* currentNode = &(base->root);
nodeCacheType::iterator cachedNode;
cachedNode = cache.find("");
@ -416,15 +464,16 @@ bool CNCCTrieCache::insertName(const std::string name, uint256 txhash, int nOut,
return true;
}
bool CNCCTrieCache::removeName(const std::string name, uint256 txhash, int nOut, CAmount nAmount, int nHeight) const
bool CNCCTrieCache::removeName(const std::string name, uint256 txhash, int nOut) const
{
CNCCTrieNode* currentNode = &(base->root);
nodeCacheType::iterator cachedNode;
cachedNode = cache.find("");
if (cachedNode != cache.end())
currentNode = cachedNode->second;
assert(currentNode != NULL); // If there is no root in either the trie or the cache, how can there be any names to remove?
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
assert(base);
CNCCTrieNode* currentNode = &(base->root);
nodeCacheType::iterator cachedNode;
cachedNode = cache.find("");
if (cachedNode != cache.end())
currentNode = cachedNode->second;
assert(currentNode != NULL); // If there is no root in either the trie or the cache, how can there be any names to remove?
for (std::string::const_iterator itCur = name.begin(); itCur != name.end(); ++itCur)
{
std::string sCurrentSubstring(name.begin(), itCur);
std::string sNextSubstring(name.begin(), itCur + 1);
@ -456,7 +505,7 @@ bool CNCCTrieCache::removeName(const std::string name, uint256 txhash, int nOut,
}
bool fChanged = false;
assert(currentNode != NULL);
bool success = currentNode->removeValue(CNodeValue(txhash, nOut, nAmount, nHeight), &fChanged);
bool success = currentNode->removeValue(CNodeValue(txhash, nOut), &fChanged);
assert(success);
if (fChanged)
{
@ -562,6 +611,8 @@ bool CNCCTrieCache::flush()
{
if (dirty())
getMerkleHash();
if (!base)
return true;
bool success = base->update(cache, cacheHashes);
if (success)
{

View file

@ -1,5 +1,5 @@
#ifndef BITCOIN_NCCTRIE_H
#define BITCOIN_NCC_H
#define BITCOIN_NCCTRIE_H
#include "amount.h"
#include "serialize.h"
@ -23,6 +23,7 @@ public:
CAmount nAmount;
int nHeight;
CNodeValue() {};
CNodeValue(uint256 txhash, uint32_t nOut) : txhash(txhash), nOut(nOut), nAmount(0), nHeight(0) {}
CNodeValue(uint256 txhash, uint32_t nOut, CAmount nAmount, int nHeight) : txhash(txhash), nOut(nOut), nAmount(nAmount), nHeight(nHeight) {}
std::string ToString();
@ -57,7 +58,7 @@ public:
}
bool operator==(const CNodeValue& other) const
{
return txhash == other.txhash && nOut == other.nOut && nAmount == other.nAmount && nHeight == other.nHeight;
return txhash == other.txhash && nOut == other.nOut;
}
bool operator!=(const CNodeValue& other) const
{
@ -122,20 +123,21 @@ class CNCCTrieCache;
class CNCCTrie
{
public:
CNCCTrie(CCoinsViewCache* coins) : db(GetDataDir() / "ncctrie", 100, false, false), coins(coins), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
CNCCTrie() : db(GetDataDir() / "ncctrie", 100, false, false), root(uint256S("0000000000000000000000000000000000000000000000000000000000000001")) {}
uint256 getMerkleHash();
CLevelDBWrapper db;
bool empty() const;
bool checkConsistency();
bool ReadFromDisk(bool check = false);
friend class CNCCTrieCache;
private:
CCoinsViewCache* coins;
bool update(nodeCacheType& cache, hashMapType& hashes);
bool updateName(const std::string& name, CNCCTrieNode* updatedNode, std::vector<std::string>& deletedNames);
bool updateHash(const std::string& name, uint256& hash, CNCCTrieNode** pNodeRet);
bool recursiveNullify(CNCCTrieNode* node, std::string& name, std::vector<std::string>& deletedNames);
bool recursiveCheckConsistency(CNCCTrieNode* node);
bool BatchWrite(nodeCacheType& changedNodes, std::vector<std::string>& deletedNames);
bool InsertFromDisk(const std::string& name, CNCCTrieNode* node);
CNCCTrieNode root;
};
@ -148,7 +150,7 @@ public:
bool flush();
bool dirty() const { return !dirtyHashes.empty(); }
bool insertName (const std::string name, uint256 txhash, int nOut, CAmount nAmount, int nDepth) const;
bool removeName (const std::string name, uint256 txhash, int nOut, CAmount nAmount, int nDepth) const;
bool removeName (const std::string name, uint256 txhash, int nOut) const;
~CNCCTrieCache() { clear(); }
private:
CNCCTrie* base;

View file

@ -28,6 +28,7 @@ public:
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint256 hashNCCTrie;
uint32_t nTime;
uint32_t nBits;
uint32_t nNonce;
@ -48,6 +49,7 @@ public:
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
READWRITE(hashNCCTrie);
}
void SetNull()
@ -55,6 +57,7 @@ public:
nVersion = CBlockHeader::CURRENT_VERSION;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
hashNCCTrie.SetNull();
nTime = 0;
nBits = 0;
nNonce = 0;
@ -118,6 +121,7 @@ public:
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
block.hashNCCTrie = hashNCCTrie;
return block;
}

View file

@ -180,6 +180,7 @@ BOOST_AUTO_TEST_CASE(bloom_match)
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
}
/* TODO: put these tests back in when there are real blocks to use
BOOST_AUTO_TEST_CASE(merkle_block_1)
{
// Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
@ -457,5 +458,6 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none)
BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
}
*/
BOOST_AUTO_TEST_SUITE_END()

View file

@ -52,34 +52,34 @@ struct {
unsigned char extranonce;
unsigned int nonce;
} blockinfo[] = {
{4, 0x00000002}, {2, 0x00000002}, {1, 0x00000000}, {1, 0x00000001}, //0
{2, 0x00000001}, {2, 0x00000002}, {1, 0x00000000}, {2, 0x0000000b}, //4
{2, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}, {2, 0x00000001}, //8
{2, 0x00000000}, {1, 0x00000000}, {2, 0x00000000}, {2, 0x00000001}, //12
{1, 0x00000000}, {2, 0x00000004}, {1, 0x00000000}, {1, 0x00000000}, //16
{3, 0x00000002}, {2, 0x00000000}, {2, 0x00000000}, {1, 0x00000000}, //20
{2, 0x00000000}, {1, 0x00000002}, {2, 0x00000000}, {2, 0x00000000}, //24
{2, 0x00000000}, {2, 0x00000001}, {2, 0x00000000}, {2, 0x00000000}, //28
{1, 0x00000000}, {2, 0x00000001}, {2, 0x00000000}, {1, 0x00000000}, //32
{2, 0x00000001}, {1, 0x00000000}, {2, 0x00000001}, {1, 0x00000000}, //36
{1, 0x00000001}, {3, 0x00000000}, {2, 0x00000000}, {5, 0x00000002}, //40
{1, 0x00000001}, {5, 0x00000000}, {1, 0x00000005}, {1, 0x00000000}, //44
{1, 0x00000000}, {2, 0x00000002}, {1, 0x00000002}, {1, 0x00000000}, //48
{1, 0x00000000}, {1, 0x00000000}, {5, 0x00000001}, {5, 0x00000000}, //52
{1, 0x00000000}, {1, 0x00000000}, {6, 0x00000000}, {2, 0x00000001}, //56
{2, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {1, 0x00000002}, //60
{2, 0x00000001}, {2, 0x00000000}, {1, 0x00000003}, {1, 0x00000001}, //64
{1, 0x00000000}, {5, 0x00000000}, {5, 0x00000002}, {1, 0x00000001}, //68
{1, 0x00000001}, {2, 0x00000000}, {2, 0x00000001}, {1, 0x00000003}, //72
{2, 0x00000002}, {1, 0x00000000}, {2, 0x00000000}, {2, 0x00000006}, //76
{1, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {5, 0x00000000}, //80
{1, 0x00000001}, {1, 0x00000001}, {1, 0x00000000}, {1, 0x00000002}, //84
{1, 0x00000000}, {1, 0x00000000}, {1, 0x00000002}, {2, 0x00000001}, //88
{0, 0x00000003}, {1, 0x00000004}, {2, 0x00000000}, {2, 0x00000001}, //92
{2, 0x00000000}, {1, 0x00000002}, {1, 0x00000000}, {1, 0x00000002}, //96
{1, 0x00000000}, {1, 0x00000003}, {1, 0x00000000}, {5, 0x00000000}, //100
{2, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {1, 0x00000001}, //104
{2, 0x00000000}, {2, 0x00000002}, //108
{4, 0x00000000}, {2, 0x00000001}, {1, 0x00000002}, {1, 0x00000000}, //0
{2, 0x00000001}, {2, 0x00000001}, {1, 0x00000001}, {2, 0x00000000}, //4
{2, 0x00000001}, {1, 0x00000000}, {1, 0x00000001}, {2, 0x00000001}, //8
{2, 0x00000003}, {1, 0x00000001}, {2, 0x00000001}, {2, 0x00000001}, //12
{1, 0x00000001}, {2, 0x00000000}, {1, 0x00000005}, {1, 0x00000001}, //16
{3, 0x00000000}, {2, 0x00000000}, {2, 0x00000000}, {1, 0x00000004}, //20
{2, 0x00000000}, {1, 0x00000000}, {2, 0x00000002}, {2, 0x00000003}, //24
{2, 0x00000001}, {2, 0x00000001}, {2, 0x00000000}, {2, 0x00000000}, //28
{1, 0x00000001}, {2, 0x00000000}, {2, 0x00000001}, {1, 0x00000000}, //32
{2, 0x00000000}, {1, 0x00000001}, {2, 0x00000000}, {1, 0x00000000}, //36
{1, 0x00000000}, {3, 0x00000000}, {2, 0x00000005}, {5, 0x00000000}, //40
{1, 0x00000002}, {5, 0x00000001}, {1, 0x00000001}, {1, 0x00000001}, //44
{1, 0x00000001}, {2, 0x00000002}, {1, 0x00000002}, {1, 0x00000001}, //48
{1, 0x00000000}, {1, 0x00000000}, {5, 0x00000002}, {5, 0x00000000}, //52
{1, 0x00000000}, {1, 0x00000000}, {6, 0x00000001}, {2, 0x00000000}, //56
{2, 0x00000003}, {1, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}, //60
{2, 0x00000000}, {2, 0x00000001}, {1, 0x00000000}, {1, 0x00000001}, //64
{1, 0x00000003}, {5, 0x00000000}, {5, 0x00000000}, {1, 0x00000002}, //68
{1, 0x00000000}, {2, 0x00000001}, {2, 0x00000004}, {1, 0x00000000}, //72
{2, 0x00000001}, {1, 0x00000002}, {2, 0x00000004}, {2, 0x00000000}, //76
{1, 0x00000000}, {1, 0x00000002}, {1, 0x00000000}, {5, 0x00000002}, //80
{1, 0x00000001}, {1, 0x00000003}, {1, 0x00000000}, {1, 0x00000002}, //84
{1, 0x00000000}, {1, 0x00000000}, {1, 0x00000002}, {2, 0x00000000}, //88
{0, 0x00000000}, {1, 0x00000000}, {2, 0x00000001}, {2, 0x00000001}, //92
{2, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}, //96
{1, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}, {5, 0x00000000}, //100
{2, 0x00000000}, {1, 0x00000002}, {1, 0x00000000}, {1, 0x00000001}, //104
{2, 0x00000003}, {2, 0x00000000}, //108
};
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
@ -122,6 +122,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits))
{
fFound = true;
if (i % 4 == 0)
std::cout << std::endl;
std::cout << "Block number: " << i << std::endl;
std::cout << "Nonce: " << std::hex << pblock->nNonce << std::dec << std::endl;
}

View file

@ -51,10 +51,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remov)
uint256 hash4;
hash4.SetHex("a79e8a5b28f7fa5e8836a4b48da9988bdf56ce749f81f413cb754f963a516200");
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
CNCCTrie trie(&coins);
CNCCTrie trie;
BOOST_CHECK(trie.empty());
@ -71,7 +68,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remov)
ntState.insertName(std::string("tes"), tx4.GetHash(), 0, 50, 100);
BOOST_CHECK(ntState.getMerkleHash() == hash2);
ntState.insertName(std::string("testtesttesttest"), tx5.GetHash(), 0, 50, 100);
ntState.removeName(std::string("testtesttesttest"), tx5.GetHash(), 0, 50, 100);
ntState.removeName(std::string("testtesttesttest"), tx5.GetHash(), 0);
BOOST_CHECK(ntState.getMerkleHash() == hash2);
ntState.flush();
@ -80,7 +77,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remov)
BOOST_CHECK(trie.checkConsistency());
CNCCTrieCache ntState2(&trie);
ntState2.insertName(std::string("abab"), tx6.GetHash(), 0, 50, 100);
ntState2.removeName(std::string("test"), tx1.GetHash(), 0, 50, 100);
ntState2.removeName(std::string("test"), tx1.GetHash(), 0);
BOOST_CHECK(ntState2.getMerkleHash() == hash3);
@ -99,7 +96,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remov)
BOOST_CHECK(trie.checkConsistency());
CNCCTrieCache ntState4(&trie);
ntState4.removeName(std::string("abab"), tx6.GetHash(), 0, 50, 100);
ntState4.removeName(std::string("abab"), tx6.GetHash(), 0);
BOOST_CHECK(ntState4.getMerkleHash() == hash2);
ntState4.flush();
BOOST_CHECK(!trie.empty());
@ -107,7 +104,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remov)
BOOST_CHECK(trie.checkConsistency());
CNCCTrieCache ntState5(&trie);
ntState5.removeName(std::string("test"), tx3.GetHash(), 0, 50, 101);
ntState5.removeName(std::string("test"), tx3.GetHash(), 0);
BOOST_CHECK(ntState5.getMerkleHash() == hash2);
ntState5.flush();