some progress on making takeover height work

This commit is contained in:
Brannon King 2019-10-30 23:13:07 -06:00
parent 377432a459
commit 515446fe7b
12 changed files with 221 additions and 188 deletions

View file

@ -174,8 +174,9 @@ bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CSc
case OP_UPDATE_CLAIM:
return claimOp.updateClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]),
vvchParams[2]);
default:
throw std::runtime_error("Unimplemented OP handler.");
}
throw std::runtime_error("Unimplemented OP handler.");
}
void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoinsViewCache& view, int nHeight, const CUpdateCacheCallbacks& callbacks)
@ -188,12 +189,12 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin
bool spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override
{
if (CClaimScriptSpendOp::spendClaim(trieCache, name, claimId)) {
callback(name, claimId, nValidHeight);
callback(name, claimId);
return true;
}
return false;
}
std::function<void(const std::string& name, const uint160& claimId, const int takeoverHeight)> callback;
std::function<void(const std::string& name, const uint160& claimId)> callback;
};
spentClaimsType spentClaims;
@ -216,8 +217,8 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin
int nValidAtHeight;
CSpendClaimHistory spendClaim(COutPoint(txin.prevout.hash, txin.prevout.n), scriptHeight, nValidAtHeight);
spendClaim.callback = [&spentClaims](const std::string& name, const uint160& claimId, const int takeoverHeight) {
spentClaims.emplace_back(name, claimId, takeoverHeight);
spendClaim.callback = [&spentClaims](const std::string& name, const uint160& claimId) {
spentClaims.emplace_back(name, claimId);
};
if (ProcessClaim(spendClaim, trieCache, scriptPubKey) && callbacks.claimUndoHeights)
callbacks.claimUndoHeights(j, nValidAtHeight);
@ -231,12 +232,11 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) override
{
int takeoverHeight = -1;
if (callback(name, claimId, takeoverHeight))
return CClaimScriptAddOp::addClaim(trieCache, name, claimId, takeoverHeight, metadata);
if (callback(name, claimId))
return CClaimScriptAddOp::addClaim(trieCache, name, claimId, -1, metadata);
return false;
}
std::function<bool(const std::string& name, const uint160& claimId, int& takeoverHeight)> callback;
std::function<bool(const std::string& name, const uint160& claimId)> callback;
};
for (std::size_t j = 0; j < tx.vout.size(); j++) {
@ -246,10 +246,9 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin
continue;
CAddSpendClaim addClaim(COutPoint(tx.GetHash(), j), txout.nValue, nHeight);
addClaim.callback = [&trieCache, &spentClaims](const std::string& name, const uint160& claimId, int& takeoverHeight) -> bool {
addClaim.callback = [&trieCache, &spentClaims](const std::string& name, const uint160& claimId) -> bool {
for (auto itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) {
if (std::get<1>(*itSpent) == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(std::get<0>(*itSpent))) {
takeoverHeight = std::get<2>(*itSpent);
if (itSpent->second == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)) {
spentClaims.erase(itSpent);
return true;
}

View file

@ -238,8 +238,7 @@ protected:
*/
bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CScript& scriptPubKey);
typedef std::tuple<std::string, uint160, int> spentClaimType;
typedef std::pair<std::string, uint160> spentClaimType;
typedef std::vector<spentClaimType> spentClaimsType;
struct CUpdateCacheCallbacks

View file

@ -56,7 +56,7 @@ CClaimTrie::CClaimTrie(bool fWipe, int height, int proportionalDelayFactor)
db.define("MERKLE_PAIR", [](const std::vector<unsigned char>& blob1, const std::vector<unsigned char>& blob2) { return Hash(blob1.begin(), blob1.end(), blob2.begin(), blob2.end()); });
db.define("MERKLE", [](const std::vector<unsigned char>& blob1) { return Hash(blob1.begin(), blob1.end()); });
db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT, hash BLOB)";
db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT, hash BLOB, takeoverHeight INTEGER, takeoverID BLOB)";
db << "CREATE INDEX IF NOT EXISTS nodes_hash ON nodes (hash)";
db << "CREATE INDEX IF NOT EXISTS nodes_parent ON nodes (parent)";
@ -325,13 +325,14 @@ CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly)
return ret;
}
bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim) const
bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset) const
{
auto nextHeight = nNextHeight + heightOffset;
auto query = db << "SELECT c.claimID, c.txID, c.txN, c.blockHeight, c.validHeight, c.amount, "
"(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount "
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? "
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN LIMIT 1"
<< nNextHeight << nNextHeight << name << nNextHeight << nNextHeight;
<< nextHeight << nextHeight << name << nextHeight << nextHeight;
for (auto&& row: query) {
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
>> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount >> claim.nEffectiveAmount;
@ -391,18 +392,19 @@ void completeHash(uint256& partialHash, const std::string& key, std::size_t to)
.Finalize(partialHash.begin());
}
uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, bool checkOnly)
uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly)
{
std::vector<uint8_t> vchToHash;
const auto pos = name.size();
auto query = db << "SELECT name, hash FROM nodes WHERE parent = ? ORDER BY name" << name;
auto query = db << "SELECT name, hash, IFNULL(takeoverHeight,0) FROM nodes WHERE parent = ? ORDER BY name" << name;
for (auto&& row : query) {
std::string key;
int childTakeoverHeight;
std::unique_ptr<uint256> hash;
row >> key >> hash;
row >> key >> hash >> childTakeoverHeight;
if (hash == nullptr) hash = std::make_unique<uint256>();
if (hash->IsNull()) {
*hash = recursiveComputeMerkleHash(key, checkOnly);
*hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly);
}
completeHash(*hash, key, pos);
vchToHash.push_back(key[pos]);
@ -411,7 +413,7 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name,
CClaimValue claim;
if (getInfoForName(name, claim)) {
uint256 valueHash = getValueHash(claim.outPoint, claim.nValidAtHeight);
uint256 valueHash = getValueHash(claim.outPoint, takeoverHeight);
vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end());
}
@ -425,12 +427,13 @@ bool CClaimTrieCacheBase::checkConsistency()
{
// verify that all claims hash to the values on the nodes
auto query = db << "SELECT name, hash FROM nodes";
auto query = db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes";
for (auto&& row: query) {
std::string name;
uint256 hash;
row >> name >> hash;
auto computedHash = recursiveComputeMerkleHash(name, true);
int takeoverHeight;
row >> name >> hash >> takeoverHeight;
auto computedHash = recursiveComputeMerkleHash(name, takeoverHeight, true);
if (computedHash != hash)
return false;
}
@ -504,22 +507,23 @@ uint256 CClaimTrieCacheBase::getMerkleHash()
{
ensureTreeStructureIsUpToDate();
std::unique_ptr<uint256> hash;
db << "SELECT hash FROM nodes WHERE name = ''" >> hash;
int takeoverHeight;
db << "SELECT hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE name = ''" >> std::tie(hash, takeoverHeight);
if (hash == nullptr || hash->IsNull()) {
assert(transacting); // no data changed but we didn't have the root hash there already?
return recursiveComputeMerkleHash("", false);
return recursiveComputeMerkleHash("", takeoverHeight, false);
}
return *hash;
}
bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const
{
CClaimValue value;
if (!getInfoForName(name, value))
auto query = db << "SELECT takeoverHeight, takeoverID FROM nodes WHERE name = ? AND takeoverID IS NOT NULL" << name;
auto it = query.begin();
if (it == query.end())
return false;
takeoverHeight = value.nValidAtHeight;
claimId = value.claimId;
return true;
*it >> takeoverHeight >> claimId;
return !claimId.IsNull();
}
bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId,
@ -528,18 +532,26 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& out
if (!transacting) { transacting = true; db << "begin"; }
// in the update scenario the previous one should be removed already
// in the downgrade scenario, the one ahead will be removed already and the old one's valid height is input
// revisiting the update scenario we have two options:
// 1. let them pull the old one first, in which case they will be responsible to pass in validHeight (since we can't determine it's a 0 delay)
// 2. don't remove the old one; have this method do a kinder "update" situation.
// Option 2 has the issue in that we don't actually update if we don't have an existing match,
// and no way to know that here without an 'update' flag
// In addition, as we currently do option 1 they use that to get the old valid height and store that for undo
// We would have to make this method return that if we go without the removal
// The other problem with 1 is that the outer shell would need to know if the one they removed was a winner or not
if (nValidHeight <= 0) {
auto delay = getDelayForName(name, claimId);
nValidHeight = nHeight + delay;
}
if (nValidHeight < 0)
nValidHeight = nHeight + getDelayForName(name, claimId); // sets nValidHeight to the old value
auto nodeName = adjustNameForValidHeight(name, nValidHeight);
auto expires = expirationTime() + nHeight;
db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName;
return true;
}
@ -548,10 +560,8 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const COutPoint& o
{
if (!transacting) { transacting = true; db << "begin"; }
if (nValidHeight <= 0) {
auto delay = getDelayForName(name, supportedClaimId);
nValidHeight = nHeight + delay;
}
if (nValidHeight < 0)
nValidHeight = nHeight + getDelayForName(name, supportedClaimId);
auto nodeName = adjustNameForValidHeight(name, nValidHeight);
auto expires = expirationTime() + nHeight;
db << "INSERT INTO supports(supportedClaimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
@ -884,7 +894,9 @@ static const boost::container::flat_map<std::pair<int, std::string>, int> takeov
{{ 653524, "celtic-folk-music-full-live-concert-mps" }, 589762},
};
bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo,
takeoverUndoType& takeoverUndo)
{
// the plan:
// for every claim and support that becomes active this block set its node hash to null (aka, dirty)
@ -932,18 +944,32 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueR
db << "SELECT name FROM nodes WHERE hash IS NULL" >> takeovers;
for (const auto& nameWithTakeover : takeovers) {
auto needsActivate = false;
if (nNextHeight >= 496856 && nNextHeight <= 653524) {
auto wit = takeoverWorkarounds.find(std::make_pair(nNextHeight, nameWithTakeover));
if (wit != takeoverWorkarounds.end()) {
activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover);
continue;
}
needsActivate = wit != takeoverWorkarounds.end();
}
// if somebody activates on this block and they are the new best, then everybody activates on this block
CClaimValue value;
if (!getInfoForName(nameWithTakeover, value) || value.nValidAtHeight == nNextHeight)
if (needsActivate || !getInfoForName(nameWithTakeover, value, 1) || value.nValidAtHeight == nNextHeight) {
activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover);
// now that they're all in get the winner:
if (getInfoForName(nameWithTakeover, value, 1)) {
int existingHeight;
std::unique_ptr<uint160> existingID;
db << "SELECT IFNULL(takeoverHeight, 0), takeoverID FROM nodes WHERE name = ?"
<< nameWithTakeover >> std::tie(existingHeight, existingID);
if (existingID == nullptr || *existingID != value.claimId) {
takeoverUndo.emplace_back(nameWithTakeover,
std::make_pair(existingHeight, existingID == nullptr ? uint160() : *existingID));
db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?"
<< nNextHeight << value.claimId << nameWithTakeover;
assert(db.rows_modified());
}
}
}
}
nNextHeight++;
@ -985,12 +1011,15 @@ void CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
<< nNextHeight << name << nNextHeight << nNextHeight;
}
bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo)
{
if (!transacting) { transacting = true; db << "begin"; }
nNextHeight--;
// to actually delete the expired items and then restore them here I would have to look up the metadata in the block
// that doesn't sound very fun so we modified the other queries to exclude expired items
for (auto it = expireSupportUndo.crbegin(); it != expireSupportUndo.crend(); ++it) {
db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?"
<< it->second.nValidAtHeight << it->second.outPoint.hash << it->second.outPoint.n;
@ -1017,16 +1046,20 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueR
db << "UPDATE nodes SET hash = NULL WHERE name = ?" << it->name;
}
return true;
}
bool CClaimTrieCacheBase::finalizeDecrement(takeoverUndoType& takeoverUndo)
{
db << "UPDATE nodes SET hash = NULL WHERE name IN "
"(SELECT nodeName FROM claims WHERE validHeight = ?)" << nNextHeight;
db << "UPDATE nodes SET hash = NULL WHERE name IN "
"(SELECT nodeName FROM supports WHERE validHeight = ?)" << nNextHeight;
return true;
}
for (auto it = takeoverUndo.crbegin(); it != takeoverUndo.crend(); ++it)
db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ?, hash = NULL WHERE name = ?"
<< it->second.first << it->second.second << it->first;
bool CClaimTrieCacheBase::finalizeDecrement()
{
return true;
}
@ -1191,33 +1224,20 @@ static const boost::container::flat_set<std::pair<int, std::string>> ownershipWo
{ 646584, "calling-tech-support-scammers-live-3" },
};
int CClaimTrieCacheBase::getNumBlocksOfContinuousOwnership(const std::string& name) const
{
if (nNextHeight <= 646584 && ownershipWorkaround.find(std::make_pair(nNextHeight, name)) != ownershipWorkaround.end())
return 0;
CClaimValue value;
if (getInfoForName(name, value))
return nNextHeight - value.nValidAtHeight;
return 0;
}
int CClaimTrieCacheBase::getDelayForName(const std::string& name) const
{
int nBlocksOfContinuousOwnership = getNumBlocksOfContinuousOwnership(name);
return std::min(nBlocksOfContinuousOwnership / base->nProportionalDelayFactor, 4032);
}
int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160& claimId) const
{
uint160 winningClaimId;
int winningTakeoverHeight;
if (getLastTakeoverForName(name, winningClaimId, winningTakeoverHeight) && winningClaimId == claimId) {
auto found = getLastTakeoverForName(name, winningClaimId, winningTakeoverHeight);
if (found && winningClaimId == claimId) {
assert(winningTakeoverHeight <= nNextHeight);
return 0;
}
return getDelayForName(name);
if (nNextHeight <= 646584 && ownershipWorkaround.find(std::make_pair(nNextHeight, name)) != ownershipWorkaround.end())
return 0;
return found ? std::min((nNextHeight - winningTakeoverHeight) / base->nProportionalDelayFactor, 4032) : 0;
}
std::string CClaimTrieCacheBase::adjustNameForValidHeight(const std::string& name, int validHeight) const

View file

@ -199,33 +199,6 @@ struct CNameOutPointHeightType
}
};
struct CNameOutPointType
{
std::string name;
COutPoint outPoint;
CNameOutPointType() = default;
CNameOutPointType(std::string name, const COutPoint& outPoint)
: name(std::move(name)), outPoint(outPoint)
{
}
bool operator==(const CNameOutPointType& other) const
{
return name == other.name && outPoint == other.outPoint;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(name);
READWRITE(outPoint);
}
};
struct CClaimNsupports
{
CClaimNsupports() = default;
@ -347,9 +320,10 @@ struct CClaimTrieProof
template <typename T>
using queueEntryType = std::pair<std::string, T>;
typedef std::vector<queueEntryType<CClaimValue>> claimQueueRowType;
typedef std::vector<queueEntryType<CSupportValue>> supportQueueRowType;
typedef std::vector<queueEntryType<CClaimValue>> claimUndoType;
typedef std::vector<queueEntryType<CSupportValue>> supportUndoType;
typedef std::vector<CNameOutPointHeightType> insertUndoType;
typedef std::vector<queueEntryType<std::pair<int, uint160>>> takeoverUndoType;
class CClaimTrieCacheBase
{
@ -370,29 +344,30 @@ public:
bool haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
bool addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount,
int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata);
int nHeight, int nValidHeight = -1, const std::vector<unsigned char>& metadata = {});
bool addSupport(const std::string& name, const COutPoint& outPoint, CAmount nAmount,
const uint160& supportedClaimId, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata);
const uint160& supportedClaimId, int nHeight, int nValidHeight = -1, const std::vector<unsigned char>& metadata = {});
bool removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight);
bool removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, int& validHeight);
virtual bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo);
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers);
virtual bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo);
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo);
virtual bool getInfoForName(const std::string& name, CClaimValue& claim) const;
virtual bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const;
virtual bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof);
virtual int expirationTime() const;
virtual bool finalizeDecrement();
virtual bool finalizeDecrement(takeoverUndoType& takeovers);
virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
@ -412,14 +387,11 @@ protected:
bool transacting;
// one greater than the height of the chain's tip
virtual uint256 recursiveComputeMerkleHash(const std::string& name, bool checkOnly);
virtual uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly);
supportEntryType getSupportsForName(const std::string& name) const;
int getDelayForName(const std::string& name) const;
virtual int getDelayForName(const std::string& name, const uint160& claimId) const;
int getNumBlocksOfContinuousOwnership(const std::string& name) const;
bool deleteNodeIfPossible(const std::string& name, std::string& parent, std::vector<std::string>& claims);
void ensureTreeStructureIsUpToDate();
@ -441,17 +413,18 @@ public:
int expirationTime() const override;
virtual void initializeIncrement();
bool finalizeDecrement() override;
bool finalizeDecrement(takeoverUndoType& takeovers) override;
bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override;
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers) override;
bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override;
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo) override;
private:
int nExpirationTime;
@ -473,17 +446,18 @@ public:
std::string normalizeClaimName(const std::string& name, bool force = false) const; // public only for validating name field on update op
bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override;
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers) override;
bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override;
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo) override;
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
bool getInfoForName(const std::string& name, CClaimValue& claim) const override;
bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const override;
CClaimSupportToName getClaimsForName(const std::string& name) const override;
std::string adjustNameForValidHeight(const std::string& name, int validHeight) const override;
@ -501,12 +475,12 @@ public:
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
void initializeIncrement() override;
bool finalizeDecrement() override;
bool finalizeDecrement(takeoverUndoType& takeovers) override;
bool allowSupportMetadata() const;
protected:
uint256 recursiveComputeMerkleHash(const std::string& name, bool checkOnly) override;
uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly) override;
};
typedef CClaimTrieCacheHashFork CClaimTrieCache;

View file

@ -25,16 +25,17 @@ int CClaimTrieCacheExpirationFork::expirationTime() const
return nExpirationTime;
}
bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo, takeoverUndoType& takeoverUndo)
{
if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) {
if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo)) {
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
return true;
}
return false;
}
bool CClaimTrieCacheExpirationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
bool CClaimTrieCacheExpirationFork::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo)
{
if (CClaimTrieCacheBase::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) {
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
@ -52,9 +53,9 @@ void CClaimTrieCacheExpirationFork::initializeIncrement()
forkForExpirationChange(true);
}
bool CClaimTrieCacheExpirationFork::finalizeDecrement()
bool CClaimTrieCacheExpirationFork::finalizeDecrement(takeoverUndoType& takeoverUndo)
{
auto ret = CClaimTrieCacheBase::finalizeDecrement();
auto ret = CClaimTrieCacheBase::finalizeDecrement(takeoverUndo);
if (ret && nNextHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
forkForExpirationChange(false);
return ret;
@ -152,13 +153,14 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(bool f
return true;
}
bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo, takeoverUndoType& takeoverUndo)
{
normalizeAllNamesInTrieIfNecessary(true);
return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo);
}
bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo)
{
auto ret = CClaimTrieCacheExpirationFork::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
if (ret)
@ -171,9 +173,9 @@ bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name,
return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), finalClaim, proof);
}
bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, CClaimValue& claim) const
bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, CClaimValue& claim, int offsetHeight) const
{
return CClaimTrieCacheExpirationFork::getInfoForName(normalizeClaimName(name), claim);
return CClaimTrieCacheExpirationFork::getInfoForName(normalizeClaimName(name), claim, offsetHeight);
}
CClaimSupportToName CClaimTrieCacheNormalizationFork::getClaimsForName(const std::string& name) const
@ -198,26 +200,27 @@ CClaimTrieCacheHashFork::CClaimTrieCacheHashFork(CClaimTrie* base) : CClaimTrieC
static const uint256 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, bool checkOnly)
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly)
{
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, checkOnly);
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, takeoverHeight, checkOnly);
auto childQuery = db << "SELECT name, hash FROM nodes WHERE parent = ? ORDER BY name" << name;
auto childQuery = db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE parent = ? ORDER BY name" << name;
std::vector<uint256> childHashes;
for (auto&& row: childQuery) {
std::string key;
std::unique_ptr<uint256> hash;
row >> key >> hash;
int childTakeoverHeight;
row >> key >> hash >> childTakeoverHeight;
if (hash == nullptr) hash = std::make_unique<uint256>();
if (hash->IsNull()) {
*hash = recursiveComputeMerkleHash(key, checkOnly);
*hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly);
}
childHashes.push_back(*hash);
}
auto claimQuery = db << "SELECT c.txID, c.txN, c.validHeight, "
auto claimQuery = db << "SELECT c.txID, c.txN, "
"(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
"AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount"
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? "
@ -226,9 +229,8 @@ uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& n
std::vector<uint256> claimHashes;
for (auto&& row: claimQuery) {
COutPoint p;
int validHeight;
row >> p.hash >> p.n >> validHeight;
auto claimHash = getValueHash(p, validHeight);
row >> p.hash >> p.n;
auto claimHash = getValueHash(p, takeoverHeight);
claimHashes.push_back(claimHash);
}
@ -310,13 +312,14 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
// cache the parent nodes
getMerkleHash();
proof = CClaimTrieProof();
auto nodeQuery = db << "SELECT name FROM nodes WHERE "
auto nodeQuery = db << "SELECT name, IFNULL(takeoverHeight, 0) FROM nodes WHERE "
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
"SELECT SUBSTR(p, 1, LENGTH(p)-1) FROM prefix WHERE p != '') SELECT p FROM prefix) "
"ORDER BY LENGTH(name)" << name;
for (auto&& row: nodeQuery) {
std::string key;;
row >> key;
int takeoverHeight;
row >> key >> takeoverHeight;
std::vector<uint256> childHashes;
uint32_t nextCurrentIdx = 0;
auto childQuery = db << "SELECT name, hash FROM nodes WHERE parent = ?" << key;
@ -335,7 +338,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
COutPoint finalOutPoint;
for (uint32_t i = 0; i < cns.claimsNsupports.size(); ++i) {
auto& child = cns.claimsNsupports[i].claim;
claimHashes.push_back(getValueHash(child.outPoint, child.nValidAtHeight));
claimHashes.push_back(getValueHash(child.outPoint, takeoverHeight));
if (child.claimId == finalClaim) {
finalClaimIdx = i;
finalOutPoint = child.outPoint;
@ -372,9 +375,9 @@ void CClaimTrieCacheHashFork::initializeIncrement()
db << "UPDATE nodes SET hash = NULL";
}
bool CClaimTrieCacheHashFork::finalizeDecrement()
bool CClaimTrieCacheHashFork::finalizeDecrement(takeoverUndoType& takeoverUndo)
{
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement();
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverUndo);
if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
db << "UPDATE nodes SET hash = NULL";
return ret;

View file

@ -56,9 +56,10 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
void blockToCache(const CBlock* pblock, CClaimTrieCache& trieCache, int nHeight)
{
insertUndoType dummyInsertUndo;
claimQueueRowType dummyExpireUndo;
claimUndoType dummyExpireUndo;
insertUndoType dummyInsertSupportUndo;
supportQueueRowType dummyExpireSupportUndo;
supportUndoType dummyExpireSupportUndo;
takeoverUndoType dummyTakeoverUndo;
CUpdateCacheCallbacks callbacks = {
.findScriptKey = [&pblock](const COutPoint& point) {
@ -78,7 +79,7 @@ void blockToCache(const CBlock* pblock, CClaimTrieCache& trieCache, int nHeight)
if (!tx->IsCoinBase())
UpdateCache(*tx, trieCache, view, nHeight, callbacks);
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo);
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverUndo);
}
BlockAssembler::Options::Options() {

View file

@ -384,6 +384,38 @@ BOOST_AUTO_TEST_CASE(support_spend_test)
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",tx5));
}
BOOST_AUTO_TEST_CASE(claimtrie_update_takeover_test)
{
ClaimTrieChainFixture fixture;
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 5);
auto cid = ClaimIdHash(tx1.GetHash(), 0);
fixture.IncrementBlocks(1);
uint160 cid2;
int takeover;
fixture.getLastTakeoverForName("test", cid2, takeover);
BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover);
CMutableTransaction u1 = fixture.MakeUpdate(tx1, "test", "a", cid, 4);
fixture.IncrementBlocks(1);
fixture.getLastTakeoverForName("test", cid2, takeover);
BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover);
CMutableTransaction u2 = fixture.MakeUpdate(u1, "test", "b", cid, 3);
fixture.IncrementBlocks(1);
fixture.getLastTakeoverForName("test", cid2, takeover);
CClaimValue value;
BOOST_REQUIRE(fixture.getInfoForName("test", value) && value.nAmount == 3);
BOOST_CHECK_EQUAL(cid, cid2);
BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover);
fixture.DecrementBlocks(1);
fixture.getLastTakeoverForName("test", cid2, takeover);
BOOST_CHECK_EQUAL(cid, cid2);
BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover);
fixture.DecrementBlocks(1);
fixture.getLastTakeoverForName("test", cid2, takeover);
BOOST_CHECK_EQUAL(cid, cid2);
BOOST_CHECK_EQUAL(chainActive.Tip()->nHeight, takeover);
}
/*
update
update preserves claim id
@ -447,7 +479,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_update_test)
CMutableTransaction tx;
tx.nVersion = CTransaction::CURRENT_VERSION;
tx.nLockTime = 1U << 31; // Disable BIP68
tx.nLockTime = 1U << 31U; // Disable BIP68
tx.vin.resize(2);
tx.vout.resize(1);
tx.vin[0].prevout.hash = tx8.GetHash();

View file

@ -26,7 +26,7 @@ public:
if (c.IsNull())
c = ClaimIdHash(p.hash, p.n);
return addClaim(key, p, c, value.nAmount, value.nHeight, -1, {});
return addClaim(key, p, c, value.nAmount, value.nHeight);
}
bool removeClaimFromTrie(const std::string& key, const COutPoint& outPoint) {
@ -47,7 +47,7 @@ public:
if (p.hash.IsNull())
p.hash = Hash(key.begin(), key.end());
return addSupport(key, p, value.nAmount, value.supportedClaimId, value.nHeight, -1, {});
return addSupport(key, p, value.nAmount, value.supportedClaimId, value.nHeight);
}
bool removeSupportFromMap(const std::string& key, const COutPoint& outPoint) {
@ -337,8 +337,8 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
CClaimTrie trie(false, 0, 1);
CClaimTrieCacheTest cache(&trie);
insertUndoType icu, isu; claimQueueRowType ecu; supportQueueRowType esu;
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
insertUndoType icu, isu; claimUndoType ecu; supportUndoType esu; takeoverUndoType tut;
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut));
CClaimValue value;
value.nHeight = 1;
@ -351,9 +351,9 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
BOOST_CHECK(cache.insertSupportIntoMap("aa", CSupportValue()));
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut));
BOOST_CHECK(cache.flush());
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut));
CSupportValue temp;
CClaimValue cv;
@ -369,7 +369,7 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
BOOST_CHECK(cache.insertClaimIntoTrie("bb", value));
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, tut));
BOOST_CHECK(cache.getInfoForName("aa", cv));
BOOST_CHECK_EQUAL(3, cv.nValidAtHeight);

View file

@ -189,7 +189,7 @@ void ClaimTrieChainFixture::CommitTx(const CMutableTransaction &tx, bool has_loc
CValidationState state;
CAmount txFeeRate = CAmount(0);
LOCK(cs_main);
BOOST_CHECK_EQUAL(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false), true);
BOOST_REQUIRE(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false));
}
}
@ -272,10 +272,10 @@ void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark)
CScript coinbase_scriptpubkey;
coinbase_scriptpubkey << CScriptNum(chainActive.Height());
std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey);
BOOST_CHECK(pblocktemplate != nullptr);
BOOST_REQUIRE(pblocktemplate != nullptr);
if (!added_unchecked)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1);
BOOST_CHECK_EQUAL(CreateBlock(pblocktemplate), true);
BOOST_REQUIRE(CreateBlock(pblocktemplate));
num_txs_for_next_block = 0;
nNextHeight = chainActive.Height() + 1;
}

View file

@ -221,13 +221,14 @@ BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
BOOST_CHECK(trieCache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), COutPoint(tx2.GetHash(), 0), name_upper, amelieValidHeight));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1, -1, {}));
BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
insertUndoType insertUndo;
claimQueueRowType expireUndo;
claimUndoType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
supportUndoType expireSupportUndo;
takeoverUndoType takeoverUndo;
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo));
BOOST_CHECK(trieCache.shouldNormalize());
}
@ -304,22 +305,23 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test)
CClaimTrieCache cache(pclaimTrie);
int height = chainActive.Height() + 1;
cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height, -1, {});
cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height, -1, {});
cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height, -1, {});
cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height, -1, {});
cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height, -1, {});
cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height);
cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height);
cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height);
cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height);
cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height);
insertUndoType insertUndo;
claimQueueRowType expireUndo;
claimUndoType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
supportUndoType expireSupportUndo;
takeoverUndoType takeoverUndo;
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo));
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 3U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[1].supports.size() == 0U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U);
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
BOOST_CHECK(cache.finalizeDecrement());
BOOST_CHECK(cache.finalizeDecrement(takeoverUndo));
std::string unused;
BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height));
BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height));

View file

@ -75,9 +75,10 @@ class CBlockUndo
public:
std::vector<CTxUndo> vtxundo; // for all but the coinbase
insertUndoType insertUndo; // any claims that went from the queue to the trie
claimQueueRowType expireUndo; // any claims that expired
claimUndoType expireUndo; // any claims that expired
insertUndoType insertSupportUndo; // any supports that went from the support queue to the support map
supportQueueRowType expireSupportUndo; // any supports that expired
supportUndoType expireSupportUndo; // any supports that expired
takeoverUndoType takeoverUndo;
ADD_SERIALIZE_METHODS;
@ -88,6 +89,7 @@ public:
READWRITE(expireUndo);
READWRITE(insertSupportUndo);
READWRITE(expireSupportUndo);
READWRITE(takeoverUndo);
}
};

View file

@ -1554,7 +1554,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
// move best block pointer to prevout block
view.SetBestBlock(pindex->pprev->GetBlockHash());
assert(trieCache.finalizeDecrement());
assert(trieCache.finalizeDecrement(blockUndo.takeoverUndo));
auto merkleHash = trieCache.getMerkleHash();
if (merkleHash != pindex->pprev->hashClaimTrie) {
LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight);
@ -2028,7 +2028,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
}
// TODO: if the "just check" flag is set, we should reduce the work done here. Incrementing blocks twice per mine is not efficient.
const auto incremented = trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo, blockundo.insertSupportUndo, blockundo.expireSupportUndo);
const auto incremented = trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo,
blockundo.insertSupportUndo, blockundo.expireSupportUndo, blockundo.takeoverUndo);
assert(incremented);
if (trieCache.getMerkleHash() != block.hashClaimTrie)