2018-08-06 21:40:20 +02:00
|
|
|
#include "claimtrie.h"
|
|
|
|
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include <boost/foreach.hpp>
|
2019-07-01 20:42:45 +02:00
|
|
|
#include <boost/locale.hpp>
|
2018-08-06 21:40:20 +02:00
|
|
|
#include <boost/locale/conversion.hpp>
|
|
|
|
#include <boost/locale/localization_backend.hpp>
|
|
|
|
#include <boost/scope_exit.hpp>
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
void CClaimTrieCacheExpirationFork::removeAndAddToExpirationQueue(expirationQueueRowType& row, int height, bool increment)
|
2018-08-06 21:40:20 +02:00
|
|
|
{
|
2019-07-01 20:42:45 +02:00
|
|
|
for (auto e = row.begin(); e != row.end(); ++e) {
|
2018-08-06 21:40:20 +02:00
|
|
|
// remove and insert with new expiration time
|
|
|
|
removeFromExpirationQueue(e->name, e->outPoint, height);
|
|
|
|
int extend_expiration = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime;
|
|
|
|
int new_expiration_height = increment ? height + extend_expiration : height - extend_expiration;
|
2019-07-01 20:42:45 +02:00
|
|
|
CNameOutPointType entry(e->name, e->outPoint);
|
2018-08-06 21:40:20 +02:00
|
|
|
addToExpirationQueue(new_expiration_height, entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
void CClaimTrieCacheExpirationFork::removeAndAddSupportToExpirationQueue(expirationQueueRowType& row, int height, bool increment)
|
2018-08-06 21:40:20 +02:00
|
|
|
{
|
2019-07-01 20:42:45 +02:00
|
|
|
for (auto e = row.begin(); e != row.end(); ++e) {
|
2018-08-06 21:40:20 +02:00
|
|
|
// remove and insert with new expiration time
|
|
|
|
removeSupportFromExpirationQueue(e->name, e->outPoint, height);
|
|
|
|
int extend_expiration = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime;
|
|
|
|
int new_expiration_height = increment ? height + extend_expiration : height - extend_expiration;
|
2019-07-01 20:42:45 +02:00
|
|
|
CNameOutPointType entry(e->name, e->outPoint);
|
2018-08-06 21:40:20 +02:00
|
|
|
addSupportToExpirationQueue(new_expiration_height, entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
|
2018-08-06 21:40:20 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
If increment is True, we have forked to extend the expiration time, thus items in the expiration queue
|
|
|
|
will have their expiration extended by "new expiration time - original expiration time"
|
|
|
|
|
|
|
|
If increment is False, we are decremented a block to reverse the fork. Thus items in the expiration queue
|
|
|
|
will have their expiration extension removed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
//look through db for expiration queues, if we haven't already found it in dirty expiration queue
|
2019-07-01 20:42:45 +02:00
|
|
|
boost::scoped_ptr<CDBIterator> pcursor(base->db->NewIterator());
|
|
|
|
for (pcursor->SeekToFirst(); pcursor->Valid(); pcursor->Next()) {
|
|
|
|
std::pair<uint8_t, int> key;
|
|
|
|
if (!pcursor->GetKey(key))
|
|
|
|
continue;
|
|
|
|
int height = key.second;
|
|
|
|
if (key.first == EXP_QUEUE_ROW) {
|
|
|
|
expirationQueueRowType row;
|
|
|
|
if (pcursor->GetValue(row)) {
|
|
|
|
removeAndAddToExpirationQueue(row, height, increment);
|
|
|
|
} else {
|
|
|
|
return error("%s(): error reading expiration queue rows from disk", __func__);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
2019-07-01 20:42:45 +02:00
|
|
|
} else if (key.first == SUPPORT_EXP_QUEUE_ROW) {
|
|
|
|
expirationQueueRowType row;
|
|
|
|
if (pcursor->GetValue(row)) {
|
|
|
|
removeAndAddSupportToExpirationQueue(row, height, increment);
|
|
|
|
} else {
|
|
|
|
return error("%s(): error reading support expiration queue rows from disk", __func__);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::shouldNormalize() const
|
|
|
|
{
|
|
|
|
return nNextHeight > Params().GetConsensus().nNormalizedNameForkHeight;
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
std::string CClaimTrieCacheNormalizationFork::normalizeClaimName(const std::string& name, bool force) const
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
if (!force && !shouldNormalize())
|
|
|
|
return name;
|
|
|
|
|
|
|
|
static std::locale utf8;
|
|
|
|
static bool initialized = false;
|
|
|
|
if (!initialized) {
|
|
|
|
static boost::locale::localization_backend_manager manager =
|
2019-07-01 20:42:45 +02:00
|
|
|
boost::locale::localization_backend_manager::global();
|
2018-08-06 21:40:20 +02:00
|
|
|
manager.select("icu");
|
|
|
|
|
|
|
|
static boost::locale::generator curLocale(manager);
|
|
|
|
utf8 = curLocale("en_US.UTF8");
|
|
|
|
initialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string normalized;
|
|
|
|
try {
|
|
|
|
// Check if it is a valid utf-8 string. If not, it will throw a
|
|
|
|
// boost::locale::conv::conversion_error exception which we catch later
|
|
|
|
normalized = boost::locale::conv::to_utf<char>(name, "UTF-8", boost::locale::conv::stop);
|
|
|
|
if (normalized.empty())
|
|
|
|
return name;
|
|
|
|
|
|
|
|
// these methods supposedly only use the "UTF8" portion of the locale object:
|
|
|
|
normalized = boost::locale::normalize(normalized, boost::locale::norm_nfd, utf8);
|
|
|
|
normalized = boost::locale::fold_case(normalized, utf8);
|
2019-07-01 20:42:45 +02:00
|
|
|
} catch (const boost::locale::conv::conversion_error& e) {
|
2018-08-06 21:40:20 +02:00
|
|
|
return name;
|
2019-07-01 20:42:45 +02:00
|
|
|
} catch (const std::bad_cast& e) {
|
2018-08-06 21:40:20 +02:00
|
|
|
LogPrintf("%s() is invalid or dependencies are missing: %s\n", __func__, e.what());
|
|
|
|
throw;
|
2019-07-01 20:42:45 +02:00
|
|
|
} catch (const std::exception& e) { // TODO: change to use ... with current_exception() in c++11
|
2018-08-06 21:40:20 +02:00
|
|
|
LogPrintf("%s() had an unexpected exception: %s\n", __func__, e.what());
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
return normalized;
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover)
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::insertClaimIntoTrie(normalizeClaimName(name, overrideInsertNormalization), claim, fCheckTakeover);
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover)
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::removeClaimFromTrie(normalizeClaimName(name, overrideRemoveNormalization), outPoint, claim, fCheckTakeover);
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover)
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::insertSupportIntoMap(normalizeClaimName(name, overrideInsertNormalization), support, fCheckTakeover);
|
|
|
|
}
|
2019-07-01 20:42:45 +02:00
|
|
|
|
|
|
|
bool CClaimTrieCacheNormalizationFork::removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover)
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::removeSupportFromMap(normalizeClaimName(name, overrideRemoveNormalization), outPoint, support, fCheckTakeover);
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(insertUndoType& insertUndo, claimQueueRowType& removeUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
|
|
|
{
|
|
|
|
if (nNextHeight != Params().GetConsensus().nNormalizedNameForkHeight)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// run the one-time upgrade of all names that need to change
|
|
|
|
// it modifies the (cache) trie as it goes, so we need to grab everything to be modified first
|
|
|
|
|
|
|
|
for (auto it = base->begin(); it != base->end(); ++it) {
|
|
|
|
const std::string normalized = normalizeClaimName(it.key(), true);
|
|
|
|
if (normalized == it.key())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto supports = getSupportsForName(it.key());
|
|
|
|
for (auto& support : supports) {
|
|
|
|
// if it's already going to expire just skip it
|
|
|
|
if (support.nHeight + base->nExpirationTime <= nNextHeight)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CSupportValue removed;
|
|
|
|
assert(removeSupportFromMap(it.key(), support.outPoint, removed, false));
|
|
|
|
expireSupportUndo.emplace_back(it.key(), removed);
|
|
|
|
assert(insertSupportIntoMap(normalized, support, false));
|
|
|
|
insertSupportUndo.emplace_back(it.key(), support.outPoint, -1);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
namesToCheckForTakeover.insert(normalized);
|
2018-08-06 21:40:20 +02:00
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
auto cached = cacheData(it.key(), false);
|
|
|
|
if (!cached || cached->claims.empty())
|
|
|
|
continue;
|
2018-08-06 21:40:20 +02:00
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
for (auto& claim : it->claims) {
|
|
|
|
if (claim.nHeight + base->nExpirationTime <= nNextHeight)
|
|
|
|
continue;
|
2018-08-06 21:40:20 +02:00
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
CClaimValue removed;
|
|
|
|
assert(removeClaimFromTrie(it.key(), claim.outPoint, removed, false));
|
|
|
|
removeUndo.emplace_back(it.key(), removed);
|
|
|
|
assert(insertClaimIntoTrie(normalized, claim, false));
|
|
|
|
insertUndo.emplace_back(it.key(), claim.outPoint, -1);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
2019-07-01 20:42:45 +02:00
|
|
|
|
|
|
|
takeoverHeightUndo.emplace_back(it.key(), it->nHeightOfLastTakeover);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
2019-07-01 20:42:45 +02:00
|
|
|
return true;
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
|
|
|
{
|
|
|
|
overrideInsertNormalization = normalizeAllNamesInTrieIfNecessary(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo);
|
|
|
|
BOOST_SCOPE_EXIT(&overrideInsertNormalization) { overrideInsertNormalization = false; }
|
|
|
|
BOOST_SCOPE_EXIT_END
|
|
|
|
return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
overrideRemoveNormalization = shouldNormalize();
|
2019-07-01 20:42:45 +02:00
|
|
|
BOOST_SCOPE_EXIT(&overrideRemoveNormalization) { overrideRemoveNormalization = false; }
|
|
|
|
BOOST_SCOPE_EXIT_END
|
|
|
|
return CClaimTrieCacheExpirationFork::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name, CClaimTrieProof& proof)
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), proof);
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, CClaimValue& claim) const
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::getInfoForName(normalizeClaimName(name), claim);
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
CClaimsForNameType CClaimTrieCacheNormalizationFork::getClaimsForName(const std::string& name) const
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::getClaimsForName(normalizeClaimName(name));
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
int CClaimTrieCacheNormalizationFork::getDelayForName(const std::string& name, const uint160& claimId)
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return CClaimTrieCacheExpirationFork::getDelayForName(normalizeClaimName(name), claimId);
|
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::addClaimToQueues(const std::string& name, const CClaimValue& claim)
|
|
|
|
{
|
|
|
|
return CClaimTrieCacheExpirationFork::addClaimToQueues(normalizeClaimName(name, claim.nValidAtHeight > Params().GetConsensus().nNormalizedNameForkHeight), claim);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
bool CClaimTrieCacheNormalizationFork::addSupportToQueues(const std::string& name, const CSupportValue& support)
|
|
|
|
{
|
|
|
|
return CClaimTrieCacheExpirationFork::addSupportToQueues(normalizeClaimName(name, support.nValidAtHeight > Params().GetConsensus().nNormalizedNameForkHeight), support);
|
2018-08-06 21:40:20 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 20:42:45 +02:00
|
|
|
std::string CClaimTrieCacheNormalizationFork::adjustNameForValidHeight(const std::string& name, int validHeight) const
|
|
|
|
{
|
2018-08-06 21:40:20 +02:00
|
|
|
return normalizeClaimName(name, validHeight > Params().GetConsensus().nNormalizedNameForkHeight);
|
|
|
|
}
|