Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate undos to dedicated DB #1381

Merged
merged 1 commit into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/flushablestorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,9 @@ class CStorageView {
}
}
}
CFlushableStorageKV& GetStorage() {
return static_cast<CFlushableStorageKV&>(DB());
}

virtual bool Flush() { return DB().Flush(); }
void Discard() { DB().Discard(); }
Expand Down
55 changes: 53 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,48 @@ void SetupAnchorSPVDatabases(bool resync) {
}
}


void MigrateDBs()
{
auto it = pundosView->LowerBound<CUndosView::ByMultiUndoKey>(UndoSourceKey{});
if (it.Valid()) {
return;
}

auto time = GetTimeMillis();

// Migrate Undos
auto migrationStarted{false};
auto mnview(*pcustomcsview);
pcustomcsview->ForEachUndo([&](const UndoKey& key, const CUndo& undo){
if (!migrationStarted) {
migrationStarted = true;
LogPrintf("Migrating undo entries, might take a while...\n");
}

pundosView->SetUndo({{key.height, key.txid}, UndoSource::CustomView}, undo);
mnview.DelUndo(key);

return true;
});

if (migrationStarted) {
pundosView->Flush();
pundosDB->Flush();

auto& map = mnview.GetStorage().GetRaw();
const auto compactBegin = map.begin()->first;
const auto compactEnd = map.rbegin()->first;
mnview.Flush();
pcustomcsview->Flush();
pcustomcsDB->Flush();
pcustomcsDB->Compact(compactBegin, compactEnd);

LogPrintf("Migrating undo data finished.\n");
LogPrint(BCLog::BENCH, " - Migrating undo data takes: %dms\n", GetTimeMillis() - time);
}
}

bool SetupInterruptArg(const std::string &argName, std::string &hashStore, int &heightStore) {
// Experimental: Block height or hash to invalidate on and stop sync
auto val = gArgs.GetArg(argName, "");
Expand Down Expand Up @@ -1717,7 +1759,7 @@ bool AppInitMain(InitInterfaces& interfaces)
pcustomcsDB.reset();
pcustomcsDB = std::make_unique<CStorageLevelDB>(GetDataDir() / "enhancedcs", nCustomCacheSize, false, fReset || fReindexChainState);
pcustomcsview.reset();
pcustomcsview = std::make_unique<CCustomCSView>(*pcustomcsDB.get());
pcustomcsview = std::make_unique<CCustomCSView>(*pcustomcsDB);

if (!fReset && !fReindexChainState) {
if (!pcustomcsDB->IsEmpty() && pcustomcsview->GetDbVersion() != CCustomCSView::DbVersion) {
Expand Down Expand Up @@ -1749,6 +1791,15 @@ bool AppInitMain(InitInterfaces& interfaces)
pvaultHistoryDB = std::make_unique<CVaultHistoryStorage>(GetDataDir() / "vault", nCustomCacheSize, false, fReset || fReindexChainState);
}

// Create Undo DB
pundosDB.reset();
pundosDB = std::make_unique<CStorageLevelDB>(GetDataDir() / "undos", nCustomCacheSize, false, fReset || fReindexChainState);
pundosView.reset();
pundosView = std::make_unique<CUndosView>(*pundosDB);

// Migrate FutureSwaps and Undos to their own new DBs.
MigrateDBs();

// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!::ChainstateActive().CoinsDB().Upgrade()) {
Expand All @@ -1757,7 +1808,7 @@ bool AppInitMain(InitInterfaces& interfaces)
}

// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB(), pcustomcsview.get())) {
if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB(), pcustomcsview.get(), pundosView.get())) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated;
break;
}
Expand Down
38 changes: 17 additions & 21 deletions src/masternodes/masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,10 @@ void CSettingsView::SetDexStatsLastHeight(const int32_t height)

std::optional<int32_t> CSettingsView::GetDexStatsLastHeight()
{
return ReadBy<KVSettings, int32_t>(DEX_STATS_LAST_HEIGHT);
if (auto res = ReadBy<KVSettings, int32_t>(DEX_STATS_LAST_HEIGHT)) {
return res;
}
return {};
}

void CSettingsView::SetDexStatsEnabled(const bool enabled)
Expand Down Expand Up @@ -878,16 +881,6 @@ void CCustomCSView::CreateAndRelayConfirmMessageIfNeed(const CAnchorIndex::Ancho
}
}

void CCustomCSView::OnUndoTx(uint256 const & txid, uint32_t height)
{
const auto undo = GetUndo(UndoKey{height, txid});
if (!undo) {
return; // not custom tx, or no changes done
}
CUndo::Revert(GetStorage(), *undo); // revert the changes of this tx
DelUndo(UndoKey{height, txid}); // erase undo data, it served its purpose
}

bool CCustomCSView::CanSpend(const uint256 & txId, int height) const
{
auto node = GetMasternode(txId);
Expand Down Expand Up @@ -1085,28 +1078,31 @@ Res CCustomCSView::PopulateCollateralData(CCollateralLoans& result, CVaultId con
return Res::Ok();
}

uint256 CCustomCSView::MerkleRoot() {
uint256 CCustomCSView::MerkleRoot(CUndosView& undo) {
auto rawMap = GetStorage().GetRaw();
if (rawMap.empty()) {
return {};
}
auto isAttributes = [](const TBytes& key) {
MapKV map = {std::make_pair(key, TBytes{})};
// Attributes should not be part of merkle root
static const std::string attributes("ATTRIBUTES");
MapKV map = {std::make_pair(key, TBytes{})};
auto it = NewKVIterator<CGovView::ByName>(attributes, map);
return it.Valid() && it.Key() == attributes;
};

auto it = NewKVIterator<CUndosView::ByUndoKey>(UndoKey{}, rawMap);
auto& undoStorage = undo.GetStorage();
auto& undoMap = undoStorage.GetRaw();
auto it = NewKVIterator<CUndosView::ByMultiUndoKey>(UndoSourceKey{}, undoMap);
for (; it.Valid(); it.Next()) {
CUndo value = it.Value();
auto& map = value.before;
for (auto it = map.begin(); it != map.end();) {
isAttributes(it->first) ? map.erase(it++) : ++it;
if (it.Key().key == UndoSource::CustomView) {
CUndo value = it.Value();
auto& map = value.before;
for (auto it = map.begin(); it != map.end();) {
isAttributes(it->first) ? map.erase(it++) : ++it;
}
auto key = std::make_pair(CUndosBaseView::ByUndoKey::prefix(), static_cast<const UndoKey&>(it.Key()));
rawMap[DbTypeToBytes(key)] = DbTypeToBytes(value);
}
auto key = std::make_pair(CUndosView::ByUndoKey::prefix(), static_cast<const UndoKey&>(it.Key()));
rawMap[DbTypeToBytes(key)] = DbTypeToBytes(value);
}

std::vector<uint256> hashes;
Expand Down
14 changes: 3 additions & 11 deletions src/masternodes/masternodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ class CCustomCSView
, public CTokensView
, public CAccountsView
, public CCommunityBalancesView
, public CUndosView
, public CUndosBaseView
, public CPoolPairView
, public CGovView
, public CAnchorConfirmsView
Expand All @@ -411,7 +411,7 @@ class CCustomCSView
CTokensView :: ID, Symbol, CreationTx, LastDctId,
CAccountsView :: ByBalanceKey, ByHeightKey, ByFuturesSwapKey,
CCommunityBalancesView :: ById,
CUndosView :: ByUndoKey,
CUndosBaseView :: ByUndoKey,
CPoolPairView :: ByID, ByPair, ByShare, ByIDPair, ByPoolSwap, ByReserves, ByRewardPct, ByRewardLoanPct,
ByPoolReward, ByDailyReward, ByCustomReward, ByTotalLiquidity, ByDailyLoanReward,
ByPoolLoanReward, ByTokenDexFeePct,
Expand Down Expand Up @@ -461,9 +461,6 @@ class CCustomCSView
/// @todo newbase move to networking?
void CreateAndRelayConfirmMessageIfNeed(const CAnchorIndex::AnchorRec* anchor, const uint256 & btcTxHash, const CKey &masternodeKey);

// simplified version of undo, without any unnecessary undo data
void OnUndoTx(uint256 const & txid, uint32_t height);

bool CanSpend(const uint256 & txId, int height) const;

bool CalculateOwnerRewards(CScript const & owner, uint32_t height);
Expand All @@ -487,12 +484,7 @@ class CCustomCSView
void SetGlobalCustomTxExpiration(const uint32_t height);
uint32_t GetGlobalCustomTxExpiration() const;

uint256 MerkleRoot();

// we construct it as it
CFlushableStorageKV& GetStorage() {
return static_cast<CFlushableStorageKV&>(DB());
}
uint256 MerkleRoot(CUndosView& undo);

virtual CAccountHistoryStorage* GetAccountHistoryStore();
CVaultHistoryStorage* GetVaultHistoryStore();
Expand Down
8 changes: 0 additions & 8 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3774,15 +3774,7 @@ Res ApplyCustomTx(CCustomCSView& mnview, const CCoinsViewCache& coins, const CTr
return res;
}

// construct undo
auto& flushable = view.GetStorage();
auto undo = CUndo::Construct(mnview.GetStorage(), flushable.GetRaw());
// flush changes
view.Flush();
// write undo
if (!undo.before.empty()) {
mnview.SetUndo(UndoKey{height, tx.GetHash()}, undo);
}
return res;
}

Expand Down
17 changes: 17 additions & 0 deletions src/masternodes/undo.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
#include <serialize_optional.h>
#include <flushablestorage.h>

// Enum for future support of multiple sources of undo data, not just CustomView.
enum UndoSource : uint8_t {
CustomView = 0,
};

struct UndoKey {
uint32_t height; // height is there to be able to prune older undos using lexicographic iteration
uint256 txid;
Expand All @@ -25,6 +30,18 @@ struct UndoKey {
}
};

struct UndoSourceKey : UndoKey {
uint8_t key;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITEAS(UndoKey, *this);
READWRITE(key);
}
};

struct CUndo {
MapKV before;

Expand Down
48 changes: 40 additions & 8 deletions src/masternodes/undos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,61 @@

#include <masternodes/undos.h>

void CUndosView::ForEachUndo(std::function<bool(UndoKey const &, CLazySerialize<CUndo>)> callback, UndoKey const & start)
void CUndosBaseView::ForEachUndo(std::function<bool(UndoKey const &, CLazySerialize<CUndo>)> callback, UndoKey const & start)
{
ForEach<ByUndoKey, UndoKey, CUndo>(callback, start);
}

Res CUndosView::SetUndo(UndoKey const & key, CUndo const & undo)
Res CUndosBaseView::DelUndo(UndoKey const & key)
{
WriteBy<ByUndoKey>(key, undo);
EraseBy<ByUndoKey>(key);
return Res::Ok();
}

Res CUndosView::DelUndo(UndoKey const & key)
void CUndosView::ForEachUndo(std::function<bool(const UndoSourceKey &, CLazySerialize<CUndo>)> callback, const UndoSourceKey& start)
{
EraseBy<ByUndoKey>(key);
ForEach<ByMultiUndoKey, UndoSourceKey, CUndo>(callback, start);
}

void CUndosView::AddUndo(const UndoSource key, CStorageView & source, CStorageView & cache, uint256 const & txid, uint32_t height)
{
auto& flushable = cache.GetStorage();
auto& rawMap = flushable.GetRaw();
if (!rawMap.empty()) {
SetUndo({{height, txid}, key}, CUndo::Construct(source.GetStorage(), rawMap));
}
}

Res CUndosView::SetUndo(UndoSourceKey const & key, CUndo const & undo)
{
WriteBy<ByMultiUndoKey>(key, undo);
return Res::Ok();
}

std::optional<CUndo> CUndosView::GetUndo(UndoKey const & key) const
void CUndosView::OnUndoTx(const UndoSource key, CStorageView & source, uint256 const & txid, uint32_t height)
{
const auto undo = GetUndo({{height, txid}, key});
if (!undo) {
return; // not custom tx, or no changes done
}
CUndo::Revert(source.GetStorage(), *undo); // revert the changes of this tx
DelUndo({{height, txid}, key}); // erase undo data, it served its purpose
}

std::optional<CUndo> CUndosView::GetUndo(UndoSourceKey const & key) const
{
CUndo val;
bool ok = ReadBy<ByUndoKey>(key, val);
if (ok) {
if (ReadBy<ByMultiUndoKey>(key, val)) {
return val;
}
return {};
}

Res CUndosView::DelUndo(const UndoSourceKey & key)
{
EraseBy<ByMultiUndoKey>(key);
return Res::Ok();
}

std::unique_ptr<CStorageLevelDB> pundosDB;
std::unique_ptr<CUndosView> pundosView;
27 changes: 23 additions & 4 deletions src/masternodes/undos.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,36 @@
#include <flushablestorage.h>
#include <masternodes/res.h>

class CUndosView : public virtual CStorageView {
class CUndosBaseView : public virtual CStorageView {
public:
void ForEachUndo(std::function<bool(UndoKey const &, CLazySerialize<CUndo>)> callback, UndoKey const & start = {});

std::optional<CUndo> GetUndo(UndoKey const & key) const;
Res SetUndo(UndoKey const & key, CUndo const & undo);
Res DelUndo(UndoKey const & key);
Res DelUndo(const UndoKey & key);

// tags
struct ByUndoKey { static constexpr uint8_t prefix() { return 'u'; } };
};

class CUndosView : public CStorageView
{
public:
CUndosView(CUndosView& other) : CStorageView(new CFlushableStorageKV(other.DB())) {}
explicit CUndosView(CStorageKV& st) : CStorageView(new CFlushableStorageKV(st)) {}

void ForEachUndo(std::function<bool(const UndoSourceKey &, CLazySerialize<CUndo>)> callback, const UndoSourceKey& start = {});

[[nodiscard]] std::optional<CUndo> GetUndo(UndoSourceKey const & key) const;
Res SetUndo(const UndoSourceKey& key, const CUndo& undo);
Res DelUndo(const UndoSourceKey & key);

void AddUndo(const UndoSource key, CStorageView & source, CStorageView & cache, uint256 const & txid, uint32_t height);
void OnUndoTx(const UndoSource key, CStorageView & source, uint256 const & txid, uint32_t height);

// tags
struct ByMultiUndoKey { static constexpr uint8_t prefix() { return 'n'; } };
};

extern std::unique_ptr<CStorageLevelDB> pundosDB;
extern std::unique_ptr<CUndosView> pundosView;

#endif //DEFI_MASTERNODES_UNDOS_H
3 changes: 2 additions & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
int nPackagesSelected = 0;
int nDescendantsUpdated = 0;
CCustomCSView mnview(*pcustomcsview);
CUndosView undosView(*pundosView);
if (!blockTime) {
UpdateTime(pblock, consensus, pindexPrev); // update time before tx packaging
}
Expand Down Expand Up @@ -354,7 +355,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
&& nHeight < chainparams.GetConsensus().EunosKampungHeight) {
// includes coinbase account changes
ApplyGeneralCoinbaseTx(mnview, *(pblock->vtx[0]), nHeight, nFees, chainparams.GetConsensus());
pblock->hashMerkleRoot = Hash2(pblock->hashMerkleRoot, mnview.MerkleRoot());
pblock->hashMerkleRoot = Hash2(pblock->hashMerkleRoot, mnview.MerkleRoot(undosView));
}

LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart));
Expand Down
6 changes: 5 additions & 1 deletion src/test/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha

pcustomcsDB.reset();
pcustomcsDB = std::make_unique<CStorageLevelDB>(GetDataDir() / "enhancedcs", nMinDbCache << 20, true, true);
pcustomcsview = std::make_unique<CCustomCSView>(*pcustomcsDB.get());
pcustomcsview = std::make_unique<CCustomCSView>(*pcustomcsDB);

pundosDB.reset();
pundosDB = std::make_unique<CStorageLevelDB>(GetDataDir() / "undos", nMinDbCache << 20, true, true);
pundosView = std::make_unique<CUndosView>(*pundosDB);

panchorauths.reset();
panchorauths = std::make_unique<CAnchorAuthIndex>();
Expand Down
Loading