// SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2020-2021, The Monero Project. #ifndef WOWLET_RESTOREHEIGHTLOOKUP_H #define WOWLET_RESTOREHEIGHTLOOKUP_H #include #include #include #include "networktype.h" #include "utils/utils.h" struct RestoreHeightLookup { NetworkType::Type type; QMap data; explicit RestoreHeightLookup(NetworkType::Type type) : type(type) {} int dateToRestoreHeight(int date) { // restore height based on a given timestamp using a lookup // table. If it cannot find the date in the lookup table, it // will calculate the blockheight based off the last known // date: ((now - lastKnownDate) / blockTime) - clearance if(this->type == NetworkType::TESTNET) return 1; int blockTime = 300; int blocksPerDay = 288; int blockCalcClearance = blocksPerDay * 5; QList values = this->data.keys(); if(date <= values.at(0)) return this->data[values.at(0)]; for(int i = 0; i != values.count(); i++) { if(values[i] > date) { return i - 1 < 0 ? this->data[values[i]] : this->data[values[i-1]] - blockCalcClearance; } } // lookup failed, calculate blockheight from last known checkpoint int lastBlockHeightTime = values.at(values.count() - 1); int lastBlockHeight = this->data[lastBlockHeightTime]; int deltaTime = date - lastBlockHeightTime; int deltaBlocks = deltaTime / blockTime; int blockHeight = (lastBlockHeight + deltaBlocks) - blockCalcClearance; qDebug() << "Calculated blockheight: " << blockHeight << " from epoch " << date; return blockHeight; } int restoreHeightToDate(int height) { // @TODO: most likely inefficient, refactor QMap::iterator i; int timestamp = 0; for (i = this->data.begin(); i != this->data.end(); ++i) { int ts = i.key(); if (i.value() > height) return timestamp; timestamp = ts; } return timestamp; } static RestoreHeightLookup *fromFile(const QString &fn, NetworkType::Type type) { // initialize this class using a lookup table, e.g `:/assets/restore_heights_monero_mainnet.txt`/ auto rtn = new RestoreHeightLookup(type); auto data = Utils::barrayToString(Utils::fileOpen(fn)); QMap _data; for(const auto &line: data.split('\n')) { if(line.trimmed().isEmpty()) continue; auto spl = line.trimmed().split(':'); rtn->data[spl.at(0).toUInt()] = spl.at(1).toUInt(); } return rtn; } }; #endif //WOWLET_RESTOREHEIGHTLOOKUP_H