some progress on making takeover height work

This commit is contained in:
Brannon King 2019-10-30 23:13:07 -06:00 committed by Anthony Fieroni
parent 395e773ef5
commit 0be9249171
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: case OP_UPDATE_CLAIM:
return claimOp.updateClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]), return claimOp.updateClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]),
vvchParams[2]); 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) 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 bool spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override
{ {
if (CClaimScriptSpendOp::spendClaim(trieCache, name, claimId)) { if (CClaimScriptSpendOp::spendClaim(trieCache, name, claimId)) {
callback(name, claimId, nValidHeight); callback(name, claimId);
return true; return true;
} }
return false; 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; spentClaimsType spentClaims;
@ -216,8 +217,8 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin
int nValidAtHeight; int nValidAtHeight;
CSpendClaimHistory spendClaim(COutPoint(txin.prevout.hash, txin.prevout.n), scriptHeight, 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) { spendClaim.callback = [&spentClaims](const std::string& name, const uint160& claimId) {
spentClaims.emplace_back(name, claimId, takeoverHeight); spentClaims.emplace_back(name, claimId);
}; };
if (ProcessClaim(spendClaim, trieCache, scriptPubKey) && callbacks.claimUndoHeights) if (ProcessClaim(spendClaim, trieCache, scriptPubKey) && callbacks.claimUndoHeights)
callbacks.claimUndoHeights(j, nValidAtHeight); 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, bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
const std::vector<unsigned char>& metadata) override const std::vector<unsigned char>& metadata) override
{ {
int takeoverHeight = -1; if (callback(name, claimId))
if (callback(name, claimId, takeoverHeight)) return CClaimScriptAddOp::addClaim(trieCache, name, claimId, -1, metadata);
return CClaimScriptAddOp::addClaim(trieCache, name, claimId, takeoverHeight, metadata);
return false; 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++) { 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; continue;
CAddSpendClaim addClaim(COutPoint(tx.GetHash(), j), txout.nValue, nHeight); 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) { for (auto itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) {
if (std::get<1>(*itSpent) == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(std::get<0>(*itSpent))) { if (itSpent->second == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)) {
takeoverHeight = std::get<2>(*itSpent);
spentClaims.erase(itSpent); spentClaims.erase(itSpent);
return true; return true;
} }

View file

@ -238,8 +238,7 @@ protected:
*/ */
bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CScript& scriptPubKey); 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; typedef std::vector<spentClaimType> spentClaimsType;
struct CUpdateCacheCallbacks 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_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.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_hash ON nodes (hash)";
db << "CREATE INDEX IF NOT EXISTS nodes_parent ON nodes (parent)"; db << "CREATE INDEX IF NOT EXISTS nodes_parent ON nodes (parent)";
@ -325,13 +325,14 @@ CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly)
return ret; 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, " 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 " "(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 >= ? " "FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? "
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN LIMIT 1" "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) { for (auto&& row: query) {
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
>> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount >> claim.nEffectiveAmount; >> 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()); .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; std::vector<uint8_t> vchToHash;
const auto pos = name.size(); 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) { for (auto&& row : query) {
std::string key; std::string key;
int childTakeoverHeight;
std::unique_ptr<uint256> hash; std::unique_ptr<uint256> hash;
row >> key >> hash; row >> key >> hash >> childTakeoverHeight;
if (hash == nullptr) hash = std::make_unique<uint256>(); if (hash == nullptr) hash = std::make_unique<uint256>();
if (hash->IsNull()) { if (hash->IsNull()) {
*hash = recursiveComputeMerkleHash(key, checkOnly); *hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly);
} }
completeHash(*hash, key, pos); completeHash(*hash, key, pos);
vchToHash.push_back(key[pos]); vchToHash.push_back(key[pos]);
@ -411,7 +413,7 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name,
CClaimValue claim; CClaimValue claim;
if (getInfoForName(name, 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()); 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 // 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) { for (auto&& row: query) {
std::string name; std::string name;
uint256 hash; uint256 hash;
row >> name >> hash; int takeoverHeight;
auto computedHash = recursiveComputeMerkleHash(name, true); row >> name >> hash >> takeoverHeight;
auto computedHash = recursiveComputeMerkleHash(name, takeoverHeight, true);
if (computedHash != hash) if (computedHash != hash)
return false; return false;
} }
@ -504,22 +507,23 @@ uint256 CClaimTrieCacheBase::getMerkleHash()
{ {
ensureTreeStructureIsUpToDate(); ensureTreeStructureIsUpToDate();
std::unique_ptr<uint256> hash; 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()) { if (hash == nullptr || hash->IsNull()) {
assert(transacting); // no data changed but we didn't have the root hash there already? assert(transacting); // no data changed but we didn't have the root hash there already?
return recursiveComputeMerkleHash("", false); return recursiveComputeMerkleHash("", takeoverHeight, false);
} }
return *hash; return *hash;
} }
bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const
{ {
CClaimValue value; auto query = db << "SELECT takeoverHeight, takeoverID FROM nodes WHERE name = ? AND takeoverID IS NOT NULL" << name;
if (!getInfoForName(name, value)) auto it = query.begin();
if (it == query.end())
return false; return false;
takeoverHeight = value.nValidAtHeight; *it >> takeoverHeight >> claimId;
claimId = value.claimId; return !claimId.IsNull();
return true;
} }
bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, 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"; } if (!transacting) { transacting = true; db << "begin"; }
// in the update scenario the previous one should be removed already // 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) { if (nValidHeight < 0)
auto delay = getDelayForName(name, claimId); nValidHeight = nHeight + getDelayForName(name, claimId); // sets nValidHeight to the old value
nValidHeight = nHeight + delay;
}
auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto nodeName = adjustNameForValidHeight(name, nValidHeight);
auto expires = expirationTime() + nHeight; auto expires = expirationTime() + nHeight;
db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) " db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName
<< outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata; << outPoint.hash << outPoint.n << nAmount << nHeight << nValidHeight << expires << metadata;
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName; db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName;
return true; return true;
} }
@ -548,10 +560,8 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const COutPoint& o
{ {
if (!transacting) { transacting = true; db << "begin"; } if (!transacting) { transacting = true; db << "begin"; }
if (nValidHeight <= 0) { if (nValidHeight < 0)
auto delay = getDelayForName(name, supportedClaimId); nValidHeight = nHeight + getDelayForName(name, supportedClaimId);
nValidHeight = nHeight + delay;
}
auto nodeName = adjustNameForValidHeight(name, nValidHeight); auto nodeName = adjustNameForValidHeight(name, nValidHeight);
auto expires = expirationTime() + nHeight; auto expires = expirationTime() + nHeight;
db << "INSERT INTO supports(supportedClaimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) " 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}, {{ 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: // the plan:
// for every claim and support that becomes active this block set its node hash to null (aka, dirty) // 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; db << "SELECT name FROM nodes WHERE hash IS NULL" >> takeovers;
for (const auto& nameWithTakeover : takeovers) { for (const auto& nameWithTakeover : takeovers) {
auto needsActivate = false;
if (nNextHeight >= 496856 && nNextHeight <= 653524) { if (nNextHeight >= 496856 && nNextHeight <= 653524) {
auto wit = takeoverWorkarounds.find(std::make_pair(nNextHeight, nameWithTakeover)); auto wit = takeoverWorkarounds.find(std::make_pair(nNextHeight, nameWithTakeover));
if (wit != takeoverWorkarounds.end()) { needsActivate = wit != takeoverWorkarounds.end();
activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover);
continue;
}
} }
// if somebody activates on this block and they are the new best, then everybody activates on this block // if somebody activates on this block and they are the new best, then everybody activates on this block
CClaimValue value; CClaimValue value;
if (!getInfoForName(nameWithTakeover, value) || value.nValidAtHeight == nNextHeight) if (needsActivate || !getInfoForName(nameWithTakeover, value, 1) || value.nValidAtHeight == nNextHeight) {
activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover); 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++; nNextHeight++;
@ -985,12 +1011,15 @@ void CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
<< nNextHeight << name << nNextHeight << nNextHeight; << 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"; } if (!transacting) { transacting = true; db << "begin"; }
nNextHeight--; 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) { for (auto it = expireSupportUndo.crbegin(); it != expireSupportUndo.crend(); ++it) {
db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?" db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?"
<< it->second.nValidAtHeight << it->second.outPoint.hash << it->second.outPoint.n; << 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; 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 " db << "UPDATE nodes SET hash = NULL WHERE name IN "
"(SELECT nodeName FROM claims WHERE validHeight = ?)" << nNextHeight; "(SELECT nodeName FROM claims WHERE validHeight = ?)" << nNextHeight;
db << "UPDATE nodes SET hash = NULL WHERE name IN " db << "UPDATE nodes SET hash = NULL WHERE name IN "
"(SELECT nodeName FROM supports WHERE validHeight = ?)" << nNextHeight; "(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; 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" }, { 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 int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160& claimId) const
{ {
uint160 winningClaimId; uint160 winningClaimId;
int winningTakeoverHeight; int winningTakeoverHeight;
if (getLastTakeoverForName(name, winningClaimId, winningTakeoverHeight) && winningClaimId == claimId) { auto found = getLastTakeoverForName(name, winningClaimId, winningTakeoverHeight);
if (found && winningClaimId == claimId) {
assert(winningTakeoverHeight <= nNextHeight); assert(winningTakeoverHeight <= nNextHeight);
return 0; 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 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 struct CClaimNsupports
{ {
CClaimNsupports() = default; CClaimNsupports() = default;
@ -347,9 +320,10 @@ struct CClaimTrieProof
template <typename T> template <typename T>
using queueEntryType = std::pair<std::string, T>; using queueEntryType = std::pair<std::string, T>;
typedef std::vector<queueEntryType<CClaimValue>> claimQueueRowType; typedef std::vector<queueEntryType<CClaimValue>> claimUndoType;
typedef std::vector<queueEntryType<CSupportValue>> supportQueueRowType; typedef std::vector<queueEntryType<CSupportValue>> supportUndoType;
typedef std::vector<CNameOutPointHeightType> insertUndoType; typedef std::vector<CNameOutPointHeightType> insertUndoType;
typedef std::vector<queueEntryType<std::pair<int, uint160>>> takeoverUndoType;
class CClaimTrieCacheBase class CClaimTrieCacheBase
{ {
@ -370,29 +344,30 @@ public:
bool haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const; 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, 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, 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 removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight);
bool removeClaim(const uint160& claimId, 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, virtual bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo); supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers);
virtual bool decrementBlock(insertUndoType& insertUndo, virtual bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo); 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 bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof);
virtual int expirationTime() const; virtual int expirationTime() const;
virtual bool finalizeDecrement(); virtual bool finalizeDecrement(takeoverUndoType& takeovers);
virtual CClaimSupportToName getClaimsForName(const std::string& name) const; virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const; virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
@ -412,14 +387,11 @@ protected:
bool transacting; bool transacting;
// one greater than the height of the chain's tip // 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; 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; 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); bool deleteNodeIfPossible(const std::string& name, std::string& parent, std::vector<std::string>& claims);
void ensureTreeStructureIsUpToDate(); void ensureTreeStructureIsUpToDate();
@ -441,17 +413,18 @@ public:
int expirationTime() const override; int expirationTime() const override;
virtual void initializeIncrement(); virtual void initializeIncrement();
bool finalizeDecrement() override; bool finalizeDecrement(takeoverUndoType& takeovers) override;
bool incrementBlock(insertUndoType& insertUndo, bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override; supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers) override;
bool decrementBlock(insertUndoType& insertUndo, bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override; supportUndoType& expireSupportUndo) override;
private: private:
int nExpirationTime; 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 std::string normalizeClaimName(const std::string& name, bool force = false) const; // public only for validating name field on update op
bool incrementBlock(insertUndoType& insertUndo, bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override; supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers) override;
bool decrementBlock(insertUndoType& insertUndo, bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override; supportUndoType& expireSupportUndo) override;
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) 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; CClaimSupportToName getClaimsForName(const std::string& name) const override;
std::string adjustNameForValidHeight(const std::string& name, int validHeight) 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; bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
void initializeIncrement() override; void initializeIncrement() override;
bool finalizeDecrement() override; bool finalizeDecrement(takeoverUndoType& takeovers) override;
bool allowSupportMetadata() const; bool allowSupportMetadata() const;
protected: protected:
uint256 recursiveComputeMerkleHash(const std::string& name, bool checkOnly) override; uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly) override;
}; };
typedef CClaimTrieCacheHashFork CClaimTrieCache; typedef CClaimTrieCacheHashFork CClaimTrieCache;

View file

@ -25,16 +25,17 @@ int CClaimTrieCacheExpirationFork::expirationTime() const
return nExpirationTime; 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)); setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
return true; return true;
} }
return false; 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)) { if (CClaimTrieCacheBase::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) {
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight)); setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
@ -52,9 +53,9 @@ void CClaimTrieCacheExpirationFork::initializeIncrement()
forkForExpirationChange(true); 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) if (ret && nNextHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
forkForExpirationChange(false); forkForExpirationChange(false);
return ret; return ret;
@ -152,13 +153,14 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(bool f
return true; 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); 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); auto ret = CClaimTrieCacheExpirationFork::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
if (ret) if (ret)
@ -171,9 +173,9 @@ bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name,
return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), finalClaim, proof); 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 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 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003"); 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) 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; std::vector<uint256> childHashes;
for (auto&& row: childQuery) { for (auto&& row: childQuery) {
std::string key; std::string key;
std::unique_ptr<uint256> hash; std::unique_ptr<uint256> hash;
row >> key >> hash; int childTakeoverHeight;
row >> key >> hash >> childTakeoverHeight;
if (hash == nullptr) hash = std::make_unique<uint256>(); if (hash == nullptr) hash = std::make_unique<uint256>();
if (hash->IsNull()) { if (hash->IsNull()) {
*hash = recursiveComputeMerkleHash(key, checkOnly); *hash = recursiveComputeMerkleHash(key, childTakeoverHeight, checkOnly);
} }
childHashes.push_back(*hash); 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 " "(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
"AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount" "AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount"
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? " "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; std::vector<uint256> claimHashes;
for (auto&& row: claimQuery) { for (auto&& row: claimQuery) {
COutPoint p; COutPoint p;
int validHeight; row >> p.hash >> p.n;
row >> p.hash >> p.n >> validHeight; auto claimHash = getValueHash(p, takeoverHeight);
auto claimHash = getValueHash(p, validHeight);
claimHashes.push_back(claimHash); claimHashes.push_back(claimHash);
} }
@ -310,13 +312,14 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
// cache the parent nodes // cache the parent nodes
getMerkleHash(); getMerkleHash();
proof = CClaimTrieProof(); 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 " "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) " "SELECT SUBSTR(p, 1, LENGTH(p)-1) FROM prefix WHERE p != '') SELECT p FROM prefix) "
"ORDER BY LENGTH(name)" << name; "ORDER BY LENGTH(name)" << name;
for (auto&& row: nodeQuery) { for (auto&& row: nodeQuery) {
std::string key;; std::string key;;
row >> key; int takeoverHeight;
row >> key >> takeoverHeight;
std::vector<uint256> childHashes; std::vector<uint256> childHashes;
uint32_t nextCurrentIdx = 0; uint32_t nextCurrentIdx = 0;
auto childQuery = db << "SELECT name, hash FROM nodes WHERE parent = ?" << key; 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; COutPoint finalOutPoint;
for (uint32_t i = 0; i < cns.claimsNsupports.size(); ++i) { for (uint32_t i = 0; i < cns.claimsNsupports.size(); ++i) {
auto& child = cns.claimsNsupports[i].claim; 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) { if (child.claimId == finalClaim) {
finalClaimIdx = i; finalClaimIdx = i;
finalOutPoint = child.outPoint; finalOutPoint = child.outPoint;
@ -372,9 +375,9 @@ void CClaimTrieCacheHashFork::initializeIncrement()
db << "UPDATE nodes SET hash = NULL"; 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) if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
db << "UPDATE nodes SET hash = NULL"; db << "UPDATE nodes SET hash = NULL";
return ret; return ret;

View file

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

View file

@ -384,6 +384,38 @@ BOOST_AUTO_TEST_CASE(support_spend_test)
fixture.DecrementBlocks(1); fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",tx5)); 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
update preserves claim id update preserves claim id
@ -447,7 +479,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_update_test)
CMutableTransaction tx; CMutableTransaction tx;
tx.nVersion = CTransaction::CURRENT_VERSION; tx.nVersion = CTransaction::CURRENT_VERSION;
tx.nLockTime = 1U << 31; // Disable BIP68 tx.nLockTime = 1U << 31U; // Disable BIP68
tx.vin.resize(2); tx.vin.resize(2);
tx.vout.resize(1); tx.vout.resize(1);
tx.vin[0].prevout.hash = tx8.GetHash(); tx.vin[0].prevout.hash = tx8.GetHash();

View file

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

View file

@ -189,7 +189,7 @@ void ClaimTrieChainFixture::CommitTx(const CMutableTransaction &tx, bool has_loc
CValidationState state; CValidationState state;
CAmount txFeeRate = CAmount(0); CAmount txFeeRate = CAmount(0);
LOCK(cs_main); 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; CScript coinbase_scriptpubkey;
coinbase_scriptpubkey << CScriptNum(chainActive.Height()); coinbase_scriptpubkey << CScriptNum(chainActive.Height());
std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey); std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey);
BOOST_CHECK(pblocktemplate != nullptr); BOOST_REQUIRE(pblocktemplate != nullptr);
if (!added_unchecked) if (!added_unchecked)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1); 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; num_txs_for_next_block = 0;
nNextHeight = chainActive.Height() + 1; 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.removeClaim(ClaimIdHash(tx2.GetHash(), 0), COutPoint(tx2.GetHash(), 0), name_upper, amelieValidHeight));
BOOST_CHECK(trieCache.getInfoForName(name, nval1)); 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)); BOOST_CHECK(trieCache.getInfoForName(name, nval1));
insertUndoType insertUndo; insertUndoType insertUndo;
claimQueueRowType expireUndo; claimUndoType expireUndo;
insertUndoType insertSupportUndo; insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo; supportUndoType expireSupportUndo;
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)); takeoverUndoType takeoverUndo;
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo));
BOOST_CHECK(trieCache.shouldNormalize()); BOOST_CHECK(trieCache.shouldNormalize());
} }
@ -304,22 +305,23 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test)
CClaimTrieCache cache(pclaimTrie); CClaimTrieCache cache(pclaimTrie);
int height = chainActive.Height() + 1; int height = chainActive.Height() + 1;
cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, 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, -1, {}); 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, -1, {}); 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, -1, {}); 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, -1, {}); cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height);
insertUndoType insertUndo; insertUndoType insertUndo;
claimQueueRowType expireUndo; claimUndoType expireUndo;
insertUndoType insertSupportUndo; insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo; supportUndoType expireSupportUndo;
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, 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.size() == 3U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U); 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[1].supports.size() == 0U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U); BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U);
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)); BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
BOOST_CHECK(cache.finalizeDecrement()); BOOST_CHECK(cache.finalizeDecrement(takeoverUndo));
std::string unused; std::string unused;
BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height)); BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height));
BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height)); BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height));

View file

@ -77,9 +77,10 @@ class CBlockUndo
public: public:
std::vector<CTxUndo> vtxundo; // for all but the coinbase std::vector<CTxUndo> vtxundo; // for all but the coinbase
insertUndoType insertUndo; // any claims that went from the queue to the trie 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 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; ADD_SERIALIZE_METHODS;
@ -90,6 +91,7 @@ public:
READWRITE(expireUndo); READWRITE(expireUndo);
READWRITE(insertSupportUndo); READWRITE(insertSupportUndo);
READWRITE(expireSupportUndo); READWRITE(expireSupportUndo);
READWRITE(takeoverUndo);
} }
}; };

View file

@ -1819,7 +1819,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
// move best block pointer to prevout block // move best block pointer to prevout block
view.SetBestBlock(pindex->pprev->GetBlockHash()); view.SetBestBlock(pindex->pprev->GetBlockHash());
assert(trieCache.finalizeDecrement()); assert(trieCache.finalizeDecrement(blockUndo.takeoverUndo));
auto merkleHash = trieCache.getMerkleHash(); auto merkleHash = trieCache.getMerkleHash();
if (merkleHash != pindex->pprev->hashClaimTrie) { if (merkleHash != pindex->pprev->hashClaimTrie) {
LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight); LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight);
@ -2304,7 +2304,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. // 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); assert(incremented);
if (trieCache.getMerkleHash() != block.hashClaimTrie) if (trieCache.getMerkleHash() != block.hashClaimTrie)