Implement a hard fork for extended/infinite claim expiration times #112

Closed
lbrynaut wants to merge 247 commits from claim-expiration into master
5 changed files with 69 additions and 43 deletions
Showing only changes of commit e7654b8703 - Show all commits

View file

@ -1641,6 +1641,7 @@ static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, CNCCTrie
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, CNCCTrieCache& trieCache, bool* pfClean)
{
assert(pindex->GetBlockHash() == view.GetBestBlock());
assert(pindex->GetBlockHash() == trieCache.getBestBlock());
if (pfClean)
*pfClean = false;
@ -1714,6 +1715,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
// move best block pointer to prevout block
view.SetBestBlock(pindex->pprev->GetBlockHash());
trieCache.setBestBlock(pindex->pprev->GetBlockHash());
assert(trieCache.getMerkleHash() == pindex->pprev->hashNCCTrie);
if (pfClean) {
@ -1773,11 +1775,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash();
assert(hashPrevBlock == view.GetBestBlock());
// also verify that the trie cache's current state corresponds to the previous block
assert(hashPrevBlock == trieCache.getBestBlock());
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
if (block.GetHash() == Params().HashGenesisBlock()) {
if (!fJustCheck)
{
view.SetBestBlock(pindex->GetBlockHash());
trieCache.setBestBlock(pindex->GetBlockHash());
}
return true;
}
@ -1960,6 +1968,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
trieCache.setBestBlock(pindex->GetBlockHash());
int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001);

View file

@ -175,7 +175,7 @@ bool CNCCTrie::recursiveCheckConsistency(CNCCTrieNode* node)
return calculatedHash == node->hash;
}
bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes)
bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlockIn)
{
// General strategy: the cache is ordered by length, ensuring child
// nodes are always inserted after their parents. Insert each node
@ -196,10 +196,6 @@ bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes)
// appending extra data to the normal txundo, which will call the
// normal insert/remove names, but obviously the opposite and in
// reverse order (though the order shouldn't ever matter).
if (cache.empty())
{
return true;
}
bool success = true;
std::vector<std::string> deletedNames;
for (nodeCacheType::iterator itcache = cache.begin(); itcache != cache.end(); ++itcache)
@ -217,7 +213,8 @@ bool CNCCTrie::update(nodeCacheType& cache, hashMapType& hashes)
return false;
changedNodes[ithash->first] = pNode;
}
BatchWrite(changedNodes, deletedNames);
BatchWrite(changedNodes, deletedNames, hashBlockIn);
hashBlock = hashBlockIn;
return true;
}
@ -308,13 +305,14 @@ void BatchEraseNode(CLevelDBBatch& batch, const std::string& name)
batch.Erase(std::make_pair('n', name));
}
bool CNCCTrie::BatchWrite(nodeCacheType& changedNodes, std::vector<std::string>& deletedNames)
bool CNCCTrie::BatchWrite(nodeCacheType& changedNodes, std::vector<std::string>& deletedNames, const uint256& hashBlockIn)
{
CLevelDBBatch batch;
for (nodeCacheType::iterator itcache = changedNodes.begin(); itcache != changedNodes.end(); ++itcache)
BatchWriteNode(batch, itcache->first, itcache->second);
for (std::vector<std::string>::iterator itname = deletedNames.begin(); itname != deletedNames.end(); ++itname)
BatchEraseNode(batch, *itname);
batch.Write('h', hashBlockIn);
return db.WriteBatch(batch);
}
@ -339,6 +337,9 @@ bool CNCCTrie::InsertFromDisk(const std::string& name, CNCCTrieNode* node)
bool CNCCTrie::ReadFromDisk(bool check)
{
if (!db.Read('h', hashBlock))
LogPrintf("%s: Couldn't read the best block's hash\n", __func__);
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
pcursor->SeekToFirst();
@ -459,7 +460,7 @@ uint256 CNCCTrieCache::getMerkleHash() const
bool CNCCTrieCache::empty() const
{
return !base || (base->empty() && cache.empty());
return base->empty() && cache.empty();
}
bool CNCCTrieCache::insertName(const std::string name, uint256 txhash, int nOut, CAmount nAmount, int nHeight) const
@ -673,6 +674,19 @@ bool CNCCTrieCache::recursivePruneName(CNCCTrieNode* tnCurrent, unsigned int nPo
return true;
}
uint256 CNCCTrieCache::getBestBlock()
{
if (hashBlock.IsNull())
if (base != NULL)
hashBlock = base->hashBlock;
return hashBlock;
}
void CNCCTrieCache::setBestBlock(const uint256& hashBlockIn)
{
hashBlock = hashBlockIn;
}
bool CNCCTrieCache::clear() const
{
for (nodeCacheType::iterator itcache = cache.begin(); itcache != cache.end(); ++itcache)
@ -689,9 +703,7 @@ bool CNCCTrieCache::flush()
{
if (dirty())
getMerkleHash();
if (!base)
return true;
bool success = base->update(cache, cacheHashes);
bool success = base->update(cache, cacheHashes, hashBlock);
if (success)
{
success = clear();

View file

@ -133,27 +133,30 @@ public:
json_spirit::Object getInfoForName(const std::string& name) const;
friend class CNCCTrieCache;
private:
bool update(nodeCacheType& cache, hashMapType& hashes);
bool update(nodeCacheType& cache, hashMapType& hashes, const uint256& hashBlock);
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 BatchWrite(nodeCacheType& changedNodes, std::vector<std::string>& deletedNames, const uint256& hashBlock);
bool InsertFromDisk(const std::string& name, CNCCTrieNode* node);
bool recursiveDumpToJSON(const std::string& name, const CNCCTrieNode* current, json_spirit::Array& ret) const;
CNCCTrieNode root;
uint256 hashBlock;
};
class CNCCTrieCache
{
public:
CNCCTrieCache(CNCCTrie* base): base(base) {}
CNCCTrieCache(CNCCTrie* base): base(base) {assert(base);}
uint256 getMerkleHash() const;
bool empty() const;
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) const;
uint256 getBestBlock();
void setBestBlock(const uint256& hashBlock);
~CNCCTrieCache() { clear(); }
private:
CNCCTrie* base;
@ -164,6 +167,7 @@ private:
bool recursiveComputeMerkleHash(CNCCTrieNode* tnCurrent, std::string sPos) const;
bool recursivePruneName(CNCCTrieNode* tnCurrent, unsigned int nPos, std::string sName, bool* pfNullified = NULL) const;
bool clear() const;
uint256 hashBlock;
};
#endif // BITCOIN_NCCTRIE_H

View file

@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include "main.h"
#include "primitives/transaction.h"
#include "ncctrie.h"
#include "coins.h"
@ -52,15 +53,13 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remove)
uint256 hash4;
hash4.SetHex("a79e8a5b28f7fa5e8836a4b48da9988bdf56ce749f81f413cb754f963a516200");
CNCCTrie trie;
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(trie.empty());
CNCCTrieCache ntState(&trie);
CNCCTrieCache ntState(pnccTrie);
ntState.insertName(std::string("test"), tx1.GetHash(), 0, 50, 100);
ntState.insertName(std::string("test2"), tx2.GetHash(), 0, 50, 100);
BOOST_CHECK(trie.empty());
BOOST_CHECK(pnccTrie->empty());
BOOST_CHECK(!ntState.empty());
BOOST_CHECK(ntState.getMerkleHash() == hash1);
@ -73,11 +72,11 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remove)
BOOST_CHECK(ntState.getMerkleHash() == hash2);
ntState.flush();
BOOST_CHECK(!trie.empty());
BOOST_CHECK(trie.getMerkleHash() == hash2);
BOOST_CHECK(trie.checkConsistency());
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->getMerkleHash() == hash2);
BOOST_CHECK(pnccTrie->checkConsistency());
CNCCTrieCache ntState1(&trie);
CNCCTrieCache ntState1(pnccTrie);
ntState1.removeName(std::string("test"), tx1.GetHash(), 0);
ntState1.removeName(std::string("test2"), tx2.GetHash(), 0);
ntState1.removeName(std::string("test"), tx3.GetHash(), 0);
@ -85,7 +84,7 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remove)
BOOST_CHECK(ntState1.getMerkleHash() == hash0);
CNCCTrieCache ntState2(&trie);
CNCCTrieCache ntState2(pnccTrie);
ntState2.insertName(std::string("abab"), tx6.GetHash(), 0, 50, 100);
ntState2.removeName(std::string("test"), tx1.GetHash(), 0);
@ -93,43 +92,43 @@ BOOST_AUTO_TEST_CASE(ncctrie_create_insert_remove)
ntState2.flush();
BOOST_CHECK(!trie.empty());
BOOST_CHECK(trie.getMerkleHash() == hash3);
BOOST_CHECK(trie.checkConsistency());
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->getMerkleHash() == hash3);
BOOST_CHECK(pnccTrie->checkConsistency());
CNCCTrieCache ntState3(&trie);
CNCCTrieCache ntState3(pnccTrie);
ntState3.insertName(std::string("test"), tx1.GetHash(), 0, 50, 100);
BOOST_CHECK(ntState3.getMerkleHash() == hash4);
ntState3.flush();
BOOST_CHECK(!trie.empty());
BOOST_CHECK(trie.getMerkleHash() == hash4);
BOOST_CHECK(trie.checkConsistency());
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->getMerkleHash() == hash4);
BOOST_CHECK(pnccTrie->checkConsistency());
CNCCTrieCache ntState4(&trie);
CNCCTrieCache ntState4(pnccTrie);
ntState4.removeName(std::string("abab"), tx6.GetHash(), 0);
BOOST_CHECK(ntState4.getMerkleHash() == hash2);
ntState4.flush();
BOOST_CHECK(!trie.empty());
BOOST_CHECK(trie.getMerkleHash() == hash2);
BOOST_CHECK(trie.checkConsistency());
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->getMerkleHash() == hash2);
BOOST_CHECK(pnccTrie->checkConsistency());
CNCCTrieCache ntState5(&trie);
CNCCTrieCache ntState5(pnccTrie);
ntState5.removeName(std::string("test"), tx3.GetHash(), 0);
BOOST_CHECK(ntState5.getMerkleHash() == hash2);
ntState5.flush();
BOOST_CHECK(!trie.empty());
BOOST_CHECK(trie.getMerkleHash() == hash2);
BOOST_CHECK(trie.checkConsistency());
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->getMerkleHash() == hash2);
BOOST_CHECK(pnccTrie->checkConsistency());
CNCCTrieCache ntState6(&trie);
CNCCTrieCache ntState6(pnccTrie);
ntState6.insertName(std::string("test"), tx3.GetHash(), 0, 50, 101);
BOOST_CHECK(ntState6.getMerkleHash() == hash2);
ntState6.flush();
BOOST_CHECK(!trie.empty());
BOOST_CHECK(trie.getMerkleHash() == hash2);
BOOST_CHECK(trie.checkConsistency());
BOOST_CHECK(!pnccTrie->empty());
BOOST_CHECK(pnccTrie->getMerkleHash() == hash2);
BOOST_CHECK(pnccTrie->checkConsistency());
}
BOOST_AUTO_TEST_CASE(ncctrienode_serialize_unserialize)

View file

@ -42,6 +42,7 @@ struct TestingSetup {
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
pnccTrie = new CNCCTrie();
InitBlockIndex();
#ifdef ENABLE_WALLET
bool fFirstRun;
@ -63,6 +64,7 @@ struct TestingSetup {
delete pwalletMain;
pwalletMain = NULL;
#endif
delete pnccTrie;
delete pcoinsTip;
delete pcoinsdbview;
delete pblocktree;