From 374007908bc8ba5e848c66c5c17c80bca2677311 Mon Sep 17 00:00:00 2001 From: valdok Date: Thu, 30 May 2024 11:57:11 +0300 Subject: [PATCH 01/34] added Rules::IsPastFork() --- bvm/bvm2.h | 2 +- core/block_crypt.cpp | 36 +++++++++---------- core/block_crypt.h | 9 +++-- core/block_rw.cpp | 8 ++--- core/serialization_adapters.h | 4 +-- explorer/adapter.cpp | 2 +- hw_crypto/unittest/hw_crypto_test.cpp | 2 +- keykeeper/local_private_key_keeper.cpp | 4 +-- keykeeper/remote_key_keeper.cpp | 4 +-- keykeeper/trezor_key_keeper.cpp | 2 +- node/node.cpp | 12 +++---- node/processor.cpp | 22 ++++++------ node/unittests/node_test.cpp | 10 +++--- node/utils/node_net_sim.cpp | 2 +- pow/beamHash.cpp | 14 ++++---- pow/stratum_server.cpp | 4 +-- wallet/api/v6_0/v6_api_handle.cpp | 12 ++----- wallet/cli/cli.cpp | 12 ++----- .../news_channels/exchange_rate_provider.cpp | 2 +- wallet/client/wallet_client.cpp | 5 --- wallet/client/wallet_client.h | 1 - wallet/core/base_tx_builder.cpp | 2 +- wallet/core/common.cpp | 12 +------ wallet/core/common.h | 1 - .../assets/aunregister_transaction.cpp | 2 +- 25 files changed, 79 insertions(+), 107 deletions(-) diff --git a/bvm/bvm2.h b/bvm/bvm2.h index f74d2bf44..9a2405c89 100644 --- a/bvm/bvm2.h +++ b/bvm/bvm2.h @@ -291,7 +291,7 @@ namespace bvm2 { bool IsPastFork(uint32_t iFork) { assert(iFork < _countof(Rules::get().pForks)); - return get_Height() + 1 >= Rules::get().pForks[iFork].m_Height; + return Rules::get().IsPastFork(get_Height() + 1, iFork); } bool IsPastHF4() { diff --git a/core/block_crypt.cpp b/core/block_crypt.cpp index 1336c5733..cf0d8116c 100644 --- a/core/block_crypt.cpp +++ b/core/block_crypt.cpp @@ -575,7 +575,7 @@ namespace beam { oracle << m_Incubation; - if (hScheme >= Rules::get().pForks[1].m_Height) + if (Rules::get().IsPastFork(hScheme, 1)) { oracle << m_Commitment; Asset::Proof::Expose(oracle, hScheme, m_pAsset); @@ -767,7 +767,7 @@ namespace beam if (!hr.IsEmpty()) { auto& r = Rules::get(); - if ((hr.m_Min >= r.pForks[2].m_Height) && (hr.m_Max - hr.m_Min > r.MaxKernelValidityDH)) + if (r.IsPastFork(hr.m_Min, 2) && (hr.m_Max - hr.m_Min > r.MaxKernelValidityDH)) hr.m_Max = hr.m_Min + r.MaxKernelValidityDH; } @@ -803,14 +803,14 @@ namespace beam // sort for nested kernels is not important. But for 'historical' reasons it's enforced up to Fork2 // Remove this code once Fork2 is reached iff no multiple nested kernels - if ((hScheme < r.pForks[2].m_Height) && p0Krn && (*p0Krn > v)) + if (!r.IsPastFork(hScheme, 2) && p0Krn && (*p0Krn > v)) TxBase::Fail_Order(); p0Krn = &v; v.TestValid(hScheme, excNested, this); } - if (hScheme < r.pForks[2].m_Height) + if (!r.IsPastFork(hScheme, 2)) { // Prior to Fork2 the parent commitment was supposed to include the nested. But nested kernels are unlikely to be seen up to Fork2. // Remove this code once Fork2 is reached iff no such kernels exist @@ -841,7 +841,7 @@ namespace beam { r.TestForkAtLeast(hScheme, 1); - if ((hScheme >= r.pForks[2].m_Height) && !m_pRelativeLock->m_LockHeight) + if (r.IsPastFork(hScheme, 2) && !m_pRelativeLock->m_LockHeight) Exc::Fail(); // zero m_LockHeight makes no sense, but allowed prior to Fork2 } @@ -994,7 +994,7 @@ namespace beam HashBase(hp); ECC::Point comm(Zero); // invalid point, avoid collision with Std kernel, which provides the commitment here - bool bFlag = m_CanEmbed && (m_Height.m_Min >= Rules::get().pForks[3].m_Height); + bool bFlag = m_CanEmbed && Rules::get().IsPastFork(m_Height.m_Min, 3); comm.m_Y = bFlag ? 2 : 1; hp @@ -1199,7 +1199,7 @@ namespace beam bool TxKernelAssetDestroy::IsCustomDeposit() const { - return (m_Height.m_Min >= Rules::get().pForks[5].m_Height); + return Rules::get().IsPastFork(m_Height.m_Min, 5); } Amount TxKernelAssetDestroy::get_Deposit() const @@ -1338,7 +1338,7 @@ namespace beam ECC::Oracle oracle; oracle << m_Msg; - if (m_Height.m_Min >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(m_Height.m_Min, 3)) oracle << m_NotSerialized.m_hvShieldedState; // auto-generate seed for sigma proof and m_R_Output @@ -1421,7 +1421,7 @@ namespace beam if (m_Dependent) { assert(pParentCtx); - if (m_Height.m_Min >= Rules::get().pForks[4].m_Height) + if (Rules::get().IsPastFork(m_Height.m_Min, 4)) hp << *pParentCtx; } } @@ -1549,7 +1549,7 @@ namespace beam const Transaction::FeeSettings& Transaction::FeeSettings::get(Height h) { - return (h >= Rules::get().pForks[3].m_Height) ? + return Rules::get().IsPastFork(h, 3) ? g_FeeSettingsGlobal.m_AfterHF3 : g_FeeSettingsGlobal.m_BeforeHF3; } @@ -2183,7 +2183,7 @@ namespace beam bool Rules::IsEnabledCA(Height hScheme) const { - return (hScheme >= pForks[2].m_Height) && CA.Enabled; + return IsPastFork(hScheme, 2) && CA.Enabled; } Amount Rules::get_EmissionEx(Height h, Height& hEnd, Amount base) const @@ -2441,7 +2441,7 @@ namespace beam Amount Rules::get_DepositForCA(Height hScheme) const { - return (hScheme >= pForks[5].m_Height) ? CA.DepositForList5 : CA.DepositForList2; + return IsPastFork(hScheme, 5) ? CA.DepositForList5 : CA.DepositForList2; } const char* Rules::get_NetworkName() const @@ -2641,14 +2641,14 @@ namespace beam { const Rules& r = Rules::get(); - if (m_Height >= r.pForks[3].m_Height) + if (r.IsPastFork(m_Height, 3)) { Merkle::Hash hvCSA; return Interpret(hv, hv, get_KL(hv), hvCSA, get_CSA(hvCSA)); } bool bUtxo = get_Utxos(hv); - if (m_Height < r.pForks[2].m_Height) + if (!r.IsPastFork(m_Height, 2)) return bUtxo; Merkle::Hash hvSA; @@ -2828,7 +2828,7 @@ namespace beam Merkle::Hash hv; p.m_State.get_ID(hv, comm); - if (m_Height < Rules::get().pForks[3].m_Height) + if (!Rules::get().IsPastFork(m_Height, 3)) { struct MyVerifier :public ProofVerifier @@ -2928,7 +2928,7 @@ namespace beam bool Block::SystemState::Full::IsValidProofKernel(const Merkle::Hash& hvID, const Merkle::Proof& proof) const { Merkle::Hash hv = hvID; - if (m_Height < Rules::get().pForks[3].m_Height) + if (!Rules::get().IsPastFork(m_Height, 3)) { Merkle::Interpret(hv, proof); return (hv == m_Kernels); @@ -3439,7 +3439,7 @@ namespace beam CmList(const Rules& r, Height hScheme) { - m_IsPastHF6 = (hScheme >= r.pForks[6].m_Height); + m_IsPastHF6 = r.IsPastFork(hScheme, 6); } bool get_At(ECC::Point::Storage& pt_s, uint32_t iIdx) override @@ -3625,7 +3625,7 @@ namespace beam void Asset::Proof::Expose(ECC::Oracle& oracle, Height hScheme, const Ptr& p) { - if (hScheme >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(hScheme, 3)) { bool bAsset = !!p; oracle << bAsset; diff --git a/core/block_crypt.h b/core/block_crypt.h index bda7c0136..6a2d31684 100644 --- a/core/block_crypt.h +++ b/core/block_crypt.h @@ -437,10 +437,15 @@ namespace beam static void Fail_Fork(uint32_t iFork); - void TestForkAtLeast(Height h, uint32_t iFork) const + bool IsPastFork(Height h, uint32_t iFork) const { assert(iFork < _countof(pForks)); - if (h < pForks[iFork].m_Height) + return (h >= pForks[iFork].m_Height); + } + + void TestForkAtLeast(Height h, uint32_t iFork) const + { + if (!IsPastFork(h, iFork)) Fail_Fork(iFork); } diff --git a/core/block_rw.cpp b/core/block_rw.cpp index 99c1f5c35..4d450e2bf 100644 --- a/core/block_rw.cpp +++ b/core/block_rw.cpp @@ -495,7 +495,7 @@ namespace beam if (!(m_Cwp.m_hvRootLive == hv)) ThrowBadData(); - if (m_Tip.m_Height >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(m_Tip.m_Height, 3)) { BEAM_VERIFY(v.get_Utxos(hv)); if (m_Tip.m_Kernels != hv) @@ -521,7 +521,7 @@ namespace beam return false; const Rules& r = Rules::get(); - if (m_Tip.m_Height >= r.pForks[2].m_Height) + if (r.IsPastFork(m_Tip.m_Height, 2)) { if (!ProceedShielded()) return false; @@ -529,7 +529,7 @@ namespace beam if (!ProceedAssets()) return false; - if (m_Tip.m_Height >= r.pForks[3].m_Height) + if (r.IsPastFork(m_Tip.m_Height, 3)) { m_Der & m_hvContracts @@ -606,7 +606,7 @@ namespace beam { txo.m_pAsset.reset(new Asset::Proof); - if (h >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(h, 3)) m_Der & txo.m_pAsset->m_hGen; } diff --git a/core/serialization_adapters.h b/core/serialization_adapters.h index 0ce0e7788..a40214e04 100644 --- a/core/serialization_adapters.h +++ b/core/serialization_adapters.h @@ -1063,7 +1063,7 @@ namespace detail { if (bRecoveryOnly) { - if (*pRecoveryScheme >= beam::Rules::get().pForks[3].m_Height) + if (beam::Rules::get().IsPastFork(*pRecoveryScheme, 3)) ar & output.m_pAsset->m_hGen; } else savePtr(ar, output.m_pAsset); @@ -1117,7 +1117,7 @@ namespace detail { if (bRecoveryOnly) { - if (*pRecoveryScheme >= beam::Rules::get().pForks[3].m_Height) + if (beam::Rules::get().IsPastFork(*pRecoveryScheme, 3)) { output.m_pAsset = std::make_unique(); ar & output.m_pAsset->m_hGen; diff --git a/explorer/adapter.cpp b/explorer/adapter.cpp index af17db8c3..a4af19020 100644 --- a/explorer/adapter.cpp +++ b/explorer/adapter.cpp @@ -1000,7 +1000,7 @@ class Adapter : public Node::IObserver, public IAdapter { Writer wr; - if (h >= r.pForks[6].m_Height) + if (r.IsPastFork(h, 6)) { a0++; wr.m_json["x"] = 0u; diff --git a/hw_crypto/unittest/hw_crypto_test.cpp b/hw_crypto/unittest/hw_crypto_test.cpp index 6dc882770..1d9c90f0e 100644 --- a/hw_crypto/unittest/hw_crypto_test.cpp +++ b/hw_crypto/unittest/hw_crypto_test.cpp @@ -1494,7 +1494,7 @@ void TestShielded() ECC::Oracle oracle; oracle << krn.m_Msg; - if (krn.m_Height.m_Min >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(krn.m_Height.m_Min, 3)) { oracle << krn.m_NotSerialized.m_hvShieldedState; Asset::Proof::Expose(oracle, krn.m_Height.m_Min, krn.m_pAsset); diff --git a/keykeeper/local_private_key_keeper.cpp b/keykeeper/local_private_key_keeper.cpp index 4308c48df..ac945baa3 100644 --- a/keykeeper/local_private_key_keeper.cpp +++ b/keykeeper/local_private_key_keeper.cpp @@ -135,7 +135,7 @@ namespace beam::wallet !krn.m_vNested.empty()) return false; // non-trivial kernels should not be supported - if ((krn.m_Height.m_Min < Rules::get().pForks[1].m_Height) && m_This.IsTrustless()) + if (!(Rules::get().IsPastFork(krn.m_Height.m_Min, 1)) && m_This.IsTrustless()) return false; // disallow weak scheme } @@ -293,7 +293,7 @@ namespace beam::wallet if (IsTrustless()) { // disallow weak paramters - if (x.m_hScheme < Rules::get().pForks[1].m_Height) + if (!Rules::get().IsPastFork(x.m_hScheme, 1)) return Status::Unspecified; // blinding factor can be tampered without user permission } diff --git a/keykeeper/remote_key_keeper.cpp b/keykeeper/remote_key_keeper.cpp index b4486190a..61aa61374 100644 --- a/keykeeper/remote_key_keeper.cpp +++ b/keykeeper/remote_key_keeper.cpp @@ -730,7 +730,7 @@ namespace beam::wallet { if (!m_Phase) { - if (m_M.m_hScheme < Rules::get().pForks[1].m_Height) + if (!Rules::get().IsPastFork(m_M.m_hScheme, 1)) { Fin(Status::NotImplemented); return; @@ -1058,7 +1058,7 @@ namespace beam::wallet krn.UpdateMsg(); m_Oracle << krn.m_Msg; - if (krn.m_Height.m_Min >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(krn.m_Height.m_Min, 3)) { m_Oracle << krn.m_NotSerialized.m_hvShieldedState; Asset::Proof::Expose(m_Oracle, krn.m_Height.m_Min, krn.m_pAsset); diff --git a/keykeeper/trezor_key_keeper.cpp b/keykeeper/trezor_key_keeper.cpp index dc637a9b8..9826179c3 100644 --- a/keykeeper/trezor_key_keeper.cpp +++ b/keykeeper/trezor_key_keeper.cpp @@ -739,7 +739,7 @@ namespace beam::wallet void TrezorKeyKeeperProxy::InvokeAsync(Method::CreateOutput& m, const Handler::Ptr& h) { - if (m.m_hScheme < Rules::get().pForks[1].m_Height) + if (!Rules::get().IsPastFork(m.m_hScheme, 1)) return PushOut(Status::NotImplemented, h); CreateOutputCtx::Ptr pCtx = std::make_unique(*this, m); diff --git a/node/node.cpp b/node/node.cpp index 3cbf7c06c..133195b48 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -2555,7 +2555,7 @@ bool Node::CalculateFeeReserve(const TxStats& s, const HeightRange& hr, const Am { feeReserve = static_cast(-1); - if (hr.m_Min >= Rules::get().pForks[1].m_Height) + if (Rules::get().IsPastFork(hr.m_Min, 1)) { auto& fs = Transaction::FeeSettings::get(hr.m_Min); Amount feesMin = fs.Calculate(s); @@ -3858,7 +3858,7 @@ void Node::Peer::OnMsg(proto::GetExternalAddr&& msg) void Node::Peer::OnMsg(proto::BbsMsg&& msg) { - if ((m_This.m_Processor.m_Cursor.m_ID.m_Height >= Rules::get().pForks[1].m_Height) && !Rules::get().FakePoW) + if (Rules::get().IsPastFork(m_This.m_Processor.m_Cursor.m_ID.m_Height, 1) && !Rules::get().FakePoW) { // test the hash ECC::Hash::Value hv; @@ -5260,7 +5260,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) const Rules& r = Rules::get(); - if (m_Processor.m_Cursor.m_ID.m_Height >= r.pForks[2].m_Height) + if (r.IsPastFork(m_Processor.m_Cursor.m_ID.m_Height, 2)) { MySerializer ser(ctx.m_Writer.m_Stream); ser & MaxHeight; // terminator @@ -5298,7 +5298,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) m_Ser & krn.m_Txo; m_Ser & krn.m_Msg; - if (pAsset && (m_Height >= Rules::get().pForks[3].m_Height)) + if (pAsset && Rules::get().IsPastFork(m_Height, 3)) m_Ser & pAsset->m_hGen; return true; @@ -5316,7 +5316,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) while (m_Processor.get_DB().AssetGetNext(ai)) { - if (m_Processor.m_Cursor.m_ID.m_Height < r.pForks[6].m_Height) + if (!r.IsPastFork(m_Processor.m_Cursor.m_ID.m_Height, 6)) ai.SetCid(nullptr); ser & ai; @@ -5324,7 +5324,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) ser & (Asset::s_MaxCount + 1); // terminator - if (m_Processor.m_Cursor.m_ID.m_Height >= r.pForks[3].m_Height) + if (r.IsPastFork(m_Processor.m_Cursor.m_ID.m_Height, 3)) { m_Processor.EnsureCursorKernels(); diff --git a/node/processor.cpp b/node/processor.cpp index bc988ab7c..f6e47fd0a 100644 --- a/node/processor.cpp +++ b/node/processor.cpp @@ -1103,7 +1103,7 @@ bool NodeProcessor::MultiShieldedContext::IsValid(const TxKernelShieldedInput& k ECC::Oracle oracle; oracle << krn.m_Msg; - if (hScheme >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(hScheme, 3)) { oracle << krn.m_NotSerialized.m_hvShieldedState; Asset::Proof::Expose(oracle, hScheme, krn.m_pAsset); @@ -1181,7 +1181,7 @@ bool NodeProcessor::MultiShieldedContext::IsValid(const TxVectors::Eternal& txve void NodeProcessor::MultiShieldedContext::Prepare(const TxVectors::Eternal& txve, NodeProcessor& np, Height h) { - if (h < Rules::get().pForks[3].m_Height) + if (!Rules::get().IsPastFork(h, 3)) return; struct MyWalker @@ -1269,7 +1269,7 @@ bool NodeProcessor::MultiAssetContext::BatchCtx::IsValid(Height hScheme, ECC::Po if (!p.IsValidPrepare(hGen, bc, &m_vKs.front())) return false; - if (hScheme >= r.pForks[6].m_Height) + if (r.IsPastFork(hScheme, 6)) { m_Ctx.Add(0, 1, &m_vKs.front()); m_Ctx.Add(p.m_Begin + 1u, N - 1, &m_vKs.front() + 1); @@ -2375,7 +2375,7 @@ Height NodeProcessor::get_ProofKernel(Merkle::Proof& proof, TxKernel::Ptr* ppRes mmr.get_Proof(proof, iTrg); - if (sid.m_Height >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(sid.m_Height, 3)) { struct MyProofBuilder :public ProofBuilder_PrevState @@ -2951,7 +2951,7 @@ bool NodeProcessor::HandleBlock(const NodeDB::StateID& sid, const Block::SystemS Merkle::Hash hvDef; ev.m_Height++; - bool bPastFork3 = (sid.m_Height >= Rules::get().pForks[3].m_Height); + bool bPastFork3 = Rules::get().IsPastFork(sid.m_Height, 3); bool bPastFastSync = (sid.m_Height >= m_SyncData.m_TxoLo); bool bDefinition = bPastFork3 || bPastFastSync; @@ -3668,7 +3668,7 @@ Height NodeProcessor::FindVisibleKernel(const Merkle::Hash& id, const BlockInter assert(h <= bic.m_Height); const Rules& r = Rules::get(); - if ((bic.m_Height >= r.pForks[2].m_Height) && (bic.m_Height - h > r.MaxKernelValidityDH)) + if (r.IsPastFork(bic.m_Height, 2) && (bic.m_Height - h > r.MaxKernelValidityDH)) return 0; // Starting from Fork2 - visibility horizon is limited } @@ -3907,7 +3907,7 @@ bool NodeProcessor::HandleAssetDestroy2(const PeerID& pidOwner, const ContractID & ai.m_Metadata & ai.m_LockHeight; - if (bic.m_Height >= Rules::get().pForks[5].m_Height) + if (Rules::get().IsPastFork(bic.m_Height, 5)) ser & ai.m_Deposit; else assert(Rules::get().CA.DepositForList2 == ai.m_Deposit); @@ -3938,7 +3938,7 @@ bool NodeProcessor::HandleAssetDestroy2(const PeerID& pidOwner, const ContractID else ai.m_Owner = pidOwner; - if (bic.m_Height >= Rules::get().pForks[5].m_Height) + if (Rules::get().IsPastFork(bic.m_Height, 5)) der & ai.m_Deposit; else ai.m_Deposit = Rules::get().CA.DepositForList2; @@ -4597,7 +4597,7 @@ void NodeProcessor::ManageKrnID(BlockInterpretCtx& bic, const TxKernel& krn) bool NodeProcessor::HandleBlockElement(const TxKernel& v, BlockInterpretCtx& bic) { const Rules& r = Rules::get(); - if (bic.m_Fwd && (bic.m_Height >= r.pForks[2].m_Height) && !bic.m_AlreadyValidated) + if (bic.m_Fwd && r.IsPastFork(bic.m_Height, 2) && !bic.m_AlreadyValidated) { Height hPrev = FindVisibleKernel(v.m_Internal.m_ID, bic); if (hPrev >= Rules::HeightGenesis) @@ -6135,7 +6135,7 @@ Difficulty NodeProcessor::get_NextDifficulty() // actual dt, only making sure it's non-negative uint32_t dtSrc_s = (thw1.first > thw0.first) ? static_cast(thw1.first - thw0.first) : 0; - if (m_Cursor.m_Full.m_Height >= r.pForks[1].m_Height) + if (r.IsPastFork(m_Cursor.m_Full.m_Height, 1)) { // Apply dampening. Recalculate dtSrc_s := dtSrc_s * M/N + dtTrg_s * (N-M)/N // Use 64-bit arithmetic to avoid overflow @@ -6600,7 +6600,7 @@ void NodeProcessor::GenerateNewHdr(BlockContext& bc, BlockInterpretCtx& bic) ev.get_Definition(bc.m_Hdr.m_Definition); - if (ev.m_Height >= Rules::get().pForks[3].m_Height) + if (Rules::get().IsPastFork(ev.m_Height, 3)) get_Utxos().get_Hash(bc.m_Hdr.m_Kernels); else bc.m_Hdr.m_Kernels = ev.m_hvKernels; diff --git a/node/unittests/node_test.cpp b/node/unittests/node_test.cpp index ee47cf8b0..2d6e1789d 100644 --- a/node/unittests/node_test.cpp +++ b/node/unittests/node_test.cpp @@ -1003,7 +1003,7 @@ namespace beam mk.m_bUseHashlock = 0 != (1 & h); mk.m_Height = h; - if (!(m_hvKrnRel == Zero) && (h >= Rules::get().pForks[1].m_Height)) + if (!(m_hvKrnRel == Zero) && Rules::get().IsPastFork(h, 1)) { mk.m_hvRelLock = m_hvKrnRel; m_hvKrnRel = Zero; @@ -1930,7 +1930,7 @@ namespace beam bool SendShielded() { Height h = m_vStates.back().m_Height; - if (h + 1 < Rules::get().pForks[2].m_Height + 3) + if ((h < 2) || !Rules::get().IsPastFork(h - 2, 2)) return false; proto::NewTransaction msgTx; @@ -2365,7 +2365,7 @@ namespace beam return false; const Block::SystemState::Full& s = m_vStates.back(); - if (s.m_Height + 1 < Rules::get().pForks[2].m_Height) + if (!Rules::get().IsPastFork(s.m_Height + 1, 2)) return false; const Amount nFee = 330; @@ -2410,7 +2410,7 @@ namespace beam return false; const Block::SystemState::Full& s = m_vStates.back(); - if (s.m_Height + 1 < Rules::get().pForks[2].m_Height) + if (!Rules::get().IsPastFork(s.m_Height + 1, 2)) return false; val -= nFee; @@ -2596,7 +2596,7 @@ namespace beam bool MaybeInvokeContract(proto::NewTransaction& msg, Amount& val) { const Block::SystemState::Full& s = m_vStates.back(); - if (s.m_Height + 1 < Rules::get().pForks[3].m_Height) + if (!Rules::get().IsPastFork(s.m_Height + 1, 3)) return false; if (m_pMan) diff --git a/node/utils/node_net_sim.cpp b/node/utils/node_net_sim.cpp index edda66dcd..936692048 100644 --- a/node/utils/node_net_sim.cpp +++ b/node/utils/node_net_sim.cpp @@ -512,7 +512,7 @@ struct Context Height h = m_FlyClient.get_Height(); std::cout << "H=" << h << std::endl; - if (h < Rules::get().pForks[2].m_Height) + if (!Rules::get().IsPastFork(h, 2)) return; std::cout << "\tTotal shielded in/outs: " << (m_pProc->m_Mmr.m_Shielded.m_Count - m_pProc->m_Extra.m_ShieldedOutputs) << " / " << m_pProc->m_Extra.m_ShieldedOutputs << std::endl; diff --git a/pow/beamHash.cpp b/pow/beamHash.cpp index 95b110db1..ecb70ecd6 100644 --- a/pow/beamHash.cpp +++ b/pow/beamHash.cpp @@ -33,13 +33,15 @@ struct Block::PoW::Helper BeamHash_III BeamHashIII; PoWScheme* getCurrentPoW(Height h) { - if (h < Rules::get().pForks[1].m_Height) { - return &BeamHashI; - } else if (h < Rules::get().pForks[2].m_Height) { - return &BeamHashII; - } else { + + const Rules& r = Rules::get(); + if (r.IsPastFork(h, 2)) return &BeamHashIII; - } + + if (r.IsPastFork(h, 1)) + return &BeamHashII; + + return &BeamHashI; } void Reset(const void* pInput, uint32_t nSizeInput, const NonceType& nonce, Height h) diff --git a/pow/stratum_server.cpp b/pow/stratum_server.cpp index 23c1fabb7..0f27526fe 100644 --- a/pow/stratum_server.cpp +++ b/pow/stratum_server.cpp @@ -136,9 +136,7 @@ bool Server::on_login(uint64_t from, const Login& login) { Result res(login.id, loginSuccess ? stratum::no_error : stratum::login_failed); res.nonceprefix = conn->get_nonceprefix(); - res.forkheight = Rules::get().pForks[1].m_Height; - res.forkheight2 = Rules::get().pForks[2].m_Height; - std::cout << "Fork Heights: " << Rules::get().pForks[1].m_Height << " " << Rules::get().pForks[2].m_Height << std::endl; + append_json_msg(_fw, res); bool sent = conn->send_msg(_currentMsg, false, !loginSuccess); _currentMsg.clear(); diff --git a/wallet/api/v6_0/v6_api_handle.cpp b/wallet/api/v6_0/v6_api_handle.cpp index e8e80d17b..97086770b 100644 --- a/wallet/api/v6_0/v6_api_handle.cpp +++ b/wallet/api/v6_0/v6_api_handle.cpp @@ -967,16 +967,8 @@ namespace beam::wallet Merkle::Hash blockHash; state.get_Hash(blockHash); - std::string rulesHash = Rules::get().pForks[_countof(Rules::get().pForks) - 1].m_Hash.str(); - - for (size_t i = 1; i < _countof(Rules::get().pForks); i++) - { - if (state.m_Height < Rules::get().pForks[i].m_Height) - { - rulesHash = Rules::get().pForks[i - 1].m_Hash.str(); - break; - } - } + const Rules& r = Rules::get(); + std::string rulesHash = r.pForks[r.FindFork(state.m_Height)].m_Hash.str(); BlockDetails::Response response; response.height = state.m_Height; diff --git a/wallet/cli/cli.cpp b/wallet/cli/cli.cpp index 1b5d009c3..be352460f 100644 --- a/wallet/cli/cli.cpp +++ b/wallet/cli/cli.cpp @@ -2919,16 +2919,8 @@ namespace Merkle::Hash blockHash; state.get_Hash(blockHash); - std::string rulesHash = Rules::get().pForks[_countof(Rules::get().pForks) - 1].m_Hash.str(); - - for (size_t i = 1; i < _countof(Rules::get().pForks); i++) - { - if (state.m_Height < Rules::get().pForks[i].m_Height) - { - rulesHash = Rules::get().pForks[i - 1].m_Hash.str(); - break; - } - } + const Rules& r = Rules::get(); + std::string rulesHash = r.pForks[r.FindFork(state.m_Height)].m_Hash.str(); std::cout << "Block Details:" << "\n" << "Height: " << state.m_Height << "\n" diff --git a/wallet/client/extensions/news_channels/exchange_rate_provider.cpp b/wallet/client/extensions/news_channels/exchange_rate_provider.cpp index 1475dde9e..fc9eca0fc 100644 --- a/wallet/client/extensions/news_channels/exchange_rate_provider.cpp +++ b/wallet/client/extensions/news_channels/exchange_rate_provider.cpp @@ -111,7 +111,7 @@ namespace beam::wallet Block::SystemState::ID state; if (m_storage.getSystemStateID(state)) { - if (state.m_Height >= Rules::get().pForks[3].m_Height) // we do not process old versioned messages + if (Rules::get().IsPastFork(state.m_Height, 3)) // we do not process old versioned messages { std::vector receivedRates; if (fromByteBuffer(buffer, receivedRates)) diff --git a/wallet/client/wallet_client.cpp b/wallet/client/wallet_client.cpp index 2a835f7c5..6214bab84 100644 --- a/wallet/client/wallet_client.cpp +++ b/wallet/client/wallet_client.cpp @@ -1067,11 +1067,6 @@ namespace beam::wallet return m_thread && m_thread->joinable(); } - bool WalletClient::isFork1() const - { - return m_currentHeight >= getRules().pForks[1].m_Height; - } - size_t WalletClient::getUnsafeActiveTransactionsCount() const { return m_unsafeActiveTxCount; diff --git a/wallet/client/wallet_client.h b/wallet/client/wallet_client.h index 1a6cf884e..675b85bf3 100644 --- a/wallet/client/wallet_client.h +++ b/wallet/client/wallet_client.h @@ -142,7 +142,6 @@ namespace beam::wallet std::string getNodeAddress() const; std::string exportOwnerKey(const beam::SecString& pass) const; bool isRunning() const; - bool isFork1() const; size_t getUnsafeActiveTransactionsCount() const; size_t getUnreadNotificationsCount() const; bool isConnectionTrusted() const; diff --git a/wallet/core/base_tx_builder.cpp b/wallet/core/base_tx_builder.cpp index da5680026..a3b1fcc51 100644 --- a/wallet/core/base_tx_builder.cpp +++ b/wallet/core/base_tx_builder.cpp @@ -918,7 +918,7 @@ namespace beam::wallet void BaseTxBuilder::CheckMinimumFee(const TxStats* pFromPeer /* = nullptr */) { // after 1st fork fee should be >= minimal fee - if (Rules::get().pForks[1].m_Height <= m_Height.m_Min) + if (Rules::get().IsPastFork(m_Height.m_Min, 1)) { Amount feeInps = 0; for (const auto& si : m_Coins.m_InputShielded) diff --git a/wallet/core/common.cpp b/wallet/core/common.cpp index 6ee2bdc12..18f90dabd 100644 --- a/wallet/core/common.cpp +++ b/wallet/core/common.cpp @@ -1559,7 +1559,7 @@ namespace beam::wallet TxFailureReason CheckAssetsEnabled(Height h) { const Rules& r = Rules::get(); - if (h < r.pForks[2].m_Height) + if (!r.IsPastFork(h, 2)) return TxFailureReason::AssetsDisabledFork2; if (!r.CA.Enabled) @@ -1571,16 +1571,6 @@ namespace beam::wallet return TxFailureReason::Count; } - bool isFork3(Height h) - { - const Rules& r = Rules::get(); - if (h < r.pForks[3].m_Height) - { - return false; - } - return true; - } - void AppendLibraryVersion(TxParameters& params) { #ifdef BEAM_LIB_VERSION diff --git a/wallet/core/common.h b/wallet/core/common.h index 92504dce1..88b6a2b6c 100644 --- a/wallet/core/common.h +++ b/wallet/core/common.h @@ -825,7 +825,6 @@ namespace beam::wallet extern bool g_AssetsEnabled; // global flag TxFailureReason CheckAssetsEnabled(Height h); - bool isFork3(Height h); void AppendLibraryVersion(TxParameters& params); diff --git a/wallet/transactions/assets/aunregister_transaction.cpp b/wallet/transactions/assets/aunregister_transaction.cpp index 5842a11e6..9c856906c 100644 --- a/wallet/transactions/assets/aunregister_transaction.cpp +++ b/wallet/transactions/assets/aunregister_transaction.cpp @@ -45,7 +45,7 @@ namespace beam::wallet std::unique_ptr pKrn = std::make_unique(); pKrn->m_AssetID = m_Tx.GetMandatoryParameter(TxParameterID::AssetID); - if (m_Height.m_Min >= Rules::get().pForks[5].m_Height) + if (Rules::get().IsPastFork(m_Height.m_Min, 5)) pKrn->m_Deposit = valDeposit; AddKernel(std::move(pKrn)); From 6e29353c91348312f9a11ec568d834ebc322d656 Mon Sep 17 00:00:00 2001 From: valdok Date: Thu, 30 May 2024 12:42:01 +0300 Subject: [PATCH 02/34] Rules::IsPastFork_() (template version) --- bvm/bvm2.cpp | 18 +++---- bvm/bvm2.h | 12 ++--- core/block_crypt.cpp | 48 +++++++++---------- core/block_crypt.h | 14 ++++++ core/block_rw.cpp | 8 ++-- core/serialization_adapters.h | 4 +- explorer/adapter.cpp | 2 +- hw_crypto/unittest/hw_crypto_test.cpp | 2 +- keykeeper/local_private_key_keeper.cpp | 4 +- keykeeper/remote_key_keeper.cpp | 4 +- keykeeper/trezor_key_keeper.cpp | 2 +- node/node.cpp | 12 ++--- node/processor.cpp | 24 +++++----- node/unittests/node_test.cpp | 10 ++-- node/utils/node_net_sim.cpp | 2 +- pow/beamHash.cpp | 4 +- .../news_channels/exchange_rate_provider.cpp | 2 +- wallet/core/base_tx_builder.cpp | 2 +- wallet/core/common.cpp | 2 +- .../assets/aunregister_transaction.cpp | 2 +- 20 files changed, 94 insertions(+), 84 deletions(-) diff --git a/bvm/bvm2.cpp b/bvm/bvm2.cpp index ed0069678..4d565b57e 100644 --- a/bvm/bvm2.cpp +++ b/bvm/bvm2.cpp @@ -478,7 +478,7 @@ namespace bvm2 { uint32_t ProcessorContract::get_WasmVersion() { - return IsPastFork(6) ? 1 : 0; + return IsPastFork_<6>() ? 1 : 0; } void Processor::Compiler::Compile(ByteBuffer& res, const Blob& src, Kind kind, Wasm::Compiler::DebugInfo* pDbgInfo /* = nullptr */) @@ -1370,7 +1370,7 @@ namespace bvm2 { } BVM_METHOD_HOST(LoadVarEx) { - Exc::Test(IsPastHF4()); + Exc::Test(IsPastFork_<4>()); std::setmin(nKeyBufSize, Limits::VarKeySize); Exc::Test(nKey <= nKeyBufSize); @@ -1445,7 +1445,7 @@ namespace bvm2 { auto nCalleeStackMax = m_Stack.m_BytesCurrent; uint8_t* pArgsPtr = nullptr; - bool bPastHF6 = IsPastFork(6); + bool bPastHF6 = IsPastFork_<6>(); if (!bPastHF6) { nFlags &= 0xff; // before HF6 it was uint8_t @@ -1559,7 +1559,7 @@ namespace bvm2 { BVM_METHOD_HOST(UpdateShader) { - Exc::Test(IsPastHF4()); + Exc::Test(IsPastFork_<4>()); TestCanWrite(); TestVarSize(nVal); @@ -1793,7 +1793,7 @@ namespace bvm2 { BVM_METHOD(get_ForkHeight) { if (Kind::Contract == get_Kind()) - Exc::Test(IsPastFork(5)); + Exc::Test(IsPastFork_<5>()); const Rules& r = Rules::get(); return (iFork >= _countof(r.pForks)) ? MaxHeight : r.pForks[iFork].m_Height; @@ -1805,7 +1805,7 @@ namespace bvm2 { { if (Kind::Contract == get_Kind()) { - Exc::Test(IsPastFork(6)); + Exc::Test(IsPastFork_<6>()); DischargeUnits(Limits::Cost::LoadVar); } @@ -2056,7 +2056,7 @@ namespace bvm2 { BVM_METHOD(HashClone) { if (Kind::Contract == get_Kind()) - Exc::Test(IsPastHF4()); + Exc::Test(IsPastFork_<4>()); return CloneHash(m_DataProcessor.FindStrict(pHash)); } @@ -2235,7 +2235,7 @@ namespace bvm2 { BVM_METHOD(Secp_Point_ExportEx) { if (Kind::Contract == get_Kind()) - Exc::Test(IsPastHF4()); + Exc::Test(IsPastFork_<4>()); DischargeUnits(Limits::Cost::Secp_Point_Export); m_Secp.m_Point.FindStrict(p).m_Val.Export(get_AddrAsW(res)); @@ -3876,7 +3876,7 @@ namespace bvm2 { // Shader aux void ProcessorContract::AddRemoveShader(const ContractID& cid, const Blob* pCode) { - AddRemoveShader(cid, pCode, IsPastHF4()); + AddRemoveShader(cid, pCode, IsPastFork_<4>()); } void ProcessorContract::AddRemoveShader(const ContractID& cid, const Blob* pCode, bool bFireEvent) diff --git a/bvm/bvm2.h b/bvm/bvm2.h index 9a2405c89..58b091223 100644 --- a/bvm/bvm2.h +++ b/bvm/bvm2.h @@ -288,15 +288,11 @@ namespace bvm2 { const HeightPos* FromWasmOpt(Wasm::Word pPos, HeightPos& buf); - bool IsPastFork(uint32_t iFork) + template + bool IsPastFork_() { - assert(iFork < _countof(Rules::get().pForks)); - return Rules::get().IsPastFork(get_Height() + 1, iFork); - } - - bool IsPastHF4() { // current height does not include the current being-interpreted block - return IsPastFork(4); + return Rules::get().IsPastFork_(get_Height() + 1); } public: @@ -433,7 +429,7 @@ namespace bvm2 { void TestVarSize(uint32_t n) { - uint32_t nMax = IsPastHF4() ? Limits::VarSize_4 : Limits::VarSize_0; + uint32_t nMax = IsPastFork_<4>() ? Limits::VarSize_4 : Limits::VarSize_0; Exc::Test(n <= nMax); } diff --git a/core/block_crypt.cpp b/core/block_crypt.cpp index cf0d8116c..60cf6e179 100644 --- a/core/block_crypt.cpp +++ b/core/block_crypt.cpp @@ -575,7 +575,7 @@ namespace beam { oracle << m_Incubation; - if (Rules::get().IsPastFork(hScheme, 1)) + if (Rules::get().IsPastFork_<1>(hScheme)) { oracle << m_Commitment; Asset::Proof::Expose(oracle, hScheme, m_pAsset); @@ -767,7 +767,7 @@ namespace beam if (!hr.IsEmpty()) { auto& r = Rules::get(); - if (r.IsPastFork(hr.m_Min, 2) && (hr.m_Max - hr.m_Min > r.MaxKernelValidityDH)) + if (r.IsPastFork_<2>(hr.m_Min) && (hr.m_Max - hr.m_Min > r.MaxKernelValidityDH)) hr.m_Max = hr.m_Min + r.MaxKernelValidityDH; } @@ -778,7 +778,7 @@ namespace beam { const Rules& r = Rules::get(); // alias if (m_CanEmbed) - r.TestForkAtLeast(hScheme, 1); + r.TestForkAtLeast_<1>(hScheme); if (pParent) { @@ -803,14 +803,14 @@ namespace beam // sort for nested kernels is not important. But for 'historical' reasons it's enforced up to Fork2 // Remove this code once Fork2 is reached iff no multiple nested kernels - if (!r.IsPastFork(hScheme, 2) && p0Krn && (*p0Krn > v)) + if (!r.IsPastFork_<2>(hScheme) && p0Krn && (*p0Krn > v)) TxBase::Fail_Order(); p0Krn = &v; v.TestValid(hScheme, excNested, this); } - if (!r.IsPastFork(hScheme, 2)) + if (!r.IsPastFork_<2>(hScheme)) { // Prior to Fork2 the parent commitment was supposed to include the nested. But nested kernels are unlikely to be seen up to Fork2. // Remove this code once Fork2 is reached iff no such kernels exist @@ -839,9 +839,9 @@ namespace beam const Rules& r = Rules::get(); // alias if (m_pRelativeLock) { - r.TestForkAtLeast(hScheme, 1); + r.TestForkAtLeast_<1>(hScheme); - if (r.IsPastFork(hScheme, 2) && !m_pRelativeLock->m_LockHeight) + if (r.IsPastFork_<2>(hScheme) && !m_pRelativeLock->m_LockHeight) Exc::Fail(); // zero m_LockHeight makes no sense, but allowed prior to Fork2 } @@ -994,7 +994,7 @@ namespace beam HashBase(hp); ECC::Point comm(Zero); // invalid point, avoid collision with Std kernel, which provides the commitment here - bool bFlag = m_CanEmbed && Rules::get().IsPastFork(m_Height.m_Min, 3); + bool bFlag = m_CanEmbed && Rules::get().IsPastFork_<3>(m_Height.m_Min); comm.m_Y = bFlag ? 2 : 1; hp @@ -1048,7 +1048,7 @@ namespace beam TestValidBase(hScheme, exc, pParent); const Rules& r = Rules::get(); // alias - r.TestForkAtLeast(hScheme, 2); + r.TestForkAtLeast_<2>(hScheme); r.TestEnabledCA(); ECC::Point::Native pPt[2]; @@ -1199,7 +1199,7 @@ namespace beam bool TxKernelAssetDestroy::IsCustomDeposit() const { - return Rules::get().IsPastFork(m_Height.m_Min, 5); + return Rules::get().IsPastFork_<5>(m_Height.m_Min); } Amount TxKernelAssetDestroy::get_Deposit() const @@ -1234,7 +1234,7 @@ namespace beam TestValidBase(hScheme, exc, pParent); const Rules& r = Rules::get(); // alias - r.TestForkAtLeast(hScheme, 2); + r.TestForkAtLeast_<2>(hScheme); r.TestEnabledShielded(); if (m_Txo.m_pAsset) @@ -1281,7 +1281,7 @@ namespace beam TestValidBase(hScheme, exc, pParent); const Rules& r = Rules::get(); // alias - r.TestForkAtLeast(hScheme, 2); + r.TestForkAtLeast_<2>(hScheme); r.TestEnabledShielded(); ECC::Point ptNeg = m_SpendProof.m_Commitment; @@ -1338,7 +1338,7 @@ namespace beam ECC::Oracle oracle; oracle << m_Msg; - if (Rules::get().IsPastFork(m_Height.m_Min, 3)) + if (Rules::get().IsPastFork_<3>(m_Height.m_Min)) oracle << m_NotSerialized.m_hvShieldedState; // auto-generate seed for sigma proof and m_R_Output @@ -1385,7 +1385,7 @@ namespace beam TestValidBase(hScheme, exc, pParent); const Rules& r = Rules::get(); // alias - r.TestForkAtLeast(hScheme, 3); + r.TestForkAtLeast_<3>(hScheme); ECC::Point::Native comm; comm.ImportNnzStrict(m_Commitment); @@ -1421,7 +1421,7 @@ namespace beam if (m_Dependent) { assert(pParentCtx); - if (Rules::get().IsPastFork(m_Height.m_Min, 4)) + if (Rules::get().IsPastFork_<4>(m_Height.m_Min)) hp << *pParentCtx; } } @@ -1549,7 +1549,7 @@ namespace beam const Transaction::FeeSettings& Transaction::FeeSettings::get(Height h) { - return Rules::get().IsPastFork(h, 3) ? + return Rules::get().IsPastFork_<3>(h) ? g_FeeSettingsGlobal.m_AfterHF3 : g_FeeSettingsGlobal.m_BeforeHF3; } @@ -2183,7 +2183,7 @@ namespace beam bool Rules::IsEnabledCA(Height hScheme) const { - return IsPastFork(hScheme, 2) && CA.Enabled; + return IsPastFork_<2>(hScheme) && CA.Enabled; } Amount Rules::get_EmissionEx(Height h, Height& hEnd, Amount base) const @@ -2441,7 +2441,7 @@ namespace beam Amount Rules::get_DepositForCA(Height hScheme) const { - return IsPastFork(hScheme, 5) ? CA.DepositForList5 : CA.DepositForList2; + return IsPastFork_<5>(hScheme) ? CA.DepositForList5 : CA.DepositForList2; } const char* Rules::get_NetworkName() const @@ -2641,14 +2641,14 @@ namespace beam { const Rules& r = Rules::get(); - if (r.IsPastFork(m_Height, 3)) + if (r.IsPastFork_<3>(m_Height)) { Merkle::Hash hvCSA; return Interpret(hv, hv, get_KL(hv), hvCSA, get_CSA(hvCSA)); } bool bUtxo = get_Utxos(hv); - if (!r.IsPastFork(m_Height, 2)) + if (!r.IsPastFork_<2>(m_Height)) return bUtxo; Merkle::Hash hvSA; @@ -2828,7 +2828,7 @@ namespace beam Merkle::Hash hv; p.m_State.get_ID(hv, comm); - if (!Rules::get().IsPastFork(m_Height, 3)) + if (!Rules::get().IsPastFork_<3>(m_Height)) { struct MyVerifier :public ProofVerifier @@ -2928,7 +2928,7 @@ namespace beam bool Block::SystemState::Full::IsValidProofKernel(const Merkle::Hash& hvID, const Merkle::Proof& proof) const { Merkle::Hash hv = hvID; - if (!Rules::get().IsPastFork(m_Height, 3)) + if (!Rules::get().IsPastFork_<3>(m_Height)) { Merkle::Interpret(hv, proof); return (hv == m_Kernels); @@ -3439,7 +3439,7 @@ namespace beam CmList(const Rules& r, Height hScheme) { - m_IsPastHF6 = r.IsPastFork(hScheme, 6); + m_IsPastHF6 = r.IsPastFork_<6>(hScheme); } bool get_At(ECC::Point::Storage& pt_s, uint32_t iIdx) override @@ -3625,7 +3625,7 @@ namespace beam void Asset::Proof::Expose(ECC::Oracle& oracle, Height hScheme, const Ptr& p) { - if (Rules::get().IsPastFork(hScheme, 3)) + if (Rules::get().IsPastFork_<3>(hScheme)) { bool bAsset = !!p; oracle << bAsset; diff --git a/core/block_crypt.h b/core/block_crypt.h index 6a2d31684..6f9032f43 100644 --- a/core/block_crypt.h +++ b/core/block_crypt.h @@ -443,12 +443,26 @@ namespace beam return (h >= pForks[iFork].m_Height); } + template + bool IsPastFork_(Height h) const + { + static_assert(iFork < _countof(pForks), ""); + return IsPastFork(h, iFork); + } + void TestForkAtLeast(Height h, uint32_t iFork) const { if (!IsPastFork(h, iFork)) Fail_Fork(iFork); } + template + void TestForkAtLeast_(Height h) const + { + static_assert(iFork < _countof(pForks), ""); + TestForkAtLeast(h, iFork); + } + void TestEnabledCA() const { if (!CA.Enabled) diff --git a/core/block_rw.cpp b/core/block_rw.cpp index 4d450e2bf..4a1b5d681 100644 --- a/core/block_rw.cpp +++ b/core/block_rw.cpp @@ -495,7 +495,7 @@ namespace beam if (!(m_Cwp.m_hvRootLive == hv)) ThrowBadData(); - if (Rules::get().IsPastFork(m_Tip.m_Height, 3)) + if (Rules::get().IsPastFork_<3>(m_Tip.m_Height)) { BEAM_VERIFY(v.get_Utxos(hv)); if (m_Tip.m_Kernels != hv) @@ -521,7 +521,7 @@ namespace beam return false; const Rules& r = Rules::get(); - if (r.IsPastFork(m_Tip.m_Height, 2)) + if (r.IsPastFork_<2>(m_Tip.m_Height)) { if (!ProceedShielded()) return false; @@ -529,7 +529,7 @@ namespace beam if (!ProceedAssets()) return false; - if (r.IsPastFork(m_Tip.m_Height, 3)) + if (r.IsPastFork_<3>(m_Tip.m_Height)) { m_Der & m_hvContracts @@ -606,7 +606,7 @@ namespace beam { txo.m_pAsset.reset(new Asset::Proof); - if (Rules::get().IsPastFork(h, 3)) + if (Rules::get().IsPastFork_<3>(h)) m_Der & txo.m_pAsset->m_hGen; } diff --git a/core/serialization_adapters.h b/core/serialization_adapters.h index a40214e04..685cccc03 100644 --- a/core/serialization_adapters.h +++ b/core/serialization_adapters.h @@ -1063,7 +1063,7 @@ namespace detail { if (bRecoveryOnly) { - if (beam::Rules::get().IsPastFork(*pRecoveryScheme, 3)) + if (beam::Rules::get().IsPastFork_<3>(*pRecoveryScheme)) ar & output.m_pAsset->m_hGen; } else savePtr(ar, output.m_pAsset); @@ -1117,7 +1117,7 @@ namespace detail { if (bRecoveryOnly) { - if (beam::Rules::get().IsPastFork(*pRecoveryScheme, 3)) + if (beam::Rules::get().IsPastFork_<3>(*pRecoveryScheme)) { output.m_pAsset = std::make_unique(); ar & output.m_pAsset->m_hGen; diff --git a/explorer/adapter.cpp b/explorer/adapter.cpp index a4af19020..6a9928fd6 100644 --- a/explorer/adapter.cpp +++ b/explorer/adapter.cpp @@ -1000,7 +1000,7 @@ class Adapter : public Node::IObserver, public IAdapter { Writer wr; - if (r.IsPastFork(h, 6)) + if (r.IsPastFork_<6>(h)) { a0++; wr.m_json["x"] = 0u; diff --git a/hw_crypto/unittest/hw_crypto_test.cpp b/hw_crypto/unittest/hw_crypto_test.cpp index 1d9c90f0e..a41f30ec3 100644 --- a/hw_crypto/unittest/hw_crypto_test.cpp +++ b/hw_crypto/unittest/hw_crypto_test.cpp @@ -1494,7 +1494,7 @@ void TestShielded() ECC::Oracle oracle; oracle << krn.m_Msg; - if (Rules::get().IsPastFork(krn.m_Height.m_Min, 3)) + if (Rules::get().IsPastFork_<3>(krn.m_Height.m_Min)) { oracle << krn.m_NotSerialized.m_hvShieldedState; Asset::Proof::Expose(oracle, krn.m_Height.m_Min, krn.m_pAsset); diff --git a/keykeeper/local_private_key_keeper.cpp b/keykeeper/local_private_key_keeper.cpp index ac945baa3..be2fc91f6 100644 --- a/keykeeper/local_private_key_keeper.cpp +++ b/keykeeper/local_private_key_keeper.cpp @@ -135,7 +135,7 @@ namespace beam::wallet !krn.m_vNested.empty()) return false; // non-trivial kernels should not be supported - if (!(Rules::get().IsPastFork(krn.m_Height.m_Min, 1)) && m_This.IsTrustless()) + if (!(Rules::get().IsPastFork_<1>(krn.m_Height.m_Min)) && m_This.IsTrustless()) return false; // disallow weak scheme } @@ -293,7 +293,7 @@ namespace beam::wallet if (IsTrustless()) { // disallow weak paramters - if (!Rules::get().IsPastFork(x.m_hScheme, 1)) + if (!Rules::get().IsPastFork_<1>(x.m_hScheme)) return Status::Unspecified; // blinding factor can be tampered without user permission } diff --git a/keykeeper/remote_key_keeper.cpp b/keykeeper/remote_key_keeper.cpp index 61aa61374..dd29d6003 100644 --- a/keykeeper/remote_key_keeper.cpp +++ b/keykeeper/remote_key_keeper.cpp @@ -730,7 +730,7 @@ namespace beam::wallet { if (!m_Phase) { - if (!Rules::get().IsPastFork(m_M.m_hScheme, 1)) + if (!Rules::get().IsPastFork_<1>(m_M.m_hScheme)) { Fin(Status::NotImplemented); return; @@ -1058,7 +1058,7 @@ namespace beam::wallet krn.UpdateMsg(); m_Oracle << krn.m_Msg; - if (Rules::get().IsPastFork(krn.m_Height.m_Min, 3)) + if (Rules::get().IsPastFork_<3>(krn.m_Height.m_Min)) { m_Oracle << krn.m_NotSerialized.m_hvShieldedState; Asset::Proof::Expose(m_Oracle, krn.m_Height.m_Min, krn.m_pAsset); diff --git a/keykeeper/trezor_key_keeper.cpp b/keykeeper/trezor_key_keeper.cpp index 9826179c3..c0f5e2b11 100644 --- a/keykeeper/trezor_key_keeper.cpp +++ b/keykeeper/trezor_key_keeper.cpp @@ -739,7 +739,7 @@ namespace beam::wallet void TrezorKeyKeeperProxy::InvokeAsync(Method::CreateOutput& m, const Handler::Ptr& h) { - if (!Rules::get().IsPastFork(m.m_hScheme, 1)) + if (!Rules::get().IsPastFork_<1>(m.m_hScheme)) return PushOut(Status::NotImplemented, h); CreateOutputCtx::Ptr pCtx = std::make_unique(*this, m); diff --git a/node/node.cpp b/node/node.cpp index 133195b48..5beff5133 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -2555,7 +2555,7 @@ bool Node::CalculateFeeReserve(const TxStats& s, const HeightRange& hr, const Am { feeReserve = static_cast(-1); - if (Rules::get().IsPastFork(hr.m_Min, 1)) + if (Rules::get().IsPastFork_<1>(hr.m_Min)) { auto& fs = Transaction::FeeSettings::get(hr.m_Min); Amount feesMin = fs.Calculate(s); @@ -3858,7 +3858,7 @@ void Node::Peer::OnMsg(proto::GetExternalAddr&& msg) void Node::Peer::OnMsg(proto::BbsMsg&& msg) { - if (Rules::get().IsPastFork(m_This.m_Processor.m_Cursor.m_ID.m_Height, 1) && !Rules::get().FakePoW) + if (Rules::get().IsPastFork_<1>(m_This.m_Processor.m_Cursor.m_ID.m_Height) && !Rules::get().FakePoW) { // test the hash ECC::Hash::Value hv; @@ -5260,7 +5260,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) const Rules& r = Rules::get(); - if (r.IsPastFork(m_Processor.m_Cursor.m_ID.m_Height, 2)) + if (r.IsPastFork_<2>(m_Processor.m_Cursor.m_ID.m_Height)) { MySerializer ser(ctx.m_Writer.m_Stream); ser & MaxHeight; // terminator @@ -5298,7 +5298,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) m_Ser & krn.m_Txo; m_Ser & krn.m_Msg; - if (pAsset && Rules::get().IsPastFork(m_Height, 3)) + if (pAsset && Rules::get().IsPastFork_<3>(m_Height)) m_Ser & pAsset->m_hGen; return true; @@ -5316,7 +5316,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) while (m_Processor.get_DB().AssetGetNext(ai)) { - if (!r.IsPastFork(m_Processor.m_Cursor.m_ID.m_Height, 6)) + if (!r.IsPastFork_<6>(m_Processor.m_Cursor.m_ID.m_Height)) ai.SetCid(nullptr); ser & ai; @@ -5324,7 +5324,7 @@ bool Node::GenerateRecoveryInfo(const char* szPath) ser & (Asset::s_MaxCount + 1); // terminator - if (r.IsPastFork(m_Processor.m_Cursor.m_ID.m_Height, 3)) + if (r.IsPastFork_<3>(m_Processor.m_Cursor.m_ID.m_Height)) { m_Processor.EnsureCursorKernels(); diff --git a/node/processor.cpp b/node/processor.cpp index f6e47fd0a..0939ad6ab 100644 --- a/node/processor.cpp +++ b/node/processor.cpp @@ -1103,7 +1103,7 @@ bool NodeProcessor::MultiShieldedContext::IsValid(const TxKernelShieldedInput& k ECC::Oracle oracle; oracle << krn.m_Msg; - if (Rules::get().IsPastFork(hScheme, 3)) + if (Rules::get().IsPastFork_<3>(hScheme)) { oracle << krn.m_NotSerialized.m_hvShieldedState; Asset::Proof::Expose(oracle, hScheme, krn.m_pAsset); @@ -1181,7 +1181,7 @@ bool NodeProcessor::MultiShieldedContext::IsValid(const TxVectors::Eternal& txve void NodeProcessor::MultiShieldedContext::Prepare(const TxVectors::Eternal& txve, NodeProcessor& np, Height h) { - if (!Rules::get().IsPastFork(h, 3)) + if (!Rules::get().IsPastFork_<3>(h)) return; struct MyWalker @@ -1269,7 +1269,7 @@ bool NodeProcessor::MultiAssetContext::BatchCtx::IsValid(Height hScheme, ECC::Po if (!p.IsValidPrepare(hGen, bc, &m_vKs.front())) return false; - if (r.IsPastFork(hScheme, 6)) + if (r.IsPastFork_<6>(hScheme)) { m_Ctx.Add(0, 1, &m_vKs.front()); m_Ctx.Add(p.m_Begin + 1u, N - 1, &m_vKs.front() + 1); @@ -2375,7 +2375,7 @@ Height NodeProcessor::get_ProofKernel(Merkle::Proof& proof, TxKernel::Ptr* ppRes mmr.get_Proof(proof, iTrg); - if (Rules::get().IsPastFork(sid.m_Height, 3)) + if (Rules::get().IsPastFork_<3>(sid.m_Height)) { struct MyProofBuilder :public ProofBuilder_PrevState @@ -2951,7 +2951,7 @@ bool NodeProcessor::HandleBlock(const NodeDB::StateID& sid, const Block::SystemS Merkle::Hash hvDef; ev.m_Height++; - bool bPastFork3 = Rules::get().IsPastFork(sid.m_Height, 3); + bool bPastFork3 = Rules::get().IsPastFork_<3>(sid.m_Height); bool bPastFastSync = (sid.m_Height >= m_SyncData.m_TxoLo); bool bDefinition = bPastFork3 || bPastFastSync; @@ -3668,7 +3668,7 @@ Height NodeProcessor::FindVisibleKernel(const Merkle::Hash& id, const BlockInter assert(h <= bic.m_Height); const Rules& r = Rules::get(); - if (r.IsPastFork(bic.m_Height, 2) && (bic.m_Height - h > r.MaxKernelValidityDH)) + if (r.IsPastFork_<2>(bic.m_Height) && (bic.m_Height - h > r.MaxKernelValidityDH)) return 0; // Starting from Fork2 - visibility horizon is limited } @@ -3907,7 +3907,7 @@ bool NodeProcessor::HandleAssetDestroy2(const PeerID& pidOwner, const ContractID & ai.m_Metadata & ai.m_LockHeight; - if (Rules::get().IsPastFork(bic.m_Height, 5)) + if (Rules::get().IsPastFork_<5>(bic.m_Height)) ser & ai.m_Deposit; else assert(Rules::get().CA.DepositForList2 == ai.m_Deposit); @@ -3938,7 +3938,7 @@ bool NodeProcessor::HandleAssetDestroy2(const PeerID& pidOwner, const ContractID else ai.m_Owner = pidOwner; - if (Rules::get().IsPastFork(bic.m_Height, 5)) + if (Rules::get().IsPastFork_<5>(bic.m_Height)) der & ai.m_Deposit; else ai.m_Deposit = Rules::get().CA.DepositForList2; @@ -4597,7 +4597,7 @@ void NodeProcessor::ManageKrnID(BlockInterpretCtx& bic, const TxKernel& krn) bool NodeProcessor::HandleBlockElement(const TxKernel& v, BlockInterpretCtx& bic) { const Rules& r = Rules::get(); - if (bic.m_Fwd && r.IsPastFork(bic.m_Height, 2) && !bic.m_AlreadyValidated) + if (bic.m_Fwd && r.IsPastFork_<2>(bic.m_Height) && !bic.m_AlreadyValidated) { Height hPrev = FindVisibleKernel(v.m_Internal.m_ID, bic); if (hPrev >= Rules::HeightGenesis) @@ -4917,7 +4917,7 @@ bool NodeProcessor::BlockInterpretCtx::BvmProcessor::Invoke(const bvm2::Contract m_Stack.PushAlias(krn.m_Args); m_Instruction.m_Mode = - IsPastHF4() ? + IsPastFork_<4>() ? Wasm::Reader::Mode::Standard : m_Bic.m_TxValidation ? Wasm::Reader::Mode::Restrict : @@ -6135,7 +6135,7 @@ Difficulty NodeProcessor::get_NextDifficulty() // actual dt, only making sure it's non-negative uint32_t dtSrc_s = (thw1.first > thw0.first) ? static_cast(thw1.first - thw0.first) : 0; - if (r.IsPastFork(m_Cursor.m_Full.m_Height, 1)) + if (r.IsPastFork_<1>(m_Cursor.m_Full.m_Height)) { // Apply dampening. Recalculate dtSrc_s := dtSrc_s * M/N + dtTrg_s * (N-M)/N // Use 64-bit arithmetic to avoid overflow @@ -6600,7 +6600,7 @@ void NodeProcessor::GenerateNewHdr(BlockContext& bc, BlockInterpretCtx& bic) ev.get_Definition(bc.m_Hdr.m_Definition); - if (Rules::get().IsPastFork(ev.m_Height, 3)) + if (Rules::get().IsPastFork_<3>(ev.m_Height)) get_Utxos().get_Hash(bc.m_Hdr.m_Kernels); else bc.m_Hdr.m_Kernels = ev.m_hvKernels; diff --git a/node/unittests/node_test.cpp b/node/unittests/node_test.cpp index 2d6e1789d..f13456ec9 100644 --- a/node/unittests/node_test.cpp +++ b/node/unittests/node_test.cpp @@ -1003,7 +1003,7 @@ namespace beam mk.m_bUseHashlock = 0 != (1 & h); mk.m_Height = h; - if (!(m_hvKrnRel == Zero) && Rules::get().IsPastFork(h, 1)) + if (!(m_hvKrnRel == Zero) && Rules::get().IsPastFork_<1>(h)) { mk.m_hvRelLock = m_hvKrnRel; m_hvKrnRel = Zero; @@ -1930,7 +1930,7 @@ namespace beam bool SendShielded() { Height h = m_vStates.back().m_Height; - if ((h < 2) || !Rules::get().IsPastFork(h - 2, 2)) + if ((h < 2) || !Rules::get().IsPastFork_<2>(h - 2)) return false; proto::NewTransaction msgTx; @@ -2365,7 +2365,7 @@ namespace beam return false; const Block::SystemState::Full& s = m_vStates.back(); - if (!Rules::get().IsPastFork(s.m_Height + 1, 2)) + if (!Rules::get().IsPastFork_<2>(s.m_Height + 1)) return false; const Amount nFee = 330; @@ -2410,7 +2410,7 @@ namespace beam return false; const Block::SystemState::Full& s = m_vStates.back(); - if (!Rules::get().IsPastFork(s.m_Height + 1, 2)) + if (!Rules::get().IsPastFork_<2>(s.m_Height + 1)) return false; val -= nFee; @@ -2596,7 +2596,7 @@ namespace beam bool MaybeInvokeContract(proto::NewTransaction& msg, Amount& val) { const Block::SystemState::Full& s = m_vStates.back(); - if (!Rules::get().IsPastFork(s.m_Height + 1, 3)) + if (!Rules::get().IsPastFork_<3>(s.m_Height + 1)) return false; if (m_pMan) diff --git a/node/utils/node_net_sim.cpp b/node/utils/node_net_sim.cpp index 936692048..547d66806 100644 --- a/node/utils/node_net_sim.cpp +++ b/node/utils/node_net_sim.cpp @@ -512,7 +512,7 @@ struct Context Height h = m_FlyClient.get_Height(); std::cout << "H=" << h << std::endl; - if (!Rules::get().IsPastFork(h, 2)) + if (!Rules::get().IsPastFork_<2>(h)) return; std::cout << "\tTotal shielded in/outs: " << (m_pProc->m_Mmr.m_Shielded.m_Count - m_pProc->m_Extra.m_ShieldedOutputs) << " / " << m_pProc->m_Extra.m_ShieldedOutputs << std::endl; diff --git a/pow/beamHash.cpp b/pow/beamHash.cpp index ecb70ecd6..3e237e726 100644 --- a/pow/beamHash.cpp +++ b/pow/beamHash.cpp @@ -35,10 +35,10 @@ struct Block::PoW::Helper PoWScheme* getCurrentPoW(Height h) { const Rules& r = Rules::get(); - if (r.IsPastFork(h, 2)) + if (r.IsPastFork_<2>(h)) return &BeamHashIII; - if (r.IsPastFork(h, 1)) + if (r.IsPastFork_<1>(h)) return &BeamHashII; return &BeamHashI; diff --git a/wallet/client/extensions/news_channels/exchange_rate_provider.cpp b/wallet/client/extensions/news_channels/exchange_rate_provider.cpp index fc9eca0fc..b3976ce38 100644 --- a/wallet/client/extensions/news_channels/exchange_rate_provider.cpp +++ b/wallet/client/extensions/news_channels/exchange_rate_provider.cpp @@ -111,7 +111,7 @@ namespace beam::wallet Block::SystemState::ID state; if (m_storage.getSystemStateID(state)) { - if (Rules::get().IsPastFork(state.m_Height, 3)) // we do not process old versioned messages + if (Rules::get().IsPastFork_<3>(state.m_Height)) // we do not process old versioned messages { std::vector receivedRates; if (fromByteBuffer(buffer, receivedRates)) diff --git a/wallet/core/base_tx_builder.cpp b/wallet/core/base_tx_builder.cpp index a3b1fcc51..307c51ce0 100644 --- a/wallet/core/base_tx_builder.cpp +++ b/wallet/core/base_tx_builder.cpp @@ -918,7 +918,7 @@ namespace beam::wallet void BaseTxBuilder::CheckMinimumFee(const TxStats* pFromPeer /* = nullptr */) { // after 1st fork fee should be >= minimal fee - if (Rules::get().IsPastFork(m_Height.m_Min, 1)) + if (Rules::get().IsPastFork_<1>(m_Height.m_Min)) { Amount feeInps = 0; for (const auto& si : m_Coins.m_InputShielded) diff --git a/wallet/core/common.cpp b/wallet/core/common.cpp index 18f90dabd..b0b5600b7 100644 --- a/wallet/core/common.cpp +++ b/wallet/core/common.cpp @@ -1559,7 +1559,7 @@ namespace beam::wallet TxFailureReason CheckAssetsEnabled(Height h) { const Rules& r = Rules::get(); - if (!r.IsPastFork(h, 2)) + if (!r.IsPastFork_<2>(h)) return TxFailureReason::AssetsDisabledFork2; if (!r.CA.Enabled) diff --git a/wallet/transactions/assets/aunregister_transaction.cpp b/wallet/transactions/assets/aunregister_transaction.cpp index 9c856906c..58f17491a 100644 --- a/wallet/transactions/assets/aunregister_transaction.cpp +++ b/wallet/transactions/assets/aunregister_transaction.cpp @@ -45,7 +45,7 @@ namespace beam::wallet std::unique_ptr pKrn = std::make_unique(); pKrn->m_AssetID = m_Tx.GetMandatoryParameter(TxParameterID::AssetID); - if (Rules::get().IsPastFork(m_Height.m_Min, 5)) + if (Rules::get().IsPastFork_<5>(m_Height.m_Min)) pKrn->m_Deposit = valDeposit; AddKernel(std::move(pKrn)); From eb89203e8601d956555d31bc8232d683db125476 Mon Sep 17 00:00:00 2001 From: valdok Date: Thu, 30 May 2024 23:37:35 +0300 Subject: [PATCH 03/34] wallet: making sure voucher response is received after wallet restart --- wallet/core/wallet.cpp | 193 ++++++++++++++++++++++++++++++++++++++--- wallet/core/wallet.h | 22 +++++ 2 files changed, 201 insertions(+), 14 deletions(-) diff --git a/wallet/core/wallet.cpp b/wallet/core/wallet.cpp index 7c02cd354..cf06d8d0f 100644 --- a/wallet/core/wallet.cpp +++ b/wallet/core/wallet.cpp @@ -150,6 +150,14 @@ namespace beam::wallet m_Extra.m_ShieldedOutputs = m_WalletDB->get_ShieldedOuts(); } + struct Wallet::VoucherManager::Ser { + static const uint32_t s_Ver = 1u; + static const char s_szVarName[]; + }; + + const char Wallet::VoucherManager::Ser::s_szVarName[] = "voucher_man"; + + Wallet::~Wallet() { CleanupNetwork(); @@ -167,6 +175,13 @@ namespace beam::wallet m_MessageEndpoints.clear(); m_NodeEndpoint = nullptr; + + // save voucher request manager state + auto buf = m_VoucherManager.SaveState(); + if (buf.empty()) + m_WalletDB->removeVarRaw(VoucherManager::Ser::s_szVarName); + else + m_WalletDB->setVarRaw(VoucherManager::Ser::s_szVarName, &buf.front(), buf.size()); } // Fly client implementation @@ -321,6 +336,13 @@ namespace beam::wallet void Wallet::ResumeAllTransactions() { + // restore being-received vouchers + { + ByteBuffer buf; + m_WalletDB->getBlob(VoucherManager::Ser::s_szVarName, buf); + m_VoucherManager.LoadState(buf); + } + auto func = [this](const auto& tx) { ResumeTransaction(tx); @@ -328,6 +350,8 @@ namespace beam::wallet }; TxListFilter filter; m_WalletDB->visitTx(func, filter); + + m_VoucherManager.CheckTimer(); } bool Wallet::IsWalletInSync() const @@ -675,19 +699,36 @@ namespace beam::wallet if (m_setTrg.end() != m_setTrg.find(key)) return nullptr; - ECC::Scalar::Native nonce; - nonce.GenRandomNnz(); - Request* pReq = new Request; + m_lstRequests.push_back(pReq->m_ListNode); + pReq->m_Target.m_Value = trg; m_setTrg.insert(pReq->m_Target); - pReq->m_OwnAddr.m_Pk.FromSk(nonce); - pReq->m_OwnAddr.SetChannelFromPk(); + return pReq; + } - get_ParentObj().Listen(pReq->m_OwnAddr, nonce); + void Wallet::VoucherManager::Listen(Request& r) + { + r.m_OwnAddr.m_Pk.FromSk(r.m_sk); + r.m_OwnAddr.SetChannelFromPk(); - return pReq; + get_ParentObj().Listen(r.m_OwnAddr, r.m_sk); + } + + void Wallet::VoucherManager::EnsureRequest(const WalletID& trg) + { + Request* pReq = CreateIfNew(trg); + if (pReq) + { + pReq->m_sk.GenRandomNnz(); + Listen(*pReq); + + SendRequest(*pReq); + + if (IsFirstDue(*pReq)) + CheckTimer(); + } } void Wallet::Listen(const WalletID& wid, const ECC::Scalar::Native& sk, IHandler* pH) @@ -709,31 +750,151 @@ namespace beam::wallet } + bool Wallet::VoucherManager::IsFirstDue(const Request& r) const + { + return &m_lstRequests.front() == &r.m_ListNode; + } + + void Wallet::VoucherManager::CheckTimer() + { + if (m_pTimer) + m_pTimer->cancel(); + + while (!m_lstRequests.empty()) + { + auto& r = m_lstRequests.front().get_ParentObj(); + Timestamp dt_s = getTimestamp() - r.m_ListNode.m_ReqTime_s; // don't care if overflow (time change?), not a problem + + const uint32_t nMaxDuration_s = 10u * 3600; // 10 hours + + if (dt_s < nMaxDuration_s) + { + if (!m_pTimer) + m_pTimer = io::Timer::create(io::Reactor::get_Current()); + + auto dt_ms = static_cast((nMaxDuration_s - dt_s) * 1000u); + m_pTimer->start(dt_ms, false, [this]() { CheckTimer(); }); + break; + } + + // timed-out. Check if we still need it + auto vTxs = get_ParentObj().FindTxWaitingForVouchers(r.m_Target.m_Value); + if (vTxs.empty()) + Delete(r); + else + { + m_lstRequests.pop_front(); + m_lstRequests.push_back(r.m_ListNode); + SendRequest(r); + } + + } + } + void Wallet::VoucherManager::Delete(Request& r) { get_ParentObj().Unlisten(r.m_OwnAddr); m_setTrg.erase(Request::Target::Set::s_iterator_to(r.m_Target)); + m_lstRequests.erase(Request::ListNode::List::s_iterator_to(r.m_ListNode)); + delete &r; } void Wallet::VoucherManager::DeleteAll() { - while (!m_setTrg.empty()) - Delete(m_setTrg.begin()->get_ParentObj()); + while (!m_lstRequests.empty()) + Delete(m_lstRequests.front().get_ParentObj()); + } + + void Wallet::VoucherManager::SendRequest(Request& r) + { + assert(&m_lstRequests.back() == &r.m_ListNode); + r.m_ListNode.m_ReqTime_s = getTimestamp(); + + get_ParentObj().RequestVouchersFrom(r.m_Target.m_Value, r.m_OwnAddr, 30); } + ByteBuffer Wallet::VoucherManager::SaveState() const + { + ByteBuffer res; + if (!m_lstRequests.empty()) + { + Serializer ser; + + uint32_t ver = Ser::s_Ver; + ser + & ver + & m_lstRequests.size(); + + for (const auto& n : m_lstRequests) + { + auto& r = n.get_ParentObj(); + ser + & n.m_ReqTime_s + & r.m_Target.m_Value + & ECC::Scalar(r.m_sk); + } + + ser.swap_buf(res); + } + + return res; + } + + void Wallet::VoucherManager::LoadState(const Blob& blob) + { + if (!blob.n) + return; + + try + { + Deserializer der; + der.reset(blob.p, blob.n); + + uint32_t ver = 0; + der & ver; + if (Ser::s_Ver != ver) + return; // incompatible ver + + size_t n = 0; + der & n; + while (n--) + { + Timestamp ts_s = 0; + WalletID widTrg; + ECC::NoLeak sk; + + der + & ts_s + & widTrg + & sk.V; + + Request* pReq = CreateIfNew(widTrg); + if (pReq) + { + pReq->m_sk = sk.V; + Listen(*pReq); + + pReq->m_ListNode.m_ReqTime_s = ts_s; + } + } + } + catch (const std::exception& e) { + BEAM_LOG_WARNING() << "Voucher manager state deserialize error: " << e.what(); + } + } + + void LoadState(const Blob&); + + void Wallet::get_UniqueVoucher(const WalletID& peerID, const TxID&, boost::optional& res) { auto count = m_WalletDB->getVoucherCount(peerID); const size_t VoucherCountThreshold = 5; if (count < VoucherCountThreshold) - { - VoucherManager::Request* pReq = m_VoucherManager.CreateIfNew(peerID); - if (pReq) - RequestVouchersFrom(peerID, pReq->m_OwnAddr, 30); - } + m_VoucherManager.EnsureRequest(peerID); if (count > 0) res = m_WalletDB->grabVoucher(peerID); @@ -907,6 +1068,7 @@ namespace beam::wallet if (r.m_OwnAddr != ownAddr) return; + bool bWasAtFront = m_VoucherManager.IsFirstDue(r); m_VoucherManager.Delete(r); for (const auto& v : res) @@ -917,6 +1079,9 @@ namespace beam::wallet { UpdateTransaction(tx); } + + if (bWasAtFront) + m_VoucherManager.CheckTimer(); } void Wallet::OnWalletMessage(const WalletID& myID, const SetTxParameter& msg) diff --git a/wallet/core/wallet.h b/wallet/core/wallet.h index 54185c035..e5c7aa0cb 100644 --- a/wallet/core/wallet.h +++ b/wallet/core/wallet.h @@ -465,17 +465,39 @@ namespace beam::wallet IMPLEMENT_GET_PARENT_OBJ(Request, m_Target) } m_Target; + struct ListNode :public boost::intrusive::list_base_hook<> + { + typedef boost::intrusive::list List; + Timestamp m_ReqTime_s; + IMPLEMENT_GET_PARENT_OBJ(Request, m_ListNode) + } m_ListNode; + WalletID m_OwnAddr; + ECC::Scalar::Native m_sk; // not so secret }; Request::Target::Set m_setTrg; + Request::ListNode::List m_lstRequests; + + io::Timer::Ptr m_pTimer; Request* CreateIfNew(const WalletID& trg); void Delete(Request&); void DeleteAll(); + void Listen(Request&); + void SendRequest(Request&); + bool IsFirstDue(const Request&) const; + + void CheckTimer(); + void EnsureRequest(const WalletID& trg); + + ByteBuffer SaveState() const; + void LoadState(const Blob&); ~VoucherManager() { DeleteAll(); } + struct Ser; + IMPLEMENT_GET_PARENT_OBJ(Wallet, m_VoucherManager) } m_VoucherManager; From d6d1dda983febc8e362b8b6788c5728eb64d7fb2 Mon Sep 17 00:00:00 2001 From: valdok Date: Mon, 3 Jun 2024 01:42:21 +0300 Subject: [PATCH 04/34] wallet: misc --- bvm/ManagerStd.cpp | 5 +++++ bvm/ManagerStd.h | 2 +- wallet/cli/cli.cpp | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bvm/ManagerStd.cpp b/bvm/ManagerStd.cpp index 00b5ab7a5..62bb16a6b 100644 --- a/bvm/ManagerStd.cpp +++ b/bvm/ManagerStd.cpp @@ -512,6 +512,11 @@ namespace bvm2 { m_Pending.m_pBlocker = nullptr; } + void ManagerStd::Reset() + { + OnReset(); + } + void ManagerStd::StartRun(uint32_t iMethod) { OnReset(); diff --git a/bvm/ManagerStd.h b/bvm/ManagerStd.h index 1f1bf5304..4f7dc67b4 100644 --- a/bvm/ManagerStd.h +++ b/bvm/ManagerStd.h @@ -60,7 +60,6 @@ namespace beam::bvm2 { void Comm_OnNewMsg(const Blob&, Comm::Channel&); void Comm_OnNewMsg(); - protected: void SelectContext(bool bDependent, uint32_t nChargeNeeded) override; bool get_HdrAt(Block::SystemState::Full&) override; void VarsEnum(const Blob& kMin, const Blob& kMax, IReadVars::Ptr&) override; @@ -92,6 +91,7 @@ namespace beam::bvm2 { // results std::ostringstream m_Out; + void Reset(); void StartRun(uint32_t iMethod); }; } // namespace diff --git a/wallet/cli/cli.cpp b/wallet/cli/cli.cpp index be352460f..384a80410 100644 --- a/wallet/cli/cli.cpp +++ b/wallet/cli/cli.cpp @@ -2378,8 +2378,6 @@ namespace { wallet->EnableBodyRequests(true); } - wallet->ResumeAllTransactions(); - auto nnet = CreateNetwork(*wallet, vm); if (!nnet) { @@ -2390,6 +2388,8 @@ namespace wallet->AddMessageEndpoint(wnet); wallet->SetNodeEndpoint(nnet); + wallet->ResumeAllTransactions(); + #ifdef BEAM_ASSET_SWAP_SUPPORT assetsSwapHandler.init(wallet, walletDB, nnet, *wnet); #endif // BEAM_ASSET_SWAP_SUPPORT From 4ccfad67baaa08171e9b6d16ffa7264f7af0da28 Mon Sep 17 00:00:00 2001 From: valdok Date: Mon, 3 Jun 2024 01:43:16 +0300 Subject: [PATCH 05/34] wallet: added "widget" handler --- utility/cli/options.cpp | 1 + utility/cli/options.h | 1 + wallet/cli/cli.cpp | 88 ++++++++++++++++++++++++++--------------- wallet/core/wallet.cpp | 55 ++++++++++++++++++++++++++ wallet/core/wallet.h | 16 +++++++- 5 files changed, 129 insertions(+), 32 deletions(-) diff --git a/utility/cli/options.cpp b/utility/cli/options.cpp index 2d238fe5c..0c997b45c 100644 --- a/utility/cli/options.cpp +++ b/utility/cli/options.cpp @@ -308,6 +308,7 @@ namespace beam const char* SHADER_BYTECODE_CONTRACT = "shader_contract_file"; const char* SHADER_PRIVILEGE = "shader_privilege"; const char* SHADER_DEBUG = "shader_debug"; + const char* SHADER_WIDGET = "widget"; // IPFS #ifdef BEAM_IPFS_SUPPORT diff --git a/utility/cli/options.h b/utility/cli/options.h index 3c2da9d1c..7e75374c4 100644 --- a/utility/cli/options.h +++ b/utility/cli/options.h @@ -271,6 +271,7 @@ namespace beam extern const char* SHADER_BYTECODE_CONTRACT; extern const char* SHADER_PRIVILEGE; extern const char* SHADER_DEBUG; + extern const char* SHADER_WIDGET; // IPFS #ifdef BEAM_IPFS_SUPPORT diff --git a/wallet/cli/cli.cpp b/wallet/cli/cli.cpp index 384a80410..2c92f47e1 100644 --- a/wallet/cli/cli.cpp +++ b/wallet/cli/cli.cpp @@ -2446,6 +2446,35 @@ namespace }); } + void CompileShader(ByteBuffer& res, const char* sz, bvm2::Processor::Kind kind, Wasm::Compiler::DebugInfo* pDbgInfo = nullptr) + { + std::FStream fs; + fs.Open(sz, true, true); + + res.resize(static_cast(fs.get_Remaining())); + if (!res.empty()) + fs.read(&res.front(), res.size()); + + struct MyCompiler :public bvm2::Processor::Compiler + { + bool m_HaveMissing; + + void OnBindingMissing(const Wasm::Compiler::PerImport& x) override + { + if (!m_HaveMissing) + { + m_HaveMissing = true; + std::cout << "Shader uses newer API, some features may not work.\n"; + } + std::cout << "\t Missing " << x << std::endl; + } + }; + + MyCompiler c; + c.m_HaveMissing = false; + c.Compile(res, res, kind, pDbgInfo); + } + int ShaderInvoke(const po::variables_map& vm) { return DoWalletFunc(vm, [](const po::variables_map& vm, auto&& wallet, auto&& walletDB, auto& currentTxID) @@ -2479,35 +2508,6 @@ namespace if (m_Async) io::Reactor::get_Current().stop(); } - - static void Compile(ByteBuffer& res, const char* sz, Kind kind, Wasm::Compiler::DebugInfo* pDbgInfo = nullptr) - { - std::FStream fs; - fs.Open(sz, true, true); - - res.resize(static_cast(fs.get_Remaining())); - if (!res.empty()) - fs.read(&res.front(), res.size()); - - struct MyCompiler :public bvm2::Processor::Compiler - { - bool m_HaveMissing; - - void OnBindingMissing(const Wasm::Compiler::PerImport& x) override - { - if (!m_HaveMissing) - { - m_HaveMissing = true; - std::cout << "Shader uses newer API, some features may not work.\n"; - } - std::cout << "\t Missing " << x << std::endl; - } - }; - - MyCompiler c; - c.m_HaveMissing = false; - c.Compile(res, res, kind, pDbgInfo); - } }; MyManager man(*wallet); @@ -2517,11 +2517,11 @@ namespace if (sVal.empty()) throw std::runtime_error("shader file not specified"); - MyManager::Compile(man.m_BodyManager, sVal.c_str(), MyManager::Kind::Manager, man.m_Debug ? &man.m_DbgInfo : nullptr); + CompileShader(man.m_BodyManager, sVal.c_str(), MyManager::Kind::Manager, man.m_Debug ? &man.m_DbgInfo : nullptr); sVal = vm[cli::SHADER_BYTECODE_CONTRACT].as(); if (!sVal.empty()) - MyManager::Compile(man.m_BodyContract, sVal.c_str(), MyManager::Kind::Contract); + CompileShader(man.m_BodyContract, sVal.c_str(), MyManager::Kind::Contract); sVal = vm[cli::SHADER_ARGS].as(); // should be comma-separated list of name=val pairs if (!sVal.empty()) @@ -2624,6 +2624,31 @@ namespace }); } + int ShaderWidget(const po::variables_map& vm) + { + return DoWalletFunc(vm, [](const po::variables_map& vm, auto&& wallet, auto&& walletDB, auto& currentTxID) + { + auto sPath = vm[cli::SHADER_BYTECODE_APP].as(); + + ByteBuffer buf; + if (sPath.empty()) + std::cout << "Widget shader reset" << std::endl; + else + { + CompileShader(buf, sPath.c_str(), bvm2::Processor::Kind::Manager); + + bvm2::ShaderID sid; + bvm2::get_ShaderID(sid, buf); + + std::cout << "Widget sid: " << sid << std::endl; + } + + wallet->SetWidget(std::move(buf)); + return 0; + }); + } + + int Listen(const po::variables_map& vm) { return DoWalletFunc(vm, [](auto&& vm, auto&& wallet, auto&& walletDB, auto& currentTxID) @@ -3318,6 +3343,7 @@ int main(int argc, char* argv[]) {cli::HID_INSTALL, HidInstall, "Install Beam app on the attached HW wallet"}, {cli::SEND, Send, "send BEAM"}, {cli::SHADER_INVOKE, ShaderInvoke, "Invoke a wallet-side shader"}, + {cli::SHADER_WIDGET, ShaderWidget, "Set the wallet widget shader"}, {cli::LISTEN, Listen, "listen to the node (the wallet won't close till halted"}, {cli::TREASURY, HandleTreasury, "process treasury"}, {cli::INFO, ShowWalletInfo, "print information about wallet balance and transactions"}, diff --git a/wallet/core/wallet.cpp b/wallet/core/wallet.cpp index cf06d8d0f..c015a073a 100644 --- a/wallet/core/wallet.cpp +++ b/wallet/core/wallet.cpp @@ -334,6 +334,19 @@ namespace beam::wallet } } + const char Wallet::WidgetRunner::s_szVarName[] = "widget_shader"; + + void Wallet::SetWidget(ByteBuffer&& x) + { + if (x.empty()) + m_WalletDB->removeVarRaw(WidgetRunner::s_szVarName); + else + m_WalletDB->setVarRaw(WidgetRunner::s_szVarName, &x.front(), x.size()); + + m_WidgetRunner.m_BodyManager = std::move(x); + m_WidgetRunner.Reset(); + } + void Wallet::ResumeAllTransactions() { // restore being-received vouchers @@ -343,6 +356,15 @@ namespace beam::wallet m_VoucherManager.LoadState(buf); } + // widget + { + m_WidgetRunner.m_pPKdf = m_WalletDB->get_OwnerKdf(); + m_WidgetRunner.m_pHist = &m_WalletDB->get_History(); + m_WidgetRunner.m_pNetwork = m_NodeEndpoint; + + m_WalletDB->getBlob(WidgetRunner::s_szVarName, m_WidgetRunner.m_BodyManager); + } + auto func = [this](const auto& tx) { ResumeTransaction(tx); @@ -2124,6 +2146,17 @@ namespace beam::wallet CheckSyncDone(); ProcessStoredMessages(); + + ProcessWidget(); + } + + void Wallet::ProcessWidget() + { + if (m_WidgetRunner.m_BodyManager.empty()) + return; + + m_WidgetRunner.m_InvokeData.Reset(); + m_WidgetRunner.StartRun(0); } void Wallet::OnTipUnchanged() @@ -2135,6 +2168,28 @@ namespace beam::wallet CheckSyncDone(); ProcessStoredMessages(); + + ProcessWidget(); + } + + void Wallet::WidgetRunner::OnDone(const std::exception* /* pExc */) + { + } + + void Wallet::WidgetRunner::WriteStream(const Blob& b, uint32_t iStream) + { + const char* szPrefix = ""; + switch (iStream) + { + case Shaders::Stream::Out: szPrefix = "Widget out: "; break; + case Shaders::Stream::Error: szPrefix = "Widget error: "; break; + default: + szPrefix = "Widget "; + } + + std::cout << szPrefix; + std::cout.write((const char*) b.p, b.n); + std::cout << std::endl; } void Wallet::getUtxoProof(const Coin& coin) diff --git a/wallet/core/wallet.h b/wallet/core/wallet.h index e5c7aa0cb..3765fa544 100644 --- a/wallet/core/wallet.h +++ b/wallet/core/wallet.h @@ -19,6 +19,7 @@ #include "base_transaction.h" #include "core/fly_client.h" #include "node/processor.h" +#include "../../bvm/ManagerStd.h" namespace beam::wallet { @@ -163,6 +164,8 @@ namespace beam::wallet void ResumeAllTransactions(); void VisitActiveTransaction(const TxVisitor& visitor); + void SetWidget(ByteBuffer&&); + bool IsWalletInSync() const; Height get_TipHeight() const; @@ -241,12 +244,22 @@ namespace beam::wallet void OnDependentStateChanged() override; struct RequestHandler - : public proto::FlyClient::Request::IHandler + :public proto::FlyClient::Request::IHandler { virtual void OnComplete(Request&) override; IMPLEMENT_GET_PARENT_OBJ(Wallet, m_RequestHandler) } m_RequestHandler; + struct WidgetRunner + :public bvm2::ManagerStd + { + static const char s_szVarName[]; + void WriteStream(const Blob&, uint32_t iStream) override; + void OnDone(const std::exception* pExc) override; + + IMPLEMENT_GET_PARENT_OBJ(Wallet, m_WidgetRunner) + } m_WidgetRunner; + size_t SyncRemains() const; size_t GetSyncDone() const; size_t GetSyncTotal() const; @@ -283,6 +296,7 @@ namespace beam::wallet void MakeTransactionActive(BaseTransaction::Ptr tx); void ProcessStoredMessages(); + void ProcessWidget(); bool IsNodeInSync() const; void SendSpecialMsg(const WalletID& peerID, SetTxParameter&); From 5f968145ebb9ce3fbf3c71eea37eccf84eaa7c1c Mon Sep 17 00:00:00 2001 From: valdok Date: Mon, 3 Jun 2024 22:22:50 +0300 Subject: [PATCH 06/34] build fix --- bvm/ethash_service/shaders_ethash.h | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/bvm/ethash_service/shaders_ethash.h b/bvm/ethash_service/shaders_ethash.h index 8147e697f..ac115e543 100644 --- a/bvm/ethash_service/shaders_ethash.h +++ b/bvm/ethash_service/shaders_ethash.h @@ -14,28 +14,9 @@ #pragma once +#include "../bvm2.h" + namespace Shaders { - using PubKey = ECC::Point; - using Secp_point_data = ECC::Point; - using Secp_point_dataEx = ECC::Point::Storage; - using Secp_scalar_data = ECC::Scalar; - using AssetID = beam::Asset::ID; - using ContractID = ECC::uintBig; - using HashValue = ECC::uintBig; - using beam::Amount; - using beam::Height; - using beam::Timestamp; - using beam::HeightPos; - - template - inline void ConvertOrd(T& x) - { - if constexpr (bToShader) - x = beam::ByteOrder::to_le(x); - else - x = beam::ByteOrder::from_le(x); - } - #include "bvm/Shaders/Ethash.h" } \ No newline at end of file From e197fea59d668de636ed35b2ce06d24d0477eb65 Mon Sep 17 00:00:00 2001 From: valdok Date: Mon, 3 Jun 2024 22:23:13 +0300 Subject: [PATCH 07/34] wallet/cli: shutdown fix --- wallet/cli/cli.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wallet/cli/cli.cpp b/wallet/cli/cli.cpp index 2c92f47e1..906684978 100644 --- a/wallet/cli/cli.cpp +++ b/wallet/cli/cli.cpp @@ -2348,9 +2348,6 @@ namespace }; } -#ifdef BEAM_ASSET_SWAP_SUPPORT - AssetsSwapCliHandler assetsSwapHandler; -#endif // BEAM_ASSET_SWAP_SUPPORT auto wallet = std::make_shared(walletDB, std::move(txCompletedAction), Wallet::UpdateCompletedAction()); @@ -2391,6 +2388,7 @@ namespace wallet->ResumeAllTransactions(); #ifdef BEAM_ASSET_SWAP_SUPPORT + AssetsSwapCliHandler assetsSwapHandler; assetsSwapHandler.init(wallet, walletDB, nnet, *wnet); #endif // BEAM_ASSET_SWAP_SUPPORT From 85794c9669c9d78102532262c0372d6516925de3 Mon Sep 17 00:00:00 2001 From: valdok Date: Tue, 4 Jun 2024 12:42:25 +0300 Subject: [PATCH 08/34] bvm: Load/SaveVar for app shader --- bvm/bvm2.cpp | 82 ++++++++++++++++++++++++++++++++-------------- bvm/bvm2.h | 15 +++++---- bvm/bvm2_opcodes.h | 6 ++-- 3 files changed, 69 insertions(+), 34 deletions(-) diff --git a/bvm/bvm2.cpp b/bvm/bvm2.cpp index 4d565b57e..1ef8d8973 100644 --- a/bvm/bvm2.cpp +++ b/bvm/bvm2.cpp @@ -1342,11 +1342,17 @@ namespace bvm2 { } BVM_METHOD_HOST(LoadVar) { + Blob key(pKey, nKey); VarKey vk; - SetVarKeyFromShader(vk, nType, Blob(pKey, nKey), false); + + if (Kind::Contract == get_Kind()) + { + ((ProcessorPlusEnv_Contract*) this)->SetVarKeyFromShader(vk, nType, key, false); + key = vk.ToBlob(); + } Blob res; - LoadVar(vk.ToBlob(), res); + LoadVar(key, res); memcpy(pVal, res.p, std::min(nVal, res.n)); return res.n; @@ -1370,38 +1376,57 @@ namespace bvm2 { } BVM_METHOD_HOST(LoadVarEx) { - Exc::Test(IsPastFork_<4>()); + Blob key(pKey, nKey); + VarKey vk; - std::setmin(nKeyBufSize, Limits::VarKeySize); - Exc::Test(nKey <= nKeyBufSize); + bool bContract = (Kind::Contract == get_Kind()); + if (bContract) + { + Exc::Test(IsPastFork_<4>()); - VarKey vk; - SetVarKeyFromShader(vk, nType, Blob(pKey, nKey), false); + std::setmin(nKeyBufSize, Limits::VarKeySize); + Exc::Test(nKey <= nKeyBufSize); + + ((ProcessorPlusEnv_Contract*) this)->SetVarKeyFromShader(vk, nType, key, false); + key = vk.ToBlob(); + } - Blob key = vk.ToBlob(), res; + Blob res; LoadVarEx(key, res, !!(Shaders::KeySearchFlags::Exact & nSearchFlag), !!(Shaders::KeySearchFlags::Bigger & nSearchFlag)); - if (key.n > ContractID::nBytes) + if (bContract) { - // make sure we're still in the context of the contract vars - auto pK = (const uint8_t*) key.p; - const auto& cid = m_FarCalls.m_Stack.back().m_Cid; - - if (!memcmp(pK, cid.m_pData, cid.nBytes) && (nType == pK[cid.nBytes])) + // make sure it's still the current contract+type + bool bMatch = (key.n > ContractID::nBytes); + if (bMatch) { - nKey = key.n - (ContractID::nBytes + 1); - memcpy(pKey, pK + ContractID::nBytes + 1, std::min(nKey, nKeyBufSize)); + auto pK = (const uint8_t*)key.p; + const auto& cid = ((ProcessorPlusEnv_Contract*) this)->m_FarCalls.m_Stack.back().m_Cid; - memcpy(pVal, res.p, std::min(nVal, res.n)); - nVal = res.n; - return; + if (!memcmp(pK, cid.m_pData, cid.nBytes) && (nType == pK[cid.nBytes])) + { + // ok + key.n -= (ContractID::nBytes + 1); + ((const uint8_t*&) key.p) += (ContractID::nBytes + 1); + } + else + bMatch = false; + } + + if (!bMatch) + { + key.n = 0; + res.n = 0; } } - nKey = 0; - nVal = 0; + nKey = key.n; + memcpy(pKey, key.p, std::min(nKey, nKeyBufSize)); + + memcpy(pVal, res.p, std::min(nVal, res.n)); + nVal = res.n; } BVM_METHOD(SaveVar) @@ -1411,12 +1436,19 @@ namespace bvm2 { } BVM_METHOD_HOST(SaveVar) { - TestVarSize(nVal); - + Blob key(pKey, nKey); VarKey vk; - SetVarKeyFromShader(vk, nType, Blob(pKey, nKey), true); - return SaveVarInternal(vk.ToBlob(), Blob(pVal, nVal)); + if (Kind::Contract == get_Kind()) + { + ((ProcessorPlusEnv_Contract*) this)->TestVarSize(nVal); + ((ProcessorPlusEnv_Contract*) this)->TestCanWrite(); + + ((ProcessorPlusEnv_Contract*) this)->SetVarKeyFromShader(vk, nType, key, true); + key = vk.ToBlob(); + } + + return SaveVar(key, Blob(pVal, nVal)); } BVM_METHOD(EmitLog) diff --git a/bvm/bvm2.h b/bvm/bvm2.h index 58b091223..37a781acf 100644 --- a/bvm/bvm2.h +++ b/bvm/bvm2.h @@ -295,6 +295,13 @@ namespace bvm2 { return Rules::get().IsPastFork_(get_Height() + 1); } + virtual void LoadVar(const Blob&, Blob& res) { res.n = 0; } // res is temporary + virtual void LoadVarEx(Blob& key, Blob& res, bool bExact, bool bBigger) { + key.n = 0; + res.n = 0; + } + virtual uint32_t SaveVar(const Blob&, const Blob& val) { return 0; } + public: enum struct Kind { @@ -330,6 +337,8 @@ namespace bvm2 { { protected: + friend struct ProcessorPlusEnv; + void SetVarKey(VarKey&); void SetVarKey(VarKey&, uint8_t nTag, const Blob&); void SetVarKeyFromShader(VarKey&, uint8_t nTag, const Blob&, bool bW); @@ -396,14 +405,8 @@ namespace bvm2 { virtual void DischargeUnits(uint32_t size) override; virtual uint32_t get_WasmVersion() override; - virtual void LoadVar(const Blob&, Blob& res) { res.n = 0; } // res is temporary - virtual uint32_t SaveVar(const Blob&, const Blob& val) { return 0; } virtual uint32_t OnLog(const Blob&, const Blob& val) { return 0; } - virtual void LoadVarEx(Blob& key, Blob& res, bool bExact, bool bBigger) { - key.n = 0; - res.n = 0; - } virtual Asset::ID AssetCreate(const Asset::Metadata&, const PeerID&, Amount& valDeposit) { return 0; } virtual bool AssetEmit(Asset::ID, const PeerID&, AmountSigned) { return false; } diff --git a/bvm/bvm2_opcodes.h b/bvm/bvm2_opcodes.h index 951a69a8a..70c765cc3 100644 --- a/bvm/bvm2_opcodes.h +++ b/bvm/bvm2_opcodes.h @@ -512,6 +512,9 @@ macro(0x19, void , StackFree) \ macro(0x1A, void* , Heap_Alloc) \ macro(0x1B, void , Heap_Free) \ + macro(0x20, uint32_t , LoadVar) \ + macro(0x21, uint32_t , SaveVar) \ + macro(0x27, void , LoadVarEx) \ macro(0x28, void , Halt) \ macro(0x2A, uint32_t , get_AssetInfo) \ macro(0x2B, void , HashWrite) \ @@ -550,14 +553,11 @@ macro(0xB0, uint8_t , VerifyBeamHashIII) \ #define BVMOpsAll_Contract(macro) \ - macro(0x20, uint32_t , LoadVar) \ - macro(0x21, uint32_t , SaveVar) \ macro(0x22, uint32_t , EmitLog) \ macro(0x23, void , CallFar) \ macro(0x24, uint32_t , get_CallDepth) \ macro(0x25, void , get_CallerCid) \ macro(0x26, void , UpdateShader) \ - macro(0x27, void , LoadVarEx) \ macro(0x29, void , AddSig) \ macro(0x30, void , FundsLock) \ macro(0x31, void , FundsUnlock) \ From 1e04404a921bc99374dbeb48ac2ca03168ef964e Mon Sep 17 00:00:00 2001 From: valdok Date: Tue, 4 Jun 2024 16:02:01 +0300 Subject: [PATCH 09/34] wallet: implemented Load/SaveVar for app shader via WalletDB --- wallet/core/contracts/shaders_manager.cpp | 20 +++++++ wallet/core/contracts/shaders_manager.h | 7 ++- wallet/core/wallet.cpp | 44 ++++++++++----- wallet/core/wallet.h | 14 ++--- wallet/core/wallet_db.cpp | 67 ++++++++++++++++++++++- wallet/core/wallet_db.h | 9 +++ 6 files changed, 135 insertions(+), 26 deletions(-) diff --git a/wallet/core/contracts/shaders_manager.cpp b/wallet/core/contracts/shaders_manager.cpp index 608ec4da1..5d615aa6c 100644 --- a/wallet/core/contracts/shaders_manager.cpp +++ b/wallet/core/contracts/shaders_manager.cpp @@ -147,6 +147,26 @@ namespace beam::wallet { std::cout << std::endl; } + void ManagerStdInWallet::LoadVar(const Blob& key, Blob& res) + { + if (!m_Wallet.get_WalletDB()->get_AppData(key, m_LastVar)) + m_LastVar.clear(); + + res = m_LastVar; + } + + void ManagerStdInWallet::LoadVarEx(Blob& key, Blob& res, bool /* bExact */, bool /* bBigger */) + { + // TODO + LoadVar(key, res); + } + + uint32_t ManagerStdInWallet::SaveVar(const Blob& key, const Blob& val) + { + m_Wallet.get_WalletDB()->set_AppData(key, val.n ? &val : nullptr); + return 0; + } + bvm2::ContractInvokeData ManagerStdInWallet::get_InvokeData() { bvm2::ContractInvokeData res; diff --git a/wallet/core/contracts/shaders_manager.h b/wallet/core/contracts/shaders_manager.h index 94f21fe47..a06f8207e 100644 --- a/wallet/core/contracts/shaders_manager.h +++ b/wallet/core/contracts/shaders_manager.h @@ -32,7 +32,8 @@ namespace beam::wallet { protected: Wallet& m_Wallet; - uint32_t m_Privilege; + uint32_t m_Privilege = 0; + ByteBuffer m_LastVar; struct SlotName; struct Channel; @@ -45,6 +46,10 @@ namespace beam::wallet { void Comm_CreateListener(Comm::Channel::Ptr&, const ECC::Hash::Value&) override; void Comm_Send(const ECC::Point&, const Blob&) override; void WriteStream(const Blob&, uint32_t iStream) override; + + void LoadVar(const Blob&, Blob& res) override; + void LoadVarEx(Blob& key, Blob& res, bool bExact, bool bBigger) override; + uint32_t SaveVar(const Blob&, const Blob& val) override; }; class ShadersManager diff --git a/wallet/core/wallet.cpp b/wallet/core/wallet.cpp index c015a073a..f5090fe61 100644 --- a/wallet/core/wallet.cpp +++ b/wallet/core/wallet.cpp @@ -25,6 +25,7 @@ #include "contract_transaction.h" #include "strings_resources.h" #include "assets_utils.h" +#include "contracts/shaders_manager.h" #include #include @@ -334,6 +335,17 @@ namespace beam::wallet } } + struct Wallet::WidgetRunner + :public ManagerStdInWallet + { + using ManagerStdInWallet::ManagerStdInWallet; + + static const char s_szVarName[]; + void WriteStream(const Blob&, uint32_t iStream) override; + void OnDone(const std::exception* pExc) override; + + }; + const char Wallet::WidgetRunner::s_szVarName[] = "widget_shader"; void Wallet::SetWidget(ByteBuffer&& x) @@ -343,8 +355,15 @@ namespace beam::wallet else m_WalletDB->setVarRaw(WidgetRunner::s_szVarName, &x.front(), x.size()); - m_WidgetRunner.m_BodyManager = std::move(x); - m_WidgetRunner.Reset(); + InitWidgetRunner(); + m_pWidgetRunner->m_BodyManager = std::move(x); + m_pWidgetRunner->Reset(); + } + + void Wallet::InitWidgetRunner() + { + if (!m_pWidgetRunner) + m_pWidgetRunner = std::make_unique(*this); } void Wallet::ResumeAllTransactions() @@ -356,14 +375,9 @@ namespace beam::wallet m_VoucherManager.LoadState(buf); } - // widget - { - m_WidgetRunner.m_pPKdf = m_WalletDB->get_OwnerKdf(); - m_WidgetRunner.m_pHist = &m_WalletDB->get_History(); - m_WidgetRunner.m_pNetwork = m_NodeEndpoint; - - m_WalletDB->getBlob(WidgetRunner::s_szVarName, m_WidgetRunner.m_BodyManager); - } + InitWidgetRunner(); + m_WalletDB->getBlob(WidgetRunner::s_szVarName, m_pWidgetRunner->m_BodyManager); + m_pWidgetRunner->Reset(); auto func = [this](const auto& tx) { @@ -2152,11 +2166,15 @@ namespace beam::wallet void Wallet::ProcessWidget() { - if (m_WidgetRunner.m_BodyManager.empty()) + if (!m_pWidgetRunner) + return; + + auto& w = *m_pWidgetRunner; + if (w.m_BodyManager.empty()) return; - m_WidgetRunner.m_InvokeData.Reset(); - m_WidgetRunner.StartRun(0); + w.m_InvokeData.Reset(); + w.StartRun(0); } void Wallet::OnTipUnchanged() diff --git a/wallet/core/wallet.h b/wallet/core/wallet.h index 3765fa544..7a1e3623d 100644 --- a/wallet/core/wallet.h +++ b/wallet/core/wallet.h @@ -19,7 +19,7 @@ #include "base_transaction.h" #include "core/fly_client.h" #include "node/processor.h" -#include "../../bvm/ManagerStd.h" +//#include "contracts/shaders_manager.h" namespace beam::wallet { @@ -250,15 +250,9 @@ namespace beam::wallet IMPLEMENT_GET_PARENT_OBJ(Wallet, m_RequestHandler) } m_RequestHandler; - struct WidgetRunner - :public bvm2::ManagerStd - { - static const char s_szVarName[]; - void WriteStream(const Blob&, uint32_t iStream) override; - void OnDone(const std::exception* pExc) override; - - IMPLEMENT_GET_PARENT_OBJ(Wallet, m_WidgetRunner) - } m_WidgetRunner; + struct WidgetRunner; + std::unique_ptr m_pWidgetRunner; + void InitWidgetRunner(); size_t SyncRemains() const; size_t GetSyncDone() const; diff --git a/wallet/core/wallet_db.cpp b/wallet/core/wallet_db.cpp index a6a7fbf0d..2e9c33e2b 100644 --- a/wallet/core/wallet_db.cpp +++ b/wallet/core/wallet_db.cpp @@ -112,6 +112,10 @@ namespace fs = std::filesystem; #define IM_NAME "IM" #define LAST_READ_IM_ID "LastReadIMId" +#define TblAppData "appdata" +#define TblAppData_Key "key" +#define TblAppData_Val "val" + #define ENUM_VARIABLES_FIELDS(each, sep, obj) \ each(name, name, TEXT UNIQUE, obj) sep \ each(value, value, BLOB, obj) @@ -1020,7 +1024,8 @@ namespace beam::wallet const uint8_t kDefaultMaxPrivacyLockTimeLimitHours = 72; const int BusyTimeoutMs = 5000; - const int DbVersion = 37; + const int DbVersion = 38; + const int DbVersion37 = 37; const int DbVersion36 = 36; const int DbVersion35 = 35; const int DbVersion34 = 34; @@ -1252,6 +1257,13 @@ namespace beam::wallet throwIfError(ret, db); } + void CreateAppDataTable(sqlite3* db) + { + const char* req = "CREATE TABLE " TblAppData " (" TblAppData_Key " BLOB NOT NULL PRIMARY KEY, " TblAppData_Val " BLOB NOT NULL );"; + int ret = sqlite3_exec(db, req, nullptr, nullptr, nullptr); + throwIfError(ret, db); + } + void CreateWalletMessageTable(sqlite3* db) { { @@ -1920,6 +1932,7 @@ namespace beam::wallet CreateVerificationTable(db); CreateDexOffersTable(db); CreateIMTables(db); + CreateAppDataTable(db); } std::shared_ptr WalletDB::initBase(const string& path, const SecString& password, bool separateDBForPrivateData) @@ -2488,10 +2501,16 @@ namespace beam::wallet CreateIMTables(walletDB->_db); // no break + case DbVersion37: + BEAM_LOG_INFO() << "Converting DB from format 37..."; + + CreateTxParamsIndex(walletDB->_db); + CreateAppDataTable(walletDB->_db); + storage::setVar(*walletDB, Version, DbVersion); + // no break case DbVersion: - CreateTxParamsIndex(walletDB->_db); // drop private variables from public database for cold wallet if (separateDBForPrivateData && !DropPrivateVariablesFromPublicDatabase(*walletDB)) { @@ -6059,6 +6078,50 @@ namespace beam::wallet stm.step(); } + bool WalletDB::get_AppData(const Blob& key, ByteBuffer& res) + { + const char* req = "SELECT " TblAppData_Val " FROM " TblAppData " WHERE " TblAppData_Key "=?"; + + sqlite::Statement stm(this, req); + stm.bind(1, key); + + if (!stm.step()) + return false; + + stm.get(0, res); + return true; + + } + + void WalletDB::set_AppData(const Blob& key, const Blob* pRes) + { + if (pRes) + { + const char* req = "INSERT or REPLACE INTO " TblAppData " (" TblAppData_Key "," TblAppData_Val ") VALUES(?1, ?2);"; + + sqlite::Statement stm(this, req); + + stm.bind(1, key); + stm.bind(2, *pRes); + + stm.step(); + } + else + { + const char* req = "DELETE FROM " TblAppData " WHERE " TblAppData_Key "=?"; + sqlite::Statement stm(this, req); + stm.bind(1, key); + stm.step(); + } + } + + void WalletDB::ClearAppData() + { + const char* req = "DELETE FROM " TblAppData; + sqlite::Statement stm(this, req); + stm.step(); + } + namespace storage { bool getTxParameter(const IWalletDB& db, const TxID& txID, SubTxID subTxID, TxParameterID paramID, ECC::Scalar::Native& value) diff --git a/wallet/core/wallet_db.h b/wallet/core/wallet_db.h index d09985072..e8cf8a3b0 100644 --- a/wallet/core/wallet_db.h +++ b/wallet/core/wallet_db.h @@ -648,6 +648,11 @@ namespace beam::wallet virtual void visitEvents(Height min, const Blob& key, std::function&& func) const = 0; virtual void visitEvents(Height min, std::function&& func) const = 0; + // app data + virtual bool get_AppData(const Blob&, ByteBuffer&) { return false; } + virtual void set_AppData(const Blob&, const Blob*) {} + virtual void ClearAppData() {} + private: bool get_CommitmentSafe(ECC::Point& comm, const CoinID&, IPrivateKeyKeeper2*); }; @@ -822,6 +827,10 @@ namespace beam::wallet void visitEvents(Height min, const Blob& key, std::function&& func) const override; void visitEvents(Height min, std::function&& func) const override; + bool get_AppData(const Blob&, ByteBuffer&) override; + void set_AppData(const Blob&, const Blob*) override; + void ClearAppData() override; + private: static std::shared_ptr initBase(const std::string& path, const SecString& password, bool separateDBForPrivateData); From f73d38a328bacb53707c94fe004ae27df1f8641b Mon Sep 17 00:00:00 2001 From: valdok Date: Wed, 5 Jun 2024 12:16:14 +0300 Subject: [PATCH 10/34] bvm: misc --- bvm/bvm2.cpp | 15 +++++++++++++++ bvm/wasm_interpreter.h | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/bvm/bvm2.cpp b/bvm/bvm2.cpp index 1ef8d8973..cf8d2aba0 100644 --- a/bvm/bvm2.cpp +++ b/bvm/bvm2.cpp @@ -1350,6 +1350,11 @@ namespace bvm2 { ((ProcessorPlusEnv_Contract*) this)->SetVarKeyFromShader(vk, nType, key, false); key = vk.ToBlob(); } + else + { + // impose the same restriction for apps + Exc::Test(key.n <= Limits::VarKeySize); + } Blob res; LoadVar(key, res); @@ -1390,6 +1395,11 @@ namespace bvm2 { ((ProcessorPlusEnv_Contract*) this)->SetVarKeyFromShader(vk, nType, key, false); key = vk.ToBlob(); } + else + { + // impose the same restriction for apps + Exc::Test(key.n <= Limits::VarKeySize); + } Blob res; LoadVarEx(key, res, @@ -1447,6 +1457,11 @@ namespace bvm2 { ((ProcessorPlusEnv_Contract*) this)->SetVarKeyFromShader(vk, nType, key, true); key = vk.ToBlob(); } + else + { + Exc::Test(key.n <= Limits::VarKeySize); + Exc::Test(nVal <= Limits::VarSize_4); + } return SaveVar(key, Blob(pVal, nVal)); } diff --git a/bvm/wasm_interpreter.h b/bvm/wasm_interpreter.h index 943b880e4..b7f733380 100644 --- a/bvm/wasm_interpreter.h +++ b/bvm/wasm_interpreter.h @@ -385,7 +385,7 @@ namespace Wasm { #endif // WASM_INTERPRETER_DEBUG Processor() - :m_Instruction(Reader::Mode::Emulate_x86) + :m_Instruction(Reader::Mode::Standard) { } From ad1fdfc749d8cb1d00b81c4943ace6704c6487c6 Mon Sep 17 00:00:00 2001 From: valdok Date: Wed, 5 Jun 2024 12:17:21 +0300 Subject: [PATCH 11/34] wallet: supporting multiple widgets --- utility/cli/options.cpp | 2 + utility/cli/options.h | 1 + wallet/cli/cli.cpp | 12 +- wallet/core/contracts/shaders_manager.cpp | 9 +- wallet/core/contracts/shaders_manager.h | 2 + wallet/core/wallet.cpp | 149 ++++++++++++++++++---- wallet/core/wallet.h | 2 +- wallet/core/wallet_db.cpp | 30 +++-- wallet/core/wallet_db.h | 12 +- 9 files changed, 172 insertions(+), 47 deletions(-) diff --git a/utility/cli/options.cpp b/utility/cli/options.cpp index 0c997b45c..e978f2200 100644 --- a/utility/cli/options.cpp +++ b/utility/cli/options.cpp @@ -309,6 +309,7 @@ namespace beam const char* SHADER_PRIVILEGE = "shader_privilege"; const char* SHADER_DEBUG = "shader_debug"; const char* SHADER_WIDGET = "widget"; + const char* SHADER_WIDGET_NAME = "name"; // IPFS #ifdef BEAM_IPFS_SUPPORT @@ -476,6 +477,7 @@ namespace beam (cli::SHADER_DEBUG, po::value()->default_value(false), "shader debug") (cli::SHADER_BYTECODE_APP, po::value()->default_value(""), "Path to the app shader file") (cli::SHADER_BYTECODE_CONTRACT, po::value()->default_value(""), "Path to the shader file for the contract (if the contract is being-created)") + (cli::SHADER_WIDGET_NAME, po::value(), "Name of the widget") (cli::MAX_PRIVACY_ADDRESS, po::bool_switch()->default_value(false), "generate max privacy transaction address") (cli::OFFLINE_COUNT, po::value>(), "generate offline transaction address with given number of payments") (cli::PUBLIC_OFFLINE, po::bool_switch()->default_value(false), "generate an offline public address for donates (less secure, but more convenient)") diff --git a/utility/cli/options.h b/utility/cli/options.h index 7e75374c4..ce00295c9 100644 --- a/utility/cli/options.h +++ b/utility/cli/options.h @@ -272,6 +272,7 @@ namespace beam extern const char* SHADER_PRIVILEGE; extern const char* SHADER_DEBUG; extern const char* SHADER_WIDGET; + extern const char* SHADER_WIDGET_NAME; // IPFS #ifdef BEAM_IPFS_SUPPORT diff --git a/wallet/cli/cli.cpp b/wallet/cli/cli.cpp index 906684978..77045dcde 100644 --- a/wallet/cli/cli.cpp +++ b/wallet/cli/cli.cpp @@ -2626,11 +2626,17 @@ namespace { return DoWalletFunc(vm, [](const po::variables_map& vm, auto&& wallet, auto&& walletDB, auto& currentTxID) { + auto sName = vm[cli::SHADER_WIDGET_NAME].as(); + if (sName.empty()) + { + std::cout << "widget name should not be empty"; + return 1; + } auto sPath = vm[cli::SHADER_BYTECODE_APP].as(); ByteBuffer buf; if (sPath.empty()) - std::cout << "Widget shader reset" << std::endl; + std::cout << "Widget " << sName << " removed" << std::endl; else { CompileShader(buf, sPath.c_str(), bvm2::Processor::Kind::Manager); @@ -2638,10 +2644,10 @@ namespace bvm2::ShaderID sid; bvm2::get_ShaderID(sid, buf); - std::cout << "Widget sid: " << sid << std::endl; + std::cout << "Widget " << sName << " sid: " << sid << std::endl; } - wallet->SetWidget(std::move(buf)); + wallet->SetWidget(std::move(sName), std::move(buf)); return 0; }); } diff --git a/wallet/core/contracts/shaders_manager.cpp b/wallet/core/contracts/shaders_manager.cpp index 5d615aa6c..02ded61e8 100644 --- a/wallet/core/contracts/shaders_manager.cpp +++ b/wallet/core/contracts/shaders_manager.cpp @@ -147,9 +147,14 @@ namespace beam::wallet { std::cout << std::endl; } + Blob ManagerStdInWallet::get_StoreName() + { + return Blob(); // empty + } + void ManagerStdInWallet::LoadVar(const Blob& key, Blob& res) { - if (!m_Wallet.get_WalletDB()->get_AppData(key, m_LastVar)) + if (!m_Wallet.get_WalletDB()->get_AppData(get_StoreName(), key, m_LastVar)) m_LastVar.clear(); res = m_LastVar; @@ -163,7 +168,7 @@ namespace beam::wallet { uint32_t ManagerStdInWallet::SaveVar(const Blob& key, const Blob& val) { - m_Wallet.get_WalletDB()->set_AppData(key, val.n ? &val : nullptr); + m_Wallet.get_WalletDB()->set_AppData(get_StoreName(), key, val.n ? &val : nullptr); return 0; } diff --git a/wallet/core/contracts/shaders_manager.h b/wallet/core/contracts/shaders_manager.h index a06f8207e..f7648aba8 100644 --- a/wallet/core/contracts/shaders_manager.h +++ b/wallet/core/contracts/shaders_manager.h @@ -50,6 +50,8 @@ namespace beam::wallet { void LoadVar(const Blob&, Blob& res) override; void LoadVarEx(Blob& key, Blob& res, bool bExact, bool bBigger) override; uint32_t SaveVar(const Blob&, const Blob& val) override; + + virtual Blob get_StoreName(); }; class ShadersManager diff --git a/wallet/core/wallet.cpp b/wallet/core/wallet.cpp index f5090fe61..830eca000 100644 --- a/wallet/core/wallet.cpp +++ b/wallet/core/wallet.cpp @@ -336,34 +336,140 @@ namespace beam::wallet } struct Wallet::WidgetRunner - :public ManagerStdInWallet { - using ManagerStdInWallet::ManagerStdInWallet; - static const char s_szVarName[]; - void WriteStream(const Blob&, uint32_t iStream) override; - void OnDone(const std::exception* pExc) override; + struct Entry + :public ManagerStdInWallet + ,public intrusive::set_base_hook + { + using ManagerStdInWallet::ManagerStdInWallet; + + void WriteStream(const Blob&, uint32_t iStream) override; + void OnDone(const std::exception* pExc) override; + + Blob get_StoreName() override { return Blob(m_Key.c_str(), static_cast(m_Key.size())); } + }; + + intrusive::multiset_autoclear m_Set; + + Entry* Get(const std::string& sName) + { + auto it = m_Set.find(sName, Entry::Comparator()); + return (m_Set.end() != it) ? &(*it) : nullptr; + } + + Entry* GetOrCreate(Wallet& w, std::string&& sName) + { + auto pVal = Get(sName); + if (pVal) + return pVal; + + ByteBuffer buf; + w.m_WalletDB->get_AppData(Blob(sName.c_str(), static_cast(sName.size())), Blob(), buf); + if (buf.empty()) + return nullptr; // no bytecode + + pVal = new Entry(w); + pVal->m_Key = std::move(sName); + m_Set.insert(*pVal); + + pVal->m_BodyManager = std::move(buf); + + return pVal; + } + + void Save(Wallet& w) + { + if (m_Set.empty()) + w.m_WalletDB->removeVarRaw(s_szVarName); + else + { + Serializer ser; + ser& m_Set.size(); + for (const auto& x : m_Set) + ser & x.m_Key; + + auto res = ser.buffer(); + + w.m_WalletDB->setVarRaw(s_szVarName, res.first, res.second); + } + + } + + void Load(Wallet& w) + { + try { + + ByteBuffer buf; + w.m_WalletDB->getBlob(s_szVarName, buf); + + if (!buf.empty()) + { + Deserializer der; + der.reset(buf); + + size_t n = 0; + der & n; + + while (n--) + { + std::string sName; + der & sName; + if (!sName.empty()) + GetOrCreate(w, std::move(sName)); + } + } + + } + catch (const std::exception&) { + // ignore + } + } }; const char Wallet::WidgetRunner::s_szVarName[] = "widget_shader"; - void Wallet::SetWidget(ByteBuffer&& x) + void Wallet::SetWidget(std::string&& sName, ByteBuffer&& x) { + if (sName.empty()) + return; // name shouldn't be empty + + InitWidgetRunner(); + auto& w = *m_pWidgetRunner; + + size_t n0 = w.m_Set.size(); + + auto pVal = w.Get(sName); + if (pVal) + w.m_Set.Delete(*pVal); + if (x.empty()) + { + m_WalletDB->ClearAppData(Blob(sName.c_str(), static_cast(sName.size()))); m_WalletDB->removeVarRaw(WidgetRunner::s_szVarName); + } else + { + Blob buf(x); + m_WalletDB->set_AppData(Blob(sName.c_str(), static_cast(sName.size())), Blob(), &buf); + m_WalletDB->setVarRaw(WidgetRunner::s_szVarName, &x.front(), x.size()); - InitWidgetRunner(); - m_pWidgetRunner->m_BodyManager = std::move(x); - m_pWidgetRunner->Reset(); + w.GetOrCreate(*this, std::move(sName)); + } + + if (w.m_Set.size() != n0) + w.Save(*this); } void Wallet::InitWidgetRunner() { if (!m_pWidgetRunner) - m_pWidgetRunner = std::make_unique(*this); + { + m_pWidgetRunner = std::make_unique(); + m_pWidgetRunner->Load(*this); + } } void Wallet::ResumeAllTransactions() @@ -376,8 +482,6 @@ namespace beam::wallet } InitWidgetRunner(); - m_WalletDB->getBlob(WidgetRunner::s_szVarName, m_pWidgetRunner->m_BodyManager); - m_pWidgetRunner->Reset(); auto func = [this](const auto& tx) { @@ -2170,11 +2274,12 @@ namespace beam::wallet return; auto& w = *m_pWidgetRunner; - if (w.m_BodyManager.empty()) - return; - w.m_InvokeData.Reset(); - w.StartRun(0); + for (auto& x : w.m_Set) + { + x.m_InvokeData.Reset(); + x.StartRun(0); + } } void Wallet::OnTipUnchanged() @@ -2190,22 +2295,20 @@ namespace beam::wallet ProcessWidget(); } - void Wallet::WidgetRunner::OnDone(const std::exception* /* pExc */) + void Wallet::WidgetRunner::Entry::OnDone(const std::exception* /* pExc */) { } - void Wallet::WidgetRunner::WriteStream(const Blob& b, uint32_t iStream) + void Wallet::WidgetRunner::Entry::WriteStream(const Blob& b, uint32_t iStream) { const char* szPrefix = ""; switch (iStream) { - case Shaders::Stream::Out: szPrefix = "Widget out: "; break; - case Shaders::Stream::Error: szPrefix = "Widget error: "; break; - default: - szPrefix = "Widget "; + case Shaders::Stream::Out: szPrefix = "out"; break; + case Shaders::Stream::Error: szPrefix = "error"; break; } - std::cout << szPrefix; + std::cout << "Widget " << m_Key << " " << szPrefix << ": "; std::cout.write((const char*) b.p, b.n); std::cout << std::endl; } diff --git a/wallet/core/wallet.h b/wallet/core/wallet.h index 7a1e3623d..bb0490557 100644 --- a/wallet/core/wallet.h +++ b/wallet/core/wallet.h @@ -164,7 +164,7 @@ namespace beam::wallet void ResumeAllTransactions(); void VisitActiveTransaction(const TxVisitor& visitor); - void SetWidget(ByteBuffer&&); + void SetWidget(std::string&&, ByteBuffer&&); bool IsWalletInSync() const; Height get_TipHeight() const; diff --git a/wallet/core/wallet_db.cpp b/wallet/core/wallet_db.cpp index 2e9c33e2b..88f24f337 100644 --- a/wallet/core/wallet_db.cpp +++ b/wallet/core/wallet_db.cpp @@ -113,6 +113,7 @@ namespace fs = std::filesystem; #define LAST_READ_IM_ID "LastReadIMId" #define TblAppData "appdata" +#define TblAppData_Name "name" #define TblAppData_Key "key" #define TblAppData_Val "val" @@ -1259,7 +1260,8 @@ namespace beam::wallet void CreateAppDataTable(sqlite3* db) { - const char* req = "CREATE TABLE " TblAppData " (" TblAppData_Key " BLOB NOT NULL PRIMARY KEY, " TblAppData_Val " BLOB NOT NULL );"; + const char* req = "CREATE TABLE " TblAppData " (" TblAppData_Name " BLOB NOT NULL, " TblAppData_Key " BLOB NOT NULL, " TblAppData_Val " BLOB NOT NULL);" + "CREATE UNIQUE INDEX " TblAppData "_Idx ON " TblAppData "(" TblAppData_Name "," TblAppData_Key ");"; int ret = sqlite3_exec(db, req, nullptr, nullptr, nullptr); throwIfError(ret, db); } @@ -6078,12 +6080,13 @@ namespace beam::wallet stm.step(); } - bool WalletDB::get_AppData(const Blob& key, ByteBuffer& res) + bool WalletDB::get_AppData(const Blob& name, const Blob& key, ByteBuffer& res) { - const char* req = "SELECT " TblAppData_Val " FROM " TblAppData " WHERE " TblAppData_Key "=?"; + const char* req = "SELECT " TblAppData_Val " FROM " TblAppData " WHERE " TblAppData_Name "=? AND " TblAppData_Key "=?"; sqlite::Statement stm(this, req); - stm.bind(1, key); + stm.bind(1, name); + stm.bind(2, key); if (!stm.step()) return false; @@ -6093,32 +6096,35 @@ namespace beam::wallet } - void WalletDB::set_AppData(const Blob& key, const Blob* pRes) + void WalletDB::set_AppData(const Blob& name, const Blob& key, const Blob* pRes) { if (pRes) { - const char* req = "INSERT or REPLACE INTO " TblAppData " (" TblAppData_Key "," TblAppData_Val ") VALUES(?1, ?2);"; + const char* req = "INSERT or REPLACE INTO " TblAppData " (" TblAppData_Name "," TblAppData_Key "," TblAppData_Val ") VALUES(?,?,?);"; sqlite::Statement stm(this, req); - stm.bind(1, key); - stm.bind(2, *pRes); + stm.bind(1, name); + stm.bind(2, key); + stm.bind(3, *pRes); stm.step(); } else { - const char* req = "DELETE FROM " TblAppData " WHERE " TblAppData_Key "=?"; + const char* req = "DELETE FROM " TblAppData " WHERE " TblAppData_Name "=? AND " TblAppData_Key "=?"; sqlite::Statement stm(this, req); - stm.bind(1, key); + stm.bind(1, name); + stm.bind(2, key); stm.step(); } } - void WalletDB::ClearAppData() + void WalletDB::ClearAppData(const Blob& name) { - const char* req = "DELETE FROM " TblAppData; + const char* req = "DELETE FROM " TblAppData " WHERE " TblAppData_Name "=?"; sqlite::Statement stm(this, req); + stm.bind(1, name); stm.step(); } diff --git a/wallet/core/wallet_db.h b/wallet/core/wallet_db.h index e8cf8a3b0..58188888c 100644 --- a/wallet/core/wallet_db.h +++ b/wallet/core/wallet_db.h @@ -649,9 +649,9 @@ namespace beam::wallet virtual void visitEvents(Height min, std::function&& func) const = 0; // app data - virtual bool get_AppData(const Blob&, ByteBuffer&) { return false; } - virtual void set_AppData(const Blob&, const Blob*) {} - virtual void ClearAppData() {} + virtual bool get_AppData(const Blob& name, const Blob&, ByteBuffer&) { return false; } + virtual void set_AppData(const Blob& name, const Blob&, const Blob*) {} + virtual void ClearAppData(const Blob& name) {} private: bool get_CommitmentSafe(ECC::Point& comm, const CoinID&, IPrivateKeyKeeper2*); @@ -827,9 +827,9 @@ namespace beam::wallet void visitEvents(Height min, const Blob& key, std::function&& func) const override; void visitEvents(Height min, std::function&& func) const override; - bool get_AppData(const Blob&, ByteBuffer&) override; - void set_AppData(const Blob&, const Blob*) override; - void ClearAppData() override; + bool get_AppData(const Blob& name, const Blob&, ByteBuffer&) override; + void set_AppData(const Blob& name, const Blob&, const Blob*) override; + void ClearAppData(const Blob& name) override; private: static std::shared_ptr initBase(const std::string& path, const SecString& password, bool separateDBForPrivateData); From eed10b3db39700d62b57e068b311a87df45a1341 Mon Sep 17 00:00:00 2001 From: valdok Date: Wed, 5 Jun 2024 12:33:39 +0300 Subject: [PATCH 12/34] wallet: widgets fix --- wallet/core/wallet.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/wallet/core/wallet.cpp b/wallet/core/wallet.cpp index 830eca000..b313353df 100644 --- a/wallet/core/wallet.cpp +++ b/wallet/core/wallet.cpp @@ -447,15 +447,12 @@ namespace beam::wallet if (x.empty()) { m_WalletDB->ClearAppData(Blob(sName.c_str(), static_cast(sName.size()))); - m_WalletDB->removeVarRaw(WidgetRunner::s_szVarName); } else { Blob buf(x); m_WalletDB->set_AppData(Blob(sName.c_str(), static_cast(sName.size())), Blob(), &buf); - m_WalletDB->setVarRaw(WidgetRunner::s_szVarName, &x.front(), x.size()); - w.GetOrCreate(*this, std::move(sName)); } From 2ab6ac4c03192f9d90d88886f03c5d3fe0f38f5c Mon Sep 17 00:00:00 2001 From: valdok Date: Sun, 9 Jun 2024 13:08:06 +0300 Subject: [PATCH 13/34] explorer: amount with + sign where applicable. htm: different clr for signed/unsigned positive. --- explorer/adapter.cpp | 64 ++++++++++++++--------- explorer/htm/BeamExplorer.htm | 15 +++--- explorer/server.cpp | 97 +++++++++++++++++------------------ 3 files changed, 94 insertions(+), 82 deletions(-) diff --git a/explorer/adapter.cpp b/explorer/adapter.cpp index 6a9928fd6..f746e8270 100644 --- a/explorer/adapter.cpp +++ b/explorer/adapter.cpp @@ -843,11 +843,46 @@ class Adapter : public Node::IObserver, public IAdapter { return MakeTypeObj("aid", aid); } - static json MakeObjAmount(const Amount x) + template + static json MakeObjAmount_T(const T& x) { return MakeTypeObj("amount", x); } + static json MakeObjAmount(const Amount x) + { + return MakeObjAmount_T(x); + } + + static json MakeObjAmount(const AmountBig::Type& x) + { + if (!AmountBig::get_Hi(x)) + return MakeObjAmount(AmountBig::get_Lo(x)); + + char sz[AmountBig::Type::nTxtLen10Max + 1]; + x.PrintDecimal(sz); + + return MakeObjAmount_T(sz); + } + + static json MakeObjAmountS(AmountBig::Type x) + { + char sz[AmountBig::Type::nTxtLen10Max + 2]; + if (x.get_Msb()) + { + x.Negate(); + sz[0] = '-'; + } + else + sz[0] = '+'; + + if (AmountBig::get_Hi(x)) + x.PrintDecimal(sz + 1); + else + uintBigFrom(AmountBig::get_Lo(x)).PrintDecimal(sz + 1); // awkward, but ok + + return MakeObjAmount_T(sz); + } static json MakeObjHeight(Height h) { return MakeTypeObj("height", h); @@ -869,27 +904,6 @@ class Adapter : public Node::IObserver, public IAdapter { return MakeTypeObj("blob", x); } - static json MakeObjAmount(const AmountBig::Type& x) - { - if (!AmountBig::get_Hi(x)) - return MakeObjAmount(AmountBig::get_Lo(x)); - - char sz[AmountBig::Type::nTxtLen10Max + 2]; - - if (x.get_Msb()) - { - auto x2 = x; - x2.Negate(); - - sz[0] = '-'; - x2.PrintDecimal(sz + 1); - } - else - x.PrintDecimal(sz); - - return MakeTypeObj("amount", sz); - } - struct ExtraInfo { struct ContractRichInfo { @@ -1128,7 +1142,7 @@ class Adapter : public Node::IObserver, public IAdapter { json jEntry = json::array(); jEntry.push_back(MakeObjAid(it->first)); - jEntry.push_back(MakeObjAmount(val)); + jEntry.push_back(MakeObjAmountS(val)); jArr.push_back(std::move(jEntry)); } @@ -1150,7 +1164,7 @@ class Adapter : public Node::IObserver, public IAdapter { json jEntry = json::array(); jEntry.push_back(MakeObjAid(it->first)); - jEntry.push_back(MakeObjAmount(val)); + jEntry.push_back(MakeObjAmountS(val)); jArr.push_back(std::move(jEntry)); } @@ -2010,7 +2024,7 @@ class Adapter : public Node::IObserver, public IAdapter { } wrItem.m_json.push_back(delta.get_Msb() ? "Burn" : "Mint"); - wrItem.m_json.push_back(MakeObjAmount(delta)); // handles negative sign + wrItem.m_json.push_back(MakeObjAmountS(delta)); // handles negative sign wrItem.m_json.push_back(MakeObjAmount(evt.m_Adp.m_Amount)); wrItem.m_json.push_back(""); } diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 1067e88b6..38523df45 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -114,14 +114,14 @@ } .amount { font-family: monospace; - font-size: 1.5rem; - color: green; + font-size: 1.7rem; + color: darkcyan; } .amount.pos { color: green; /* Positive values in green */ } .amount.neg { - color: blue; /* Negative values in blue */ + color: red; /* Negative values in red */ } .th { /* Not sure yet how to use this class (these "headers" can appear in rows or in columns)... */ @@ -447,13 +447,14 @@ function MakeAmountClr(amount) { - if (!amount) - return ""; + let type = "amount"; - let type = "amount pos"; if (amount[0] == '-') type = "amount neg"; - return AddClass(amount,type); + if (amount[0] == '+') + type = "amount pos"; + + return AddClass(amount, type); } function AddClass(txt,className) diff --git a/explorer/server.cpp b/explorer/server.cpp index 8413071d2..afa04dd19 100644 --- a/explorer/server.cpp +++ b/explorer/server.cpp @@ -205,6 +205,37 @@ struct HtmlConverter return sRet.empty() ? s : sRet; } + static bool ReadAmount(const json& objV, Amount& val, AmountBig::Type& valBig, bool& bBig, char& chSign) + { + chSign = 0; + + if (objV.is_number()) + { + val = objV.get(); + bBig = false; + return true; + } + + if (!objV.is_string()) + return false; + + const auto& s = objV.get(); + auto sz = s.c_str(); + switch (sz[0]) + { + case '-': + case '+': + chSign = sz[0]; + sz++; + } + + // convert it. NOTE - this may be a BIG number, don't use std::stoll. + ReadUIntBig(valBig, sz); + bBig = true; + + return true; + } + bool OnObjSpecial(const json& obj) { auto itT = obj.find("type"); @@ -234,34 +265,19 @@ struct HtmlConverter if (sType == "amount") { - uint64_t val = 0; + uint64_t val; AmountBig::Type valBig; - bool bMinus = false; - bool bBig = false; - - if (objV.is_number()) - val = objV.get(); - else - { - if (!objV.is_string()) - return false; + char chSign; + bool bBig; - const auto& s = objV.get(); - auto sz = s.c_str(); - if (*sz == '-') - { - bMinus = true; - sz++; - } + if (!ReadAmount(objV, val, valBig, bBig, chSign)) + return false; - // convert it. NOTE - this may be a BIG number, don't use std::stoll. - bBig = true; - ReadUIntBig(valBig, sz); - } + const char* szClr = ('-' == chSign) ? "red" : ('+' == chSign) ? "green" : "blue"; - m_os << ""; - if (bMinus) - m_os << "-"; + m_os << ""; + if (chSign) + m_os << chSign; if (bBig) AmountBig::Print(m_os, valBig, false); @@ -567,34 +583,17 @@ void jsonExp(json& obj, uint32_t nDepth) const auto& sType = objT.get(); if (sType == "amount") { - uint64_t val = 0; + uint64_t val; AmountBig::Type valBig; - bool bMinus = false; - bool bBig = false; - - if (objV.is_number()) - val = objV.get(); - else - { - if (!objV.is_string()) - return; - - const auto& s = objV.get(); - auto sz = s.c_str(); - if (*sz == '-') - { - bMinus = true; - sz++; - } + char chSign; + bool bBig; - // convert it. NOTE - this may be a BIG number, don't use std::stoll. - bBig = true; - HtmlConverter::ReadUIntBig(valBig, sz); - } + if (!HtmlConverter::ReadAmount(objV, val, valBig, bBig, chSign)) + return; std::ostringstream os; - if (bMinus) - os << '-'; + if (chSign) + os << chSign; if (bBig) AmountBig::Print(os, valBig, false); @@ -602,10 +601,8 @@ void jsonExp(json& obj, uint32_t nDepth) AmountBig::Print(os, val, false); objV = os.str(); - } - } } From 817294dffd8334dd7376dbcb87eb3145fa234f73 Mon Sep 17 00:00:00 2001 From: valdok Date: Sun, 9 Jun 2024 17:53:41 +0300 Subject: [PATCH 14/34] explorer: flexible column selection in "hdrs" query --- explorer/adapter.cpp | 192 +++++++++++++++++++--------------- explorer/adapter.h | 29 ++++- explorer/htm/BeamExplorer.htm | 2 +- explorer/server.cpp | 43 +++++++- 4 files changed, 177 insertions(+), 89 deletions(-) diff --git a/explorer/adapter.cpp b/explorer/adapter.cpp index f746e8270..08ed40129 100644 --- a/explorer/adapter.cpp +++ b/explorer/adapter.cpp @@ -288,6 +288,7 @@ class Adapter : public Node::IObserver, public IAdapter { struct MW { CountAndSize m_Inputs; CountAndSize m_Outputs; + uint64_t get_Utxos() const { return m_Outputs.m_Count - m_Inputs.m_Count; } } m_MW; struct Shielded { @@ -302,6 +303,9 @@ class Adapter : public Node::IObserver, public IAdapter { uint64_t get_Sum() const { return m_Created + m_Destroyed + m_Invoked; } + uint64_t get_Active() const { + return m_Created - m_Destroyed; + } } m_Contract; void OnHiLevelKrn(const TxKernel::Ptr& pKrn) @@ -691,10 +695,12 @@ class Adapter : public Node::IObserver, public IAdapter { ret.m_sz[nLen++] = '-'; } - nLen += NiceDecimal::Print(ret.m_sz + nLen, static_cast(x)); + uint32_t nLenUns = NiceDecimal::Print(ret.m_sz + nLen, static_cast(x));; + if (get_ExpandWithCommas()) - nLen = NiceDecimal::ExpandCommas(ret.m_sz, nLen); + nLenUns = NiceDecimal::ExpandCommas(ret.m_sz + nLen, nLenUns); + nLen += nLenUns; assert(nLen < _countof(ret.m_sz)); } else @@ -2121,74 +2127,114 @@ class Adapter : public Node::IObserver, public IAdapter { return MakeTable(std::move(jAssets)); } - struct AggrFormatter + void OnHdrs_Difficulty_Abs(json& j) { j.push_back(MakeTableHdr("Chainwork")); } + void OnHdrs_Difficulty_Abs(json& j, const Totals&, const Block::SystemState::Full& s) { j.push_back(NiceDecimal::MakeDifficulty(s.m_ChainWork).m_sz); } + void OnHdrs_Difficulty_Rel(json& j) { j.push_back(MakeTableHdr("Difficulty")); } + void OnHdrs_Difficulty_Rel(json& j, const Totals&, const Totals&, const Block::SystemState::Full& s) { j.push_back(NiceDecimal::MakeDifficulty(s.m_PoW.m_Difficulty).m_sz); } + + void OnHdrs_Fee_Abs(json& j) { j.push_back(MakeTableHdr("T.Fee")); } + void OnHdrs_Fee_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeObjAmount(t1.m_Fee)); } + void OnHdrs_Fee_Rel(json& j) { j.push_back(MakeTableHdr("Fee")); } + void OnHdrs_Fee_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { + auto val = t0.m_Fee; + val.Negate(); + val += t1.m_Fee; + j.push_back(MakeObjAmount(val)); + } + + void OnHdrs_Kernels_Abs(json& j) { j.push_back(MakeTableHdr("T.Txs")); } + void OnHdrs_Kernels_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_Kernels.m_Count).m_sz); } + void OnHdrs_Kernels_Rel(json& j) { j.push_back(MakeTableHdr("Txs")); } + void OnHdrs_Kernels_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_Kernels.m_Count - t0.m_Kernels.m_Count).m_sz); } + + void OnHdrs_MwOutputs_Abs(json& j) { j.push_back(MakeTableHdr("T.MW.Outputs")); } + void OnHdrs_MwOutputs_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_MW.m_Outputs.m_Count).m_sz); } + void OnHdrs_MwOutputs_Rel(json& j) { j.push_back(MakeTableHdr("MW.Outputs")); } + void OnHdrs_MwOutputs_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_MW.m_Outputs.m_Count - t0.m_MW.m_Outputs.m_Count).m_sz); } + + void OnHdrs_MwInputs_Abs(json& j) { j.push_back(MakeTableHdr("T.MW.Inputs")); } + void OnHdrs_MwInputs_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_MW.m_Inputs.m_Count).m_sz); } + void OnHdrs_MwInputs_Rel(json& j) { j.push_back(MakeTableHdr("MW.Inputs")); } + void OnHdrs_MwInputs_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_MW.m_Inputs.m_Count - t0.m_MW.m_Inputs.m_Count).m_sz); } + + void OnHdrs_MwUtxos_Abs(json& j) { j.push_back(MakeTableHdr("T.MW.Utxos")); } + void OnHdrs_MwUtxos_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_MW.get_Utxos()).m_sz); } + void OnHdrs_MwUtxos_Rel(json& j) { j.push_back(MakeTableHdr("MW.Utxos")); } + void OnHdrs_MwUtxos_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_MW.get_Utxos() - t0.m_MW.get_Utxos()).m_sz); } + + void OnHdrs_ShOutputs_Abs(json& j) { j.push_back(MakeTableHdr("T.SH.Outputs")); } + void OnHdrs_ShOutputs_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_Shielded.m_Outputs).m_sz); } + void OnHdrs_ShOutputs_Rel(json& j) { j.push_back(MakeTableHdr("SH.Outputs")); } + void OnHdrs_ShOutputs_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_Shielded.m_Outputs - t0.m_Shielded.m_Outputs).m_sz); } + + void OnHdrs_ShInputs_Abs(json& j) { j.push_back(MakeTableHdr("T.SH.Inputs")); } + void OnHdrs_ShInputs_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_Shielded.m_Inputs).m_sz); } + void OnHdrs_ShInputs_Rel(json& j) { j.push_back(MakeTableHdr("SH.Inputs")); } + void OnHdrs_ShInputs_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_Shielded.m_Inputs - t0.m_Shielded.m_Inputs).m_sz); } + + void OnHdrs_ContractsActive_Abs(json& j) { j.push_back(MakeTableHdr("T.Contracts")); } + void OnHdrs_ContractsActive_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_Contract.get_Active()).m_sz); } + void OnHdrs_ContractsActive_Rel(json& j) { j.push_back(MakeTableHdr("Contracts")); } + void OnHdrs_ContractsActive_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_Contract.get_Active() - t0.m_Contract.get_Active()).m_sz); } + + void OnHdrs_ContractCalls_Abs(json& j) { j.push_back(MakeTableHdr("T.ContractCalls")); } + void OnHdrs_ContractCalls_Abs(json& j, const Totals& t1, const Block::SystemState::Full&) { j.push_back(MakeDecimal(t1.m_Contract.get_Sum()).m_sz); } + void OnHdrs_ContractCalls_Rel(json& j) { j.push_back(MakeTableHdr("ContractCalls")); } + void OnHdrs_ContractCalls_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full&) { j.push_back(MakeDecimalDelta(t1.m_Contract.get_Sum() - t0.m_Contract.get_Sum()).m_sz); } + + static uint64_t get_ChainSize(Height h, const Totals& t, bool bArchieve) { - bool m_Rel = true; - bool m_Abs = true; + // size estimation + uint64_t ret = + static_cast(sizeof(Block::SystemState::Sequence::Element)) * (h - Rules::HeightGenesis + 1) + + t.m_Kernels.m_Size + + t.m_MW.m_Outputs.m_Size; - template - void PushValWithTotal(json& res, T1&& x, T2&& dx) const - { - //json jRow = json::array(); - //jRow.push_back(std::move(x)); - //jRow.push_back(std::move(dx)); + if (bArchieve) + ret += t.m_MW.m_Inputs.m_Count * sizeof(ECC::Point); + else + ret -= t.m_MW.m_Inputs.m_Size; - //json jRows = json::array(); - //jRows.push_back(std::move(jRow)); + return ret; + } - //res.push_back(MakeTable(std::move(jRows))); - //res.push_back(std::move(dx)); - //res.push_back(std::move(x)); + void OnHdrs_SizeArchieve_Abs(json& j) { j.push_back(MakeTableHdr("Size.Archieve")); } + void OnHdrs_SizeArchieve_Abs(json& j, const Totals& t1, const Block::SystemState::Full& s) { j.push_back(MakeDecimal(get_ChainSize(s.m_Height, t1, true)).m_sz); } + void OnHdrs_SizeArchieve_Rel(json& j) { j.push_back(MakeTableHdr("D.Size.Archieve")); } + void OnHdrs_SizeArchieve_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full& s) { j.push_back(MakeDecimalDelta(get_ChainSize(s.m_Height, t1, true) - get_ChainSize(s.m_Height - 1, t0, true)).m_sz); } - if (m_Rel) - { - if (m_Abs) - { - res.push_back(MakeTable({ - { std::move(x) }, - { std::move(dx) } })); - } - else - res.push_back(std::move(dx)); - } - else - { - if (m_Abs) - res.push_back(std::move(x)); - else - res.push_back(""); - } - } - }; + void OnHdrs_SizeCompressed_Abs(json& j) { j.push_back(MakeTableHdr("Size.Compressed")); } + void OnHdrs_SizeCompressed_Abs(json& j, const Totals& t1, const Block::SystemState::Full& s) { j.push_back(MakeDecimal(get_ChainSize(s.m_Height, t1, false)).m_sz); } + void OnHdrs_SizeCompressed_Rel(json& j) { j.push_back(MakeTableHdr("D.Size.Compressed")); } + void OnHdrs_SizeCompressed_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full& s) { j.push_back(MakeDecimalDelta(get_ChainSize(s.m_Height, t1, false) - get_ChainSize(s.m_Height - 1, t0, false)).m_sz); } - json get_hdrs(uint64_t hMax, uint64_t nMax, bool bRel, bool bAbs) override + json get_hdrs(uint64_t hMax, uint64_t nMax, uint32_t fAbs, uint32_t fRel) override { std::setmin(nMax, 2048u); std::setmin(hMax, _nodeBackend.m_Cursor.m_Full.m_Height); json jRet = json::array(); - jRet.push_back(json::array({ - MakeTableHdr("Height"), - MakeTableHdr("Timestamp"), - MakeTableHdr("Hash"), - MakeTableHdr("Difficulty"), - MakeTableHdr("Fees"), - MakeTableHdr("Txs"), - MakeTableHdr("MW.Outs"), - MakeTableHdr("MW.Ins"), - MakeTableHdr("Sh.Outs"), - MakeTableHdr("Sh.Ins"), - MakeTableHdr("Contract calls"), - })); + { + json jCols = json::array({ + MakeTableHdr("Height"), + MakeTableHdr("Timestamp"), + MakeTableHdr("Hash"), + }); + +#define THE_MACRO(type) \ + if (TotalsFlags::type & fAbs) OnHdrs_##type##_Abs(jCols); \ + if (TotalsFlags::type & fRel) OnHdrs_##type##_Rel(jCols); + + ExplorerTotals_All(THE_MACRO) +#undef THE_MACRO + + jRet.push_back(std::move(jCols)); + } Height hMore = 0; - AggrFormatter af; - af.m_Rel = bRel; - af.m_Abs = bAbs; - if (hMax && nMax) { auto& db = _nodeBackend.get_DB(); @@ -2217,8 +2263,6 @@ class Adapter : public Node::IObserver, public IAdapter { jRow.push_back(MakeTypeObj("time", s.m_TimeStamp)); jRow.push_back(MakeObjBlob(hv)); - af.PushValWithTotal(jRow, NiceDecimal::MakeDifficulty(s.m_ChainWork).m_sz, NiceDecimal::MakeDifficulty(s.m_PoW.m_Difficulty).m_sz); - bool bDone = false; iIdxTots = !iIdxTots; @@ -2234,29 +2278,12 @@ class Adapter : public Node::IObserver, public IAdapter { const auto& t1 = pTots[!iIdxTots].m_Totals; const auto& t0 = pTots[iIdxTots].m_Totals; +#define THE_MACRO(type) \ + if (TotalsFlags::type & fAbs) OnHdrs_##type##_Abs(jRow, t1, s); \ + if (TotalsFlags::type & fRel) OnHdrs_##type##_Rel(jRow, t1, t0, s); - // Fees - { - auto val = t0.m_Fee; - val.Negate(); - val += t1.m_Fee; - - af.PushValWithTotal(jRow, MakeObjAmount(t1.m_Fee), MakeObjAmount(val)); - } - - // Txs - af.PushValWithTotal(jRow, MakeDecimal(t1.m_Kernels.m_Count).m_sz, MakeDecimalDelta(t1.m_Kernels.m_Count - t0.m_Kernels.m_Count).m_sz); - // MW outputs - af.PushValWithTotal(jRow, MakeDecimal(t1.m_MW.m_Outputs.m_Count).m_sz, MakeDecimalDelta(t1.m_MW.m_Outputs.m_Count - t0.m_MW.m_Outputs.m_Count).m_sz); - // MW inputs - af.PushValWithTotal(jRow, MakeDecimal(t1.m_MW.m_Inputs.m_Count).m_sz, MakeDecimalDelta(t1.m_MW.m_Inputs.m_Count - t0.m_MW.m_Inputs.m_Count).m_sz); - // Shielded outputs - af.PushValWithTotal(jRow, MakeDecimal(t1.m_Shielded.m_Outputs).m_sz, MakeDecimalDelta(t1.m_Shielded.m_Outputs - t0.m_Shielded.m_Outputs).m_sz); - // Shielded inputs - af.PushValWithTotal(jRow, MakeDecimal(t1.m_Shielded.m_Inputs).m_sz, MakeDecimalDelta(t1.m_Shielded.m_Inputs - t0.m_Shielded.m_Inputs).m_sz); - // Contracts - af.PushValWithTotal(jRow, MakeDecimal(t1.m_Contract.get_Sum()).m_sz, MakeDecimalDelta(t1.m_Contract.get_Sum() - t0.m_Contract.get_Sum()).m_sz); - + ExplorerTotals_All(THE_MACRO) +#undef THE_MACRO jRet.push_back(std::move(jRow)); @@ -2289,7 +2316,7 @@ class Adapter : public Node::IObserver, public IAdapter { json jInfo = json::array(); jInfo.push_back({ MakeTableHdr("Transactions"), MakeDecimal(sd.m_Totals.m_Kernels.m_Count).m_sz }); jInfo.push_back({ MakeTableHdr("TXOs"), MakeDecimal(sd.m_Totals.m_MW.m_Outputs.m_Count).m_sz }); - jInfo.push_back({ MakeTableHdr("UTXOs"), MakeDecimal(sd.m_Totals.m_MW.m_Outputs.m_Count - sd.m_Totals.m_MW.m_Inputs.m_Count).m_sz }); + jInfo.push_back({ MakeTableHdr("UTXOs"), MakeDecimal(sd.m_Totals.m_MW.get_Utxos()).m_sz }); jInfo.push_back({ MakeTableHdr("Shielded Outs"), MakeDecimal(sd.m_Totals.m_Shielded.m_Outputs).m_sz }); jInfo.push_back({ MakeTableHdr("Shielded Ins"), MakeDecimal(sd.m_Totals.m_Shielded.m_Inputs).m_sz }); jInfo.push_back({ MakeTableHdr("Contracts Invoked"), MakeDecimal(sd.m_Totals.m_Contract.get_Sum()).m_sz }); @@ -2306,11 +2333,8 @@ class Adapter : public Node::IObserver, public IAdapter { jInfo.push_back({ MakeTableHdr("Total Emission"), MakeObjAmount(valAmount) }); // size estimation - uint64_t nSizeEternal = sd.m_Totals.m_Kernels.m_Size; - nSizeEternal += static_cast(sizeof(Block::SystemState::Sequence::Element)) * (s.m_Height - Rules::HeightGenesis + 1); - - jInfo.push_back({ MakeTableHdr("Size Compressed"), MakeDecimal(nSizeEternal + sd.m_Totals.m_MW.m_Outputs.m_Size - sd.m_Totals.m_MW.m_Inputs.m_Size).m_sz }); - jInfo.push_back({ MakeTableHdr("Size Archive"), MakeDecimal(nSizeEternal + sd.m_Totals.m_MW.m_Outputs.m_Size + sd.m_Totals.m_MW.m_Inputs.m_Count * sizeof(ECC::Point)).m_sz }); + jInfo.push_back({ MakeTableHdr("Size Compressed"), MakeDecimal(get_ChainSize(s.m_Height, sd.m_Totals, false)).m_sz }); + jInfo.push_back({ MakeTableHdr("Size Archive"), MakeDecimal(get_ChainSize(s.m_Height, sd.m_Totals, true)).m_sz }); PrepareTreasureSchedule(); if (!m_mapTreasury.empty()) diff --git a/explorer/adapter.h b/explorer/adapter.h index 70bc21f5c..5d57c7b39 100644 --- a/explorer/adapter.h +++ b/explorer/adapter.h @@ -21,6 +21,20 @@ namespace beam { struct Node; using nlohmann::json; +#define ExplorerTotals_All(macro) \ + macro(Difficulty) \ + macro(Fee) \ + macro(Kernels) \ + macro(MwOutputs) \ + macro(MwInputs) \ + macro(MwUtxos) \ + macro(ShOutputs) \ + macro(ShInputs) \ + macro(ContractsActive) \ + macro(ContractCalls) \ + macro(SizeArchieve) \ + macro(SizeCompressed) \ + namespace explorer { /// node->explorer adapter interface @@ -32,6 +46,19 @@ struct IAdapter { AutoHtml, }; + struct TotalsFlags { + + enum struct Bit { +#define THE_MACRO(type) type, + ExplorerTotals_All(THE_MACRO) +#undef THE_MACRO + }; + +#define THE_MACRO(type) static const uint32_t type = 1u << static_cast(Bit::type); + ExplorerTotals_All(THE_MACRO) +#undef THE_MACRO + }; + Mode m_Mode = Mode::Legacy; using Ptr = std::unique_ptr; @@ -45,7 +72,7 @@ struct IAdapter { virtual json get_block(uint64_t height) = 0; virtual json get_block_by_kernel(const Blob& key) = 0; virtual json get_blocks(uint64_t startHeight, uint64_t n) = 0; - virtual json get_hdrs(uint64_t hMax, uint64_t nMax, bool bRel, bool bAbs) = 0; + virtual json get_hdrs(uint64_t hMax, uint64_t nMax, uint32_t fAbs, uint32_t fRel) = 0; virtual json get_peers() = 0; #ifdef BEAM_ATOMIC_SWAP_SUPPORT diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 38523df45..4641e6450 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -1260,7 +1260,7 @@

Contract " + AddClass(g_CurrentID, "cidTitle") + "

\n"; else if (type == "hdrs") { xmlhttp.onload = DisplayHdrs; - xmlhttp.open("GET", urlPrefix + "hdrs" + urlSuffix + "&nMax=100"); + xmlhttp.open("GET", urlPrefix + "hdrs" + urlSuffix + "&nMax=100&cabs=&crel=dfkoOiIC"); xmlhttp.send(); } else if (type == "contracts") diff --git a/explorer/server.cpp b/explorer/server.cpp index afa04dd19..3cc2dff41 100644 --- a/explorer/server.cpp +++ b/explorer/server.cpp @@ -768,15 +768,52 @@ OnRequest(blocks) return _backend.get_blocks(start, n); } +bool ReadColFlags(const HttpUrl& url, uint32_t& res, const char* szArg) +{ + auto it = url.args.find(szArg); + if (url.args.end() == it) + return false; + + res = 0; + + typedef IAdapter::TotalsFlags F; + + for (char ch : it->second) + { + switch (ch) + { + case 'd': res |= F::Difficulty; break; + case 'f': res |= F::Fee; break; + case 'k': res |= F::Kernels; break; + case 'o': res |= F::MwOutputs; break; + case 'i': res |= F::MwInputs; break; + case 'u': res |= F::MwUtxos; break; + case 'O': res |= F::ShOutputs; break; + case 'I': res |= F::ShInputs; break; + case 'c': res |= F::ContractsActive; break; + case 'C': res |= F::ContractCalls; break; + case 's': res |= F::SizeCompressed; break; + case 'S': res |= F::SizeArchieve; break; + } + } + + return true; +} + OnRequest(hdrs) { Height hTop = _currentUrl.get_int_arg("hMax", std::numeric_limits::max()); uint32_t n = (uint32_t) _currentUrl.get_int_arg("nMax", static_cast(-1)); - bool bRel = !!_currentUrl.get_int_arg("rel", 1); - bool bAbs = !!_currentUrl.get_int_arg("rel", 0); + // defaults + typedef IAdapter::TotalsFlags F; + uint32_t fAbs = 0; + uint32_t fRel = F::Difficulty | F::Fee | F::Kernels | F::MwOutputs | F::MwInputs | F::ShOutputs | F::ShInputs | F::ContractCalls; + + ReadColFlags(_currentUrl, fAbs, "cabs"); + ReadColFlags(_currentUrl, fRel, "crel"); - return _backend.get_hdrs(hTop, n, bRel, bAbs); + return _backend.get_hdrs(hTop, n, fAbs, fRel); } OnRequest(peers) From 767d55c48872d3c32531d7a879db408c1383f82e Mon Sep 17 00:00:00 2001 From: valdok Date: Sun, 9 Jun 2024 18:09:56 +0300 Subject: [PATCH 15/34] explorer: added dh arg to hdrs query --- explorer/adapter.cpp | 25 +++++++++++++++++++++---- explorer/adapter.h | 2 +- explorer/server.cpp | 3 ++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/explorer/adapter.cpp b/explorer/adapter.cpp index 08ed40129..1ea65eda9 100644 --- a/explorer/adapter.cpp +++ b/explorer/adapter.cpp @@ -2209,11 +2209,13 @@ class Adapter : public Node::IObserver, public IAdapter { void OnHdrs_SizeCompressed_Rel(json& j) { j.push_back(MakeTableHdr("D.Size.Compressed")); } void OnHdrs_SizeCompressed_Rel(json& j, const Totals& t1, const Totals& t0, const Block::SystemState::Full& s) { j.push_back(MakeDecimalDelta(get_ChainSize(s.m_Height, t1, false) - get_ChainSize(s.m_Height - 1, t0, false)).m_sz); } - json get_hdrs(uint64_t hMax, uint64_t nMax, uint32_t fAbs, uint32_t fRel) override + json get_hdrs(uint64_t hMax, uint64_t nMax, uint64_t dh, uint32_t fAbs, uint32_t fRel) override { std::setmin(nMax, 2048u); std::setmin(hMax, _nodeBackend.m_Cursor.m_Full.m_Height); + std::setmax(dh, 1u); + json jRet = json::array(); { @@ -2244,6 +2246,7 @@ class Adapter : public Node::IObserver, public IAdapter { sid.m_Row = db.FindActiveStateStrict(hMax); Merkle::Hash hv; + bool bValidHv = false; StateData pTots[2]; uint32_t iIdxTots = 0; @@ -2254,7 +2257,7 @@ class Adapter : public Node::IObserver, public IAdapter { Block::SystemState::Full s; db.get_State(sid.m_Row, s); - if (hMax == sid.m_Height) + if (!bValidHv) s.get_Hash(hv); json jRow = json::array(); @@ -2267,7 +2270,17 @@ class Adapter : public Node::IObserver, public IAdapter { iIdxTots = !iIdxTots; - if (!db.get_Prev(sid)) + if (sid.m_Height - Rules::HeightGenesis >= dh) + { + if (1u == dh) + db.get_Prev(sid); + else + { + sid.m_Height -= dh; + sid.m_Row = db.FindActiveStateStrict(sid.m_Height); + } + } + else { ZeroObject(sid); bDone = true; @@ -2296,7 +2309,11 @@ class Adapter : public Node::IObserver, public IAdapter { if (bDone) break; - hv = s.m_Prev; + if (1u == dh) + { + hv = s.m_Prev; + bValidHv = true; + } } } diff --git a/explorer/adapter.h b/explorer/adapter.h index 5d57c7b39..1115e424b 100644 --- a/explorer/adapter.h +++ b/explorer/adapter.h @@ -72,7 +72,7 @@ struct IAdapter { virtual json get_block(uint64_t height) = 0; virtual json get_block_by_kernel(const Blob& key) = 0; virtual json get_blocks(uint64_t startHeight, uint64_t n) = 0; - virtual json get_hdrs(uint64_t hMax, uint64_t nMax, uint32_t fAbs, uint32_t fRel) = 0; + virtual json get_hdrs(uint64_t hMax, uint64_t nMax, uint64_t dh, uint32_t fAbs, uint32_t fRel) = 0; virtual json get_peers() = 0; #ifdef BEAM_ATOMIC_SWAP_SUPPORT diff --git a/explorer/server.cpp b/explorer/server.cpp index 3cc2dff41..b49d33398 100644 --- a/explorer/server.cpp +++ b/explorer/server.cpp @@ -804,6 +804,7 @@ OnRequest(hdrs) { Height hTop = _currentUrl.get_int_arg("hMax", std::numeric_limits::max()); uint32_t n = (uint32_t) _currentUrl.get_int_arg("nMax", static_cast(-1)); + Height dh = _currentUrl.get_int_arg("dh", static_cast(1)); // defaults typedef IAdapter::TotalsFlags F; @@ -813,7 +814,7 @@ OnRequest(hdrs) ReadColFlags(_currentUrl, fAbs, "cabs"); ReadColFlags(_currentUrl, fRel, "crel"); - return _backend.get_hdrs(hTop, n, fAbs, fRel); + return _backend.get_hdrs(hTop, n, dh, fAbs, fRel); } OnRequest(peers) From 65dbfaf5f569ef5a3b28cdb5cbba8fcc197f2650 Mon Sep 17 00:00:00 2001 From: dbadol Date: Sun, 9 Jun 2024 23:58:10 +0200 Subject: [PATCH 16/34] Update BeamExplorer.htm --- explorer/htm/BeamExplorer.htm | 1004 ++++++++++++++++++++++++--------- 1 file changed, 729 insertions(+), 275 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 4641e6450..37f7393d6 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -1,9 +1,38 @@ + - + + + + + + Beam Smart Explorer + + - + - -

Loading...

- + + + + + + +
+ + +
+ + +

+

Loading...

+

+ + + + + + + + + + + + From 226a5cc2c2536ab156c080c037382ba1661e20a8 Mon Sep 17 00:00:00 2001 From: dbadol Date: Wed, 12 Jun 2024 01:05:48 +0200 Subject: [PATCH 17/34] Eye symbols toggle text both ways --- explorer/htm/BeamExplorer.htm | 90 ++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 13 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 37f7393d6..79ab89c96 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -124,7 +124,7 @@ .metadata .full { display: inline-block; /* Needed to allow setting a max-width */ max-width: 80ch; /* Wrap long strings after 80 characters */ - white-space: pre-wrap; + white-space: pre-wrap; /* Wrap and preserve all space */ word-wrap: break-word; /* Allow breaking words to next line */ font-family: inherit; } @@ -138,16 +138,16 @@ font-family: inherit; } /* The extend symbols are hidden by default in the HTML. We show them only if right after a truncated element */ - .metadata .reduced + .extend { + .extend { display: inline; /* Superseed the HTML 'hidden' attribute */ visibility: hidden; /* Hide the symbols but maintain their space */ cursor: pointer; font-size: 1.8rem; color: grey; - vertical-align: text-bottom; /* This is to align correctly the symbol with the text */ + vertical-align: text-bottom; /* This is to try to align correctly the symbol with the text... */ } - /* Display the extend symbols when hovering over the cell or the span containing a truncated text */ - td:hover .metadata .reduced + .extend, span:hover .metadata .reduced + .extend { + /* Display the extend symbols when hovering over the cell or the span containing the text */ + td:hover > .metadata .extend, span:hover .metadata .extend { visibility: visible; } /* Highlight the symbol when hovering on it */ @@ -201,7 +201,7 @@ font-family: inherit; } /* The extend symbols are hidden by default in the HTML. We show them only if right after a truncated element */ - .truncated + .expand { + .expand { display: inline; /* Superseed the HTML 'hidden' attribute */ visibility: hidden; /* Hide the symbols but maintain their space */ cursor: pointer; @@ -209,8 +209,9 @@ color: grey; position: relative; } - /* Display the expand symbols when hovering over the cell or the list item containing a truncated text */ - td:hover .truncated + .expand, li:hover > span .truncated + .expand { + /* Display the expand symbols when hovering over the cell or the list item containing the text */ + td:hover .truncated + .expand, li:hover > span .truncated + .expand, + td:hover .expanded + .expand, li:hover > span .expanded + .expand { visibility: visible; } /* Hide the expand symbol in the special case of a text with link (just to avoid confusion about the effect of clicking) */ @@ -1548,7 +1549,7 @@

Deployed Smart Contracts

\n\ let myClass = (myHash.querySelector("a")) ? "truncated withLink" : "truncated"; // Add a span to truncate the text, and another span to hold the clickable symbol let myHTML = myHash.innerHTML; - myHash.innerHTML = "" + myHTML + ""; + myHash.innerHTML = "" + myHTML + ""; // Add event listener on the symbol myHash.querySelector(".expand").addEventListener("click", expandHash); } @@ -1556,7 +1557,7 @@

Deployed Smart Contracts

\n\ for (let myMetadata of document.querySelectorAll(".metadata")) { // Add a span to truncate the text, and another span to hold the clickable symbol let myHTML = myMetadata.innerHTML; - myMetadata.innerHTML = "" + myHTML + ""; + myMetadata.innerHTML = "" + myHTML + ""; // Add event listener on the symbol myMetadata.querySelector(".extend").addEventListener("click", expandMetadata); } @@ -1575,6 +1576,9 @@

Deployed Smart Contracts

\n\ for (let myItem of myRow.cells[col].querySelectorAll(".truncated")) { myItem.classList.remove("truncated"); myItem.classList.add("expanded"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", expandHash); + myItem.nextElementSibling.addEventListener("click", truncateHash); } } } else { @@ -1582,6 +1586,39 @@

Deployed Smart Contracts

\n\ for (let myItem of input.parentNode.querySelectorAll(".truncated")) { myItem.classList.remove("truncated"); myItem.classList.add("expanded"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", expandHash); + myItem.nextElementSibling.addEventListener("click", truncateHash); + } + } + } + + function truncateHash(e) { + // Get element, table and column number of the event + let input = e.currentTarget; + // If item is in table, truncate the whole column + if (input.closest('table')) { + let col = input.closest('th,td').cellIndex; + let table = input.closest('table'); + // Loop on all cells in that column + for (let myRow of table.rows) { + // Remove all expanded classes in the cell + for (let myItem of myRow.cells[col].querySelectorAll(".expanded")) { + myItem.classList.remove("expanded"); + myItem.classList.add("truncated"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", truncateHash); + myItem.nextElementSibling.addEventListener("click", expandHash); + } + } + } else { + // Expand only the item and its siblings + for (let myItem of input.parentNode.querySelectorAll(".expanded")) { + myItem.classList.remove("expanded"); + myItem.classList.add("truncated"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", truncateHash); + myItem.nextElementSibling.addEventListener("click", expandHash); } } } @@ -1592,6 +1629,21 @@

Deployed Smart Contracts

\n\ for (let myItem of input.parentNode.querySelectorAll(".reduced")) { myItem.classList.remove("reduced"); myItem.classList.add("full"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", expandMetadata); + myItem.nextElementSibling.addEventListener("click", truncateMetadata); + } + } + + function truncateMetadata(e) { + // Truncate selected metadata only + let input = e.currentTarget; + for (let myItem of input.parentNode.querySelectorAll(".full")) { + myItem.classList.remove("full"); + myItem.classList.add("reduced"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", truncateMetadata); + myItem.nextElementSibling.addEventListener("click", expandMetadata); } } @@ -1600,11 +1652,17 @@

Deployed Smart Contracts

\n\ for (let myItem of document.querySelectorAll(".truncated")) { myItem.classList.remove("truncated"); myItem.classList.add("expanded"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", expandHash); + myItem.nextElementSibling.addEventListener("click", truncateHash); } // Expand all truncated Metadata for (let myItem of document.querySelectorAll(".reduced")) { myItem.classList.remove("reduced"); myItem.classList.add("full"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", expandMetadata); + myItem.nextElementSibling.addEventListener("click", truncateMetadata); } // Expand all small collapsible blocks for (let myItem of document.querySelectorAll(".collapsible-checkbox")) { @@ -1612,10 +1670,10 @@

Deployed Smart Contracts

\n\ myItem.checked = true; } } - // Switch action of the clickable symbol + // Switch action of the main clickable symbol let icon = document.querySelector("#ExpandAll"); icon.setAttribute("href", "javascript:truncateEverything();"); - icon.setAttribute("title", "Truncate everything"); + icon.setAttribute("title", "Reduce everything"); } function truncateEverything() { @@ -1623,11 +1681,17 @@

Deployed Smart Contracts

\n\ for (let myItem of document.querySelectorAll(".expanded")) { myItem.classList.remove("expanded"); myItem.classList.add("truncated"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", truncateHash); + myItem.nextElementSibling.addEventListener("click", expandHash); } // Truncate all Metadata for (let myItem of document.querySelectorAll(".full")) { myItem.classList.remove("full"); myItem.classList.add("reduced"); + // Switch action of the clickable symbols + myItem.nextElementSibling.removeEventListener("click", truncateMetadata); + myItem.nextElementSibling.addEventListener("click", expandMetadata); } // Collapse all small collapsible blocks for (let myItem of document.querySelectorAll(".collapsible-checkbox")) { @@ -1635,7 +1699,7 @@

Deployed Smart Contracts

\n\ myItem.checked = false; } } - // Switch action of the clickable symbol + // Switch action of the main clickable symbol let icon = document.querySelector("#ExpandAll"); icon.setAttribute("href", "javascript:expandEverything();"); icon.setAttribute("title", "Expand everything"); From 45f3bf579ff78a9689b35f876b5616b495575cb8 Mon Sep 17 00:00:00 2001 From: dbadol Date: Sun, 16 Jun 2024 12:27:11 +0200 Subject: [PATCH 18/34] Correction of Cell Amounts --- explorer/htm/BeamExplorer.htm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 79ab89c96..1b0c48773 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -985,8 +985,8 @@

Deployed Smart Contracts

\n\ text += MakeCell(MakeBlock(jRow[0])); text += MakeCell(jRow[1]); - text += MakeCellAmount(jRow[2]["value"], ""); - text += MakeCellAmount(jRow[3]["value"], ""); + text += MakeCellAmount(Obj2Html(jRow[2]), ""); + text += MakeCellAmount(Obj2Html(jRow[3]), ""); text += MakeCell(Obj2Html(jRow[4])); text += ""; } From 4f17b967f8f4d0aa9098f35a11608c85632dd7e8 Mon Sep 17 00:00:00 2001 From: dbadol Date: Sun, 16 Jun 2024 17:49:32 +0200 Subject: [PATCH 19/34] adjust vocabulary --- explorer/htm/BeamExplorer.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 1b0c48773..9c718a747 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -1673,7 +1673,7 @@

Deployed Smart Contracts

\n\ // Switch action of the main clickable symbol let icon = document.querySelector("#ExpandAll"); icon.setAttribute("href", "javascript:truncateEverything();"); - icon.setAttribute("title", "Reduce everything"); + icon.setAttribute("title", "Collapse everything"); } function truncateEverything() { From 1045e20bf056948744a08884c246971de118796d Mon Sep 17 00:00:00 2001 From: dbadol Date: Mon, 17 Jun 2024 01:52:55 +0200 Subject: [PATCH 20/34] Correct an overflow display of eye symbols --- explorer/htm/BeamExplorer.htm | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 9c718a747..e475875f5 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -116,35 +116,35 @@ } .metadata { font-family: "Lucida Console", ui-monospace, monospace; + display: table; /* We use table-like display to ensure that text and symbol stay inline */ color: #505050; font-size: 1.2rem; - white-space: nowrap; /* To ensure that the symbol stays inline with text */ } /* Display full metadata */ .metadata .full { - display: inline-block; /* Needed to allow setting a max-width */ + font-family: inherit; + display: table-cell; max-width: 80ch; /* Wrap long strings after 80 characters */ white-space: pre-wrap; /* Wrap and preserve all space */ - word-wrap: break-word; /* Allow breaking words to next line */ - font-family: inherit; + overflow-wrap: break-word; /* Break words when needed (similar to the old word-wrap) */ + /*word-break: break-all; /* Wrap anywhere, without even trying to do it between words */ } /* Display reduced metadata */ .metadata .reduced { - display: inline-block; /* Needed to allow setting a max-width */ - max-width: 45ch; /* Show only the 45 first characters (good enough for AMML tokens!) */ - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-family: inherit; + display: table-cell; + max-width: 45ch; /* Show only the 45 first characters (good enough for AMML tokens!) */ + white-space: nowrap; /* Don't wrap text */ + overflow: hidden; /* Hide text that overflows */ + text-overflow: ellipsis; /* Add '...' when overflowing */ } - /* The extend symbols are hidden by default in the HTML. We show them only if right after a truncated element */ + /* The extend symbols are hidden by default in the HTML */ .extend { - display: inline; /* Superseed the HTML 'hidden' attribute */ visibility: hidden; /* Hide the symbols but maintain their space */ + display: table-cell; cursor: pointer; font-size: 1.8rem; color: grey; - vertical-align: text-bottom; /* This is to try to align correctly the symbol with the text... */ } /* Display the extend symbols when hovering over the cell or the span containing the text */ td:hover > .metadata .extend, span:hover .metadata .extend { From a25e9cd8b2a66e57520c81d4e63ab485ffab6e51 Mon Sep 17 00:00:00 2001 From: dbadol Date: Mon, 17 Jun 2024 23:47:58 +0200 Subject: [PATCH 21/34] Cleaning --- explorer/htm/BeamExplorer.htm | 48 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index e475875f5..bb858b438 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -114,6 +114,22 @@ .assetName a { color: black; /* Keep links in black */ } + .bool { + font-family: "Lucida Console", ui-monospace, monospace; + font-size: 1.6rem; + color: black; + } + .bool.yes { + color: green; /* 'True' in green */ + } + .bool.no { + color: blue; /* 'False' in blue */ + } + .time { + white-space: nowrap; /* Don't wrap text */ + font-size: 1.2rem; + color: #650000; + } .metadata { font-family: "Lucida Console", ui-monospace, monospace; display: table; /* We use table-like display to ensure that text and symbol stay inline */ @@ -127,7 +143,6 @@ max-width: 80ch; /* Wrap long strings after 80 characters */ white-space: pre-wrap; /* Wrap and preserve all space */ overflow-wrap: break-word; /* Break words when needed (similar to the old word-wrap) */ - /*word-break: break-all; /* Wrap anywhere, without even trying to do it between words */ } /* Display reduced metadata */ .metadata .reduced { @@ -152,23 +167,7 @@ } /* Highlight the symbol when hovering on it */ .extend:hover { - color: #2c2c2c !important; /* I don't know why !important is needed here... */ - } - .bool { - font-family: "Lucida Console", ui-monospace, monospace; - font-size: 1.6rem; - color: black; - } - .bool.yes { - color: green; /* 'True' in green */ - } - .bool.no { - color: blue; /* 'False' in blue */ - } - .time { - white-space: nowrap; /* Don't wrap text */ - font-size: 1.2rem; - color: #650000; + color: #2c2c2c; } .cid, .kernelId, .blob, .commitment { font-family: "Lucida Console", ui-monospace, monospace; @@ -176,7 +175,7 @@ color: #525252; white-space: nowrap; display: inline; - vertical-align: middle; + vertical-align: middle; /* Needed to align text and extend symbol */ } .cid a { font-family: "Lucida Console", ui-monospace, monospace; @@ -189,18 +188,19 @@ font-family: "Lucida Console", ui-monospace, monospace; font-weight: normal; } - /* Display truncated texts */ + /* Display truncated hashes */ .truncated { + font-family: inherit; display: inline-block; /* Needed to allow setting a max-width */ max-width: 25ch; /* Show only the 25 first characters */ - overflow: hidden; - text-overflow: ellipsis; - font-family: inherit; + overflow: hidden; /* Hide text that overflows */ + text-overflow: ellipsis; /* Add '...' when overflowing */ } + /* Display extended hashes */ .expanded { font-family: inherit; } - /* The extend symbols are hidden by default in the HTML. We show them only if right after a truncated element */ + /* The extend symbols are hidden by default in the HTML */ .expand { display: inline; /* Superseed the HTML 'hidden' attribute */ visibility: hidden; /* Hide the symbols but maintain their space */ From 2351d527d3c8d147a92b308457c41e9cfc5f0ff6 Mon Sep 17 00:00:00 2001 From: dbadol Date: Tue, 18 Jun 2024 00:02:17 +0200 Subject: [PATCH 22/34] Simplify some CSS --- explorer/htm/BeamExplorer.htm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index bb858b438..692d17975 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -210,12 +210,11 @@ position: relative; } /* Display the expand symbols when hovering over the cell or the list item containing the text */ - td:hover .truncated + .expand, li:hover > span .truncated + .expand, - td:hover .expanded + .expand, li:hover > span .expanded + .expand { - visibility: visible; + td:hover span + .expand, li:hover > span span + .expand { + visibility: visible; } /* Hide the expand symbol in the special case of a text with link (just to avoid confusion about the effect of clicking) */ - .truncated.withLink:hover + .expand { + span.withLink:hover + .expand { visibility: hidden; } /* Highlight the symbol when hovering on it */ From 45455574f831309ec13f158d1d29fe530f4676c7 Mon Sep 17 00:00:00 2001 From: dbadol Date: Tue, 18 Jun 2024 01:58:34 +0200 Subject: [PATCH 23/34] Use SVG icons in banner --- explorer/htm/BeamExplorer.htm | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 692d17975..f7ecd3129 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -350,14 +350,11 @@ color: #525252; text-decoration-line: none; } - #Reload { - font-weight: bold; - } - #Back, #ExpandAll { - /* Nothing special */ + #Back *, #Reload *, #ExpandAll * { + fill: #606060; /* Color all SVG elements */ } - #Reload:hover, #Back:hover, #ExpandAll:hover { - color: #2c2c2c; + #Back:hover *, #Reload:hover *, #ExpandAll:hover * { + fill: #2c2c2c; /* Color all SVG elements */ } #TopButton, #BottomButton { position: fixed; /* Fixed position */ @@ -591,8 +588,8 @@ @@ -608,9 +605,9 @@

Beam Smart Explorer v0.4

- -
-
👁 + +
+
From 215f0f8247a9836530205778656e501c7ac816bf Mon Sep 17 00:00:00 2001 From: dbadol Date: Wed, 19 Jun 2024 01:05:33 +0200 Subject: [PATCH 24/34] Replace all eye symbols with SVG --- explorer/htm/BeamExplorer.htm | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index f7ecd3129..4bc28f522 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -153,13 +153,13 @@ overflow: hidden; /* Hide text that overflows */ text-overflow: ellipsis; /* Add '...' when overflowing */ } - /* The extend symbols are hidden by default in the HTML */ + /* Remark: The extend symbols are hidden by default in the HTML */ .extend { visibility: hidden; /* Hide the symbols but maintain their space */ display: table-cell; cursor: pointer; - font-size: 1.8rem; - color: grey; + fill: #aaaaaa; + padding: 0 0 0 3px; } /* Display the extend symbols when hovering over the cell or the span containing the text */ td:hover > .metadata .extend, span:hover .metadata .extend { @@ -167,7 +167,7 @@ } /* Highlight the symbol when hovering on it */ .extend:hover { - color: #2c2c2c; + fill: grey; } .cid, .kernelId, .blob, .commitment { font-family: "Lucida Console", ui-monospace, monospace; @@ -205,9 +205,8 @@ display: inline; /* Superseed the HTML 'hidden' attribute */ visibility: hidden; /* Hide the symbols but maintain their space */ cursor: pointer; - font-size: 1.8rem; - color: grey; - position: relative; + fill: #aaaaaa; + padding: 0 0 0 3px; } /* Display the expand symbols when hovering over the cell or the list item containing the text */ td:hover span + .expand, li:hover > span span + .expand { @@ -219,7 +218,7 @@ } /* Highlight the symbol when hovering on it */ .expand:hover { - color: #2c2c2c; + fill: grey; } .amount { font-family: "Lucida Console", ui-monospace, monospace; @@ -351,10 +350,10 @@ text-decoration-line: none; } #Back *, #Reload *, #ExpandAll * { - fill: #606060; /* Color all SVG elements */ + fill: #636785; /* Color all SVG elements */ } #Back:hover *, #Reload:hover *, #ExpandAll:hover * { - fill: #2c2c2c; /* Color all SVG elements */ + fill: #505050; /* Color all SVG elements */ } #TopButton, #BottomButton { position: fixed; /* Fixed position */ @@ -583,6 +582,9 @@ + + + @@ -1545,7 +1547,7 @@

Deployed Smart Contracts

\n\ let myClass = (myHash.querySelector("a")) ? "truncated withLink" : "truncated"; // Add a span to truncate the text, and another span to hold the clickable symbol let myHTML = myHash.innerHTML; - myHash.innerHTML = "" + myHTML + ""; + myHash.innerHTML = "" + myHTML + ""; // Add event listener on the symbol myHash.querySelector(".expand").addEventListener("click", expandHash); } @@ -1553,7 +1555,7 @@

Deployed Smart Contracts

\n\ for (let myMetadata of document.querySelectorAll(".metadata")) { // Add a span to truncate the text, and another span to hold the clickable symbol let myHTML = myMetadata.innerHTML; - myMetadata.innerHTML = "" + myHTML + ""; + myMetadata.innerHTML = "" + myHTML + ""; // Add event listener on the symbol myMetadata.querySelector(".extend").addEventListener("click", expandMetadata); } From bf404e49d34bf01f5218e0509947046cb33ac744 Mon Sep 17 00:00:00 2001 From: dbadol Date: Sun, 23 Jun 2024 02:02:09 +0200 Subject: [PATCH 25/34] Replace next/prev symbols with SVG SVG icons are defined as templates and then called everytime they are needed. --- explorer/htm/BeamExplorer.htm | 101 +++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 37 deletions(-) diff --git a/explorer/htm/BeamExplorer.htm b/explorer/htm/BeamExplorer.htm index 4bc28f522..e4d7285a6 100644 --- a/explorer/htm/BeamExplorer.htm +++ b/explorer/htm/BeamExplorer.htm @@ -97,15 +97,30 @@ .blockTitle .blockHeight { font-weight: bold; } - #LinkToBlocksHeaders { + .listOfBlockHeaders { + cursor: pointer; + fill: #777ebc; + display: inline-block; + vertical-align: top; /* Needed to align text and symbol */ + } + .listOfBlockHeaders:hover { + fill: #555fb8; + } + .nextBlock, .previousBlock, .newerBlocks, .olderBlocks { + cursor: pointer; + stroke: #777ebc; display: inline-block; + vertical-align: middle; /* Needed to align text and symbol */ + } + .nextBlock:hover, .previousBlock:hover, .newerBlocks:hover, .olderBlocks:hover { + stroke: #555fb8; } - #LinkToBlocksHeaders a, .olderBlocks a, .newerBlocks a { - text-decoration-line:none; - color:#0066CC; + .nextBlock.off, .previousBlock.off, .newerBlocks.off, .olderBlocks.off { /* Dim out when disabled */ + cursor: default; + stroke: lightgrey; } - #LinkToBlocksHeaders a:hover, .olderBlocks a:hover, .newerBlocks a:hover { - color:#003399; + .nextBlock.off:hover, .previousBlock.off:hover, .newerBlocks.off:hover, .olderBlocks.off:hover { + stroke: lightgrey; } .assetName { color: black; @@ -175,7 +190,7 @@ color: #525252; white-space: nowrap; display: inline; - vertical-align: middle; /* Needed to align text and extend symbol */ + vertical-align: middle; /* Needed to align text and symbol */ } .cid a { font-family: "Lucida Console", ui-monospace, monospace; @@ -409,7 +424,7 @@ width: fit-content; /* Will have the width of its full content */ } .collapsible-checkbox { - display: none; /* Hide the actual checkbox (clicking will happen on its label only) */ + display: none; /* Hide the actual checkbox (clicking will happen on its label only) */ } /* Normal collapsible header */ .collapsible-label { @@ -582,15 +597,21 @@ - - + + + + + + + +