diff --git a/src/init.cpp b/src/init.cpp index cd4e69f7c..2d017c40c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1072,6 +1072,12 @@ bool AppInit2(boost::thread_group& threadGroup) strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); break; } + + if (!pnccTrie->ReadFromDisk(true)) + { + strLoadError = _("Error loading the ncc trie from disk"); + break; + } uiInterface.InitMessage(_("Verifying blocks...")); if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3), @@ -1079,11 +1085,6 @@ 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"); diff --git a/src/main.cpp b/src/main.cpp index c0c7aca95..82b62172b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1628,8 +1628,9 @@ static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, CNCCTrie { assert(vvchParams.size() == 2); std::string name(vvchParams[0].begin(), vvchParams[0].end()); + LogPrintf("%s: Restoring %s to the NCC trie due to a block being disconnected\n", __func__, name.c_str()); if (!trieCache.insertName(name, out.hash, out.n, undo.txout.nValue, undo.nHeight)) - LogPrintf("Something went wrong inserting the name"); + LogPrintf("%s: Something went wrong inserting the name\n", __func__); } coins->vout[out.n] = undo.txout; @@ -1687,8 +1688,9 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex { assert(vvchParams.size() == 2); std::string name(vvchParams[0].begin(), vvchParams[0].end()); + LogPrintf("%s: Removing %s from the ncc trie due to its block being disconnected\n", __func__, name.c_str()); if (!trieCache.removeName(name, hash, i)) - LogPrintf("Something went wrong removing the name"); + LogPrintf("%s: Something went wrong removing the name %s in hash %s\n", __func__, name.c_str(), hash.GetHex()); } } @@ -1712,6 +1714,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); + assert(trieCache.getMerkleHash() == pindex->pprev->hashNCCTrie); if (pfClean) { *pfClean = fClean; @@ -1870,10 +1873,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin std::vector > vvchParams; if (DecodeNCCScript(coins->vout[txin.prevout.n].scriptPubKey, op, vvchParams)) { - assert(vvchParams.size() == 1); + 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"); + LogPrintf("%s: Something went wrong removing the name\n", __func__); } } @@ -1888,7 +1891,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin 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"); + LogPrintf("%s: Something went wrong inserting the name\n", __func__); } } } @@ -2094,6 +2097,7 @@ bool static DisconnectTip(CValidationState &state) { return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); assert(view.Flush()); assert(trieCache.flush()); + assert(pindexDelete->pprev->hashNCCTrie == trieCache.getMerkleHash()); } LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); // Write the chain state to disk, if necessary. diff --git a/src/miner.cpp b/src/miner.cpp index bd65ef211..ba3a777db 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -281,15 +281,15 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) continue; - 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()"); + LogPrintf("%s: !coins || txin.prevout.n >= coins->vout.size(). txin.prevout.hash = %s\n", __func__, txin.prevout.hash.GetHex()); + if (coins) + LogPrintf("coins is not null. txin.prevout.n = %d, coins->vout.size() = %d\n", txin.prevout.n, coins->vout.size()); continue; } @@ -301,10 +301,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) 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"); + LogPrintf("%s: Something went wrong removing the name\n", __func__); } } + UpdateCoins(tx, state, view, nHeight); + for (unsigned int i = 0; i < tx.vout.size(); ++i) { const CTxOut& txout = tx.vout[i]; @@ -316,7 +318,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) 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"); + LogPrintf("%s: Something went wrong inserting the name\n", __func__); } } diff --git a/src/ncctrie.cpp b/src/ncctrie.cpp index d73a34d16..d0792ea25 100644 --- a/src/ncctrie.cpp +++ b/src/ncctrie.cpp @@ -109,7 +109,7 @@ json_spirit::Array CNCCTrie::dumpToJSON() const { json_spirit::Array ret; if (!recursiveDumpToJSON("", &root, ret)) - LogPrintf("Something went wrong dumping to JSON"); + LogPrintf("%s: Something went wrong dumping to JSON", __func__); return ret; } @@ -321,8 +321,10 @@ bool CNCCTrie::BatchWrite(nodeCacheType& changedNodes, std::vector& 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) { @@ -342,7 +344,7 @@ bool CNCCTrie::ReadFromDisk(bool check) while (pcursor->Valid()) { - //TODO: make try statement here + try { leveldb::Slice slKey = pcursor->key(); CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION); @@ -359,15 +361,35 @@ bool CNCCTrie::ReadFromDisk(bool check) if (!InsertFromDisk(name, node)) return false; } + pcursor->Next(); } + catch (const std::exception& e) + { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + } if (check) - return checkConsistency(); + { + LogPrintf("Checking NCC trie consistency..."); + if( checkConsistency()) + { + LogPrintf("consistent\n"); + return true; + } + LogPrintf("inconsistent!\n"); + return false; + } return true; } bool CNCCTrieCache::recursiveComputeMerkleHash(CNCCTrieNode* tnCurrent, std::string sPos) const { + if (sPos == "" && tnCurrent->empty()) + { + cacheHashes[""] = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); + return true; + } std::string stringToHash; CNodeValue val; @@ -547,7 +569,7 @@ bool CNCCTrieCache::removeName(const std::string name, uint256 txhash, int nOut) continue; } - // The name doesn't exist in either the trie or the cache, so how can we remove it? + LogPrintf("%s: The name %s does not exist in the trie\n", __func__, name.c_str()); return false; } diff --git a/src/test/ncctrie_tests.cpp b/src/test/ncctrie_tests.cpp index e44c2d92c..014891e4b 100644 --- a/src/test/ncctrie_tests.cpp +++ b/src/test/ncctrie_tests.cpp @@ -30,9 +30,10 @@ CMutableTransaction BuildTransaction(const uint256& prevhash) return tx; } -BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remov) +BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remove) { - CMutableTransaction tx1 = BuildTransaction(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()); @@ -75,6 +76,15 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remov) BOOST_CHECK(!trie.empty()); BOOST_CHECK(trie.getMerkleHash() == hash2); BOOST_CHECK(trie.checkConsistency()); + + CNCCTrieCache ntState1(&trie); + ntState1.removeName(std::string("test"), tx1.GetHash(), 0); + ntState1.removeName(std::string("test2"), tx2.GetHash(), 0); + ntState1.removeName(std::string("test"), tx3.GetHash(), 0); + ntState1.removeName(std::string("tes"), tx4.GetHash(), 0); + + BOOST_CHECK(ntState1.getMerkleHash() == hash0); + CNCCTrieCache ntState2(&trie); ntState2.insertName(std::string("abab"), tx6.GetHash(), 0, 50, 100); ntState2.removeName(std::string("test"), tx1.GetHash(), 0);