fix a few bugs and add some assertions
ncctrietests.cpp: add test to make sure emptying the ncc trie cache results in a default hash ("00...01") ncctrie.cpp: fix the ncc trie cache so that emptying it causes the root hash to be computed as the default hash ("00...01") fix two bugs in reading the ncc trie from disk: all insertions were returning immediately due to parenthesis misplacement, and the loop reading nodes from disk wasn't terminating due to a lack of an incrementing operation miner.cpp fix a bug in the miner where input coins in the cache were being spent before their txouts could be checked for NCC commands main.cpp add some assertions when disconnecting blocks from the active chain, ensuring the merkle root of the ncc trie after undoing the block is equal to the hashNCCTrie in the previous block fix an erroneous assertion in ConnectBlock to assert the correct expected value change some log statements to use __func__ init.cpp change the order of some init operations so the NCC trie is restored from disk before the DB is verified
This commit is contained in:
parent
df59145787
commit
389a2a963e
5 changed files with 60 additions and 21 deletions
11
src/init.cpp
11
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");
|
||||
|
|
14
src/main.cpp
14
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<std::vector<unsigned char> > 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.
|
||||
|
|
|
@ -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__);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<std::string>&
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue