From 9949813bc67e4b50a26170fde530ed739b607658 Mon Sep 17 00:00:00 2001 From: valdok Date: Mon, 4 Dec 2023 22:09:28 +0200 Subject: [PATCH] explorer node: misc --- explorer/adapter.cpp | 161 ++++++++++++++++++++++++++++++++------ explorer/htm/explorer.htm | 116 +++++++++++++++++++-------- 2 files changed, 218 insertions(+), 59 deletions(-) diff --git a/explorer/adapter.cpp b/explorer/adapter.cpp index caff17a15..6a48215e8 100644 --- a/explorer/adapter.cpp +++ b/explorer/adapter.cpp @@ -272,41 +272,152 @@ class Adapter : public Node::IObserver, public IAdapter { if (_nextHook) _nextHook->OnRolledBack(id); } + struct TresEntry + :public intrusive::set_base_hook + { + Amount m_Total; + uint32_t m_iIdx; + }; + + intrusive::multiset_autoclear m_mapTreasury; + + void PrepareTreasureSchedule() + { + if (!m_mapTreasury.empty()) + return; + + if (Rules::get().TreasuryChecksum == Zero) + return; + + ByteBuffer buf; + _nodeBackend.get_DB().ParamGet(NodeDB::ParamID::Treasury, nullptr, nullptr, &buf); + if (buf.empty()) + return; + + Treasury::Data td; + if (!NodeProcessor::ExtractTreasury(buf, td)) + return; + + auto tb = td.get_Bursts(); + for (const auto& burst : tb) + { + auto* pE = m_mapTreasury.Create(burst.m_Height); + pE->m_Total = burst.m_Value; + } + + if (m_mapTreasury.empty()) + return; + + // to cumulative + const TresEntry* pPrev = nullptr; + for (auto& te : m_mapTreasury) + { + if (pPrev) + { + te.m_Total += pPrev->m_Total; + te.m_iIdx = pPrev->m_iIdx + 1; + } + else + te.m_iIdx = 0; + + pPrev = &te; + } + } + json get_status() override { - Height h = _nodeBackend.m_Cursor.m_Full.m_Height; + const auto& c = _nodeBackend.m_Cursor; + + char szCw[ECC::uintBig::nTxtLen10Max / 3 * 4 + 2]; + PrintDifficulty(szCw, c.m_Full.m_ChainWork); + + if (Mode::Legacy == m_Mode) + { + double possibleShieldedReadyHours = 0; + uint64_t shieldedPer24h = 0; + + if (c.m_Full.m_Height) + { + NodeDB& db = _nodeBackend.get_DB(); + auto shieldedByLast24h = db.ShieldedOutpGet(c.m_Full.m_Height >= 1440 ? c.m_Full.m_Height - 1440 : 1); + auto averageWindowBacklog = Rules::get().Shielded.MaxWindowBacklog / 2; + + if (shieldedByLast24h && shieldedByLast24h != _nodeBackend.m_Extra.m_ShieldedOutputs) + { + shieldedPer24h = _nodeBackend.m_Extra.m_ShieldedOutputs - shieldedByLast24h; + possibleShieldedReadyHours = ceil(averageWindowBacklog / (double)shieldedPer24h * 24); + } + } + + char buf[80]; + json j{ + { "timestamp", c.m_Full.m_TimeStamp }, + { "height", c.m_Full.m_Height }, + { "low_horizon", _nodeBackend.m_Extra.m_TxoHi }, + { "hash", hash_to_hex(buf, c.m_ID.m_Hash) }, + { "chainwork", szCw }, + { "peers_count", _node.get_AcessiblePeerCount() }, + { "shielded_outputs_total", _nodeBackend.m_Extra.m_ShieldedOutputs }, + { "shielded_outputs_per_24h", shieldedPer24h }, + { "shielded_possible_ready_in_hours", shieldedPer24h ? std::to_string(possibleShieldedReadyHours) : "-" } + }; + return j; + } + + json jInfo = json::array(); - double possibleShieldedReadyHours = 0; - uint64_t shieldedPer24h = 0; + jInfo.push_back({ MakeTableHdr("Height"), MakeObjHeight(c.m_Full.m_Height) }); + jInfo.push_back({ MakeTableHdr("Total Work"), szCw }); + jInfo.push_back({ MakeTableHdr("Last block Timestamp"),MakeTypeObj("time", c.m_Full.m_TimeStamp) }); + jInfo.push_back({ MakeTableHdr("Last block Subsidy"), MakeObjAmount(Rules::get_Emission(c.m_Full.m_Height)) }); - if (h) + char szBuf[uintBigFor::Type::nTxtLen10Max / 3 * 4 + 2]; + auto len = uintBigFrom(_nodeBackend.m_Extra.m_ShieldedOutputs).PrintDecimal(szBuf); + ExpanedNumWithCommas(szBuf, szBuf, len); + + jInfo.push_back({ MakeTableHdr("Total shielded outputs"), szBuf }); + + len = uintBigFrom(_nodeBackend.m_Extra.m_Txos - _nodeBackend.m_Extra.m_TxosTreasury - c.m_Full.m_Height - Rules::HeightGenesis + 1).PrintDecimal(szBuf); + ExpanedNumWithCommas(szBuf, szBuf, len); + jInfo.push_back({ MakeTableHdr("Total TXOs"), szBuf }); + + + AmountBig::Type valAmount; + Rules::get_Emission(valAmount, HeightRange(Rules::HeightGenesis, c.m_Full.m_Height)); + jInfo.push_back({ MakeTableHdr("Current Emission"), MakeObjAmount(valAmount) }); + + Rules::get_Emission(valAmount, HeightRange(Rules::HeightGenesis, MaxHeight)); + jInfo.push_back({ MakeTableHdr("Total Emission"), MakeObjAmount(valAmount) }); + + PrepareTreasureSchedule(); + if (!m_mapTreasury.empty()) { - NodeDB& db = _nodeBackend.get_DB(); - auto shieldedByLast24h = db.ShieldedOutpGet(h >= 1440 ? h - 1440 : 1); - auto averageWindowBacklog = Rules::get().Shielded.MaxWindowBacklog / 2; + Amount valTotal = m_mapTreasury.rbegin()->m_Total; - if (shieldedByLast24h && shieldedByLast24h != _nodeBackend.m_Extra.m_ShieldedOutputs) + auto it = m_mapTreasury.upper_bound(c.m_Full.m_Height, TresEntry::Comparator()); + const TresEntry* pNext = (m_mapTreasury.end() == it) ? nullptr : &(*it); + + const TresEntry* pPrev = nullptr; + if (m_mapTreasury.begin() != it) { - shieldedPer24h = _nodeBackend.m_Extra.m_ShieldedOutputs - shieldedByLast24h; - possibleShieldedReadyHours = ceil(averageWindowBacklog / (double)shieldedPer24h * 24); + --it; + pPrev = &(*it); } + + jInfo.push_back({ MakeTableHdr("Treasury total"), MakeObjAmount(valTotal) }); + jInfo.push_back({ MakeTableHdr("Treasury released"), MakeObjAmount(pPrev ? pPrev->m_Total : 0) }); + + if (pPrev) + jInfo.push_back({ MakeTableHdr("Treasury Prev release"), MakeObjHeight(pPrev->m_Key) }); + if (pNext) + jInfo.push_back({ MakeTableHdr("Treasury Next release"), MakeObjHeight(pNext->m_Key) }); } - char buf[80]; - - json j{ - { "timestamp", _nodeBackend.m_Cursor.m_Full.m_TimeStamp }, - { "height", h }, - { "low_horizon", _nodeBackend.m_Extra.m_TxoHi }, - { "hash", hash_to_hex(buf, _nodeBackend.m_Cursor.m_ID.m_Hash) }, - { "chainwork", uint256_to_hex(buf, _nodeBackend.m_Cursor.m_Full.m_ChainWork) }, - { "peers_count", _node.get_AcessiblePeerCount() }, - { "shielded_outputs_total", _nodeBackend.m_Extra.m_ShieldedOutputs }, - { "shielded_outputs_per_24h", shieldedPer24h }, - { "shielded_possible_ready_in_hours", shieldedPer24h ? std::to_string(possibleShieldedReadyHours) : "-" } - }; + auto jRet = MakeTable(std::move(jInfo)); - return j; + if (Mode::ExplicitType == m_Mode) + jRet["h"] = c.m_Full.m_Height; + return jRet; } bool extract_row(Height height, uint64_t& row, uint64_t* prevRow) { @@ -1630,7 +1741,7 @@ class Adapter : public Node::IObserver, public IAdapter { jAssets.push_back(std::move(wr.m_json)); } - return jAssets; + return MakeTable(std::move(jAssets)); } static uint32_t ExpanedNumWithCommas(char* szDst, const char* szSrc, uint32_t len) diff --git a/explorer/htm/explorer.htm b/explorer/htm/explorer.htm index f558d5712..6cf9a0a11 100644 --- a/explorer/htm/explorer.htm +++ b/explorer/htm/explorer.htm @@ -418,6 +418,46 @@

Asset " + g_CurrentID + " history

\n\ return text; } + function MakeTblAssets(j) + { + let text = "\ +\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ +"; + + let jTbl = j["value"]; + + // skip 1st row + for (let iRow = 1; iRow < jTbl.length; iRow++) + { + const jRow = jTbl[iRow]; + text += ""; + + text += MakeCell(MakeAsset(jRow[0]["value"])); + text += MakeCell(Obj2Html(jRow[1])); + text += MakeCellAmount(jRow[2]["value"]); + text += MakeCellAmount(jRow[3]["value"]); + text += MakeCell(MakeBlock(jRow[4])); + text += MakeCell(Obj2Html(jRow[5])); + + text += ""; + } + + + text += "
AidOwnerDepositSupplyLock-HeightMetadata
" + return text; + } + + function MakeCAs(h) + { + return "

" + MakeRef(UrlSelfWithID("assets", h, ""), "Confidential Assets") + "

"; + } + function DisplayBlock() { let text = ""; @@ -512,40 +552,11 @@

Asset " + g_CurrentID + " history

\n\ if (j) { text += MakeCollapsibleBegin("Assets state"); - - text += "\ -\n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ -"; - - jTbl = j["value"]; - - // skip 1st row - for (let iRow = 1; iRow < jTbl.length; iRow++) - { - const jRow = jTbl[iRow]; - text += ""; - - text += MakeCell(MakeAsset(jRow[0]["value"])); - text += MakeCell(Obj2Html(jRow[1])); - text += MakeCellAmount(jRow[2]["value"]); - text += MakeCellAmount(jRow[3]["value"]); - text += MakeCell(MakeBlock(jRow[4])); - text += MakeCell(Obj2Html(jRow[5])); - - text += ""; - } - - - text += "
AidOwnerDepositSupplyLock-HeightMetadata
" - + text += MakeTblAssets(j); text += MakeCollapsibleEnd(); } + else + text += MakeCAs(g_CurrentID); SetContent(text); } @@ -699,6 +710,31 @@

Contract " + MakeMonospace(g_CurrentID) + "

\n"; SetContent(text); } + function DisplayStatus() + { + const jData = JSON.parse(this.responseText); + + let text = MakeCollapsibleBegin("Blockchain status"); + text += Obj2Html(jData); + text += MakeCollapsibleEnd(); + + text += "

" + MakeRef(UrlSelf("contracts", ""), "Contracts") + "

"; + text += MakeCAs(jData["h"]); + text += "

" + MakeRef(UrlSelf("hdrs", ""), "Recent block headers") + "

"; + + SetContent(text); + } + + function DisplayAssets() + { + const jData = JSON.parse(this.responseText); + + let text = "

Assets state for height " + MakeBlock(g_CurrentID) + "

\n"; + text += MakeTblAssets(jData); + + SetContent(text); + } + const args = (new URL(document.location)).searchParams; const type = args.get("type"); @@ -735,15 +771,27 @@

Contract " + MakeMonospace(g_CurrentID) + "

\n"; else if (type == "hdrs") { xmlhttp.onload = DisplayHdrs; - xmlhttp.open("GET", urlPrefix + "hdrs" + urlSuffix); + xmlhttp.open("GET", urlPrefix + "hdrs" + urlSuffix + "&nMax=100"); xmlhttp.send(); } - else + else if (type == "contracts") { xmlhttp.onload = DisplayContracts; xmlhttp.open("GET", urlPrefix + "contracts" + urlSuffix); xmlhttp.send(); } + else if (type == "assets") + { + xmlhttp.onload = DisplayAssets; + xmlhttp.open("GET", urlPrefix + "assets" + urlSuffix + "&height=" + g_CurrentID); + xmlhttp.send(); + } + else + { + xmlhttp.onload = DisplayStatus; + xmlhttp.open("GET", urlPrefix + "status" + urlSuffix); + xmlhttp.send(); + }