Rename CClaimTrieCache to CClaimTrieUpdateBuffer #156
11 changed files with 268 additions and 74 deletions
|
@ -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"));
|
||||
|
|
|
@ -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");
|
||||
|
|
105
src/main.cpp
105
src/main.cpp
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue