From 5ed3546460973f47a44403ab77493f6537e9d94d Mon Sep 17 00:00:00 2001 From: victor-tucci Date: Tue, 13 Feb 2024 16:40:17 +0530 Subject: [PATCH 1/4] setBnsRecord and resolveAddress functions added in libwalletapi --- src/wallet/api/wallet.cpp | 21 ++++++++++++++++++++- src/wallet/api/wallet.h | 1 + src/wallet/api/wallet2_api.h | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 2fc70d5c8b..fb9668ef14 100755 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1605,7 +1605,8 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectornettype(), dst_addr[i])) { + std::optional address = w->resolve_address(dst_addr[i]); + if(!cryptonote::get_account_address_from_str(info, m_wallet_ptr->nettype(), *address)) { // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 setStatusError(tr("Invalid destination address")); error = true; @@ -2123,6 +2124,24 @@ PendingTransaction *WalletImpl::bnsRenewTransaction(std::string &name,std::strin return transaction; } +EXPORT +bool WalletImpl::setBnsRecord(const std::string &name) +{ + std::string reason; + auto name_str = tools::lowercase_ascii_string(name); + if (bns::validate_bns_name(name_str, &reason)) + { + std::string name_hash_str = bns::name_to_base64_hash(name); + tools::wallet2::bns_detail detail = { + name_str, + name_hash_str}; + wallet()->set_bns_cache_record(detail); + return true; + } + setStatusError(tr("Invalid BNS name '" + name_str + "': " + reason)); + return false; +} + EXPORT PendingTransaction *WalletImpl::createSweepUnmixableTransaction() diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 017ca12291..d7a9d232c5 100755 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -205,6 +205,7 @@ class WalletImpl : public Wallet uint32_t priority=0, uint32_t m_current_subaddress_account = 0, std::set subaddr_indices = {}) override; + bool setBnsRecord(const std::string &name) override; PendingTransaction* createSweepUnmixableTransaction() override; bool submitTransaction(std::string_view filename) override; UnsignedTransaction* loadUnsignedTx(std::string_view unsigned_filename) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index d12f1c046f..1d4dfec00a 100755 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -927,6 +927,13 @@ struct Wallet uint32_t m_current_subaddress_account = 0, std::set subaddr_indices = {}) = 0; + /*! + * \brief setBnsRecord - attach an name and namehash to a wallet cache attribute + * \param name - the key + * \return true if successful, false otherwise + */ + virtual bool setBnsRecord(const std::string &name) = 0; + /*! * \brief createSweepUnmixableTransaction creates transaction with unmixable outputs. * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() From 9bcfe53797a914d62fd22e882339b47d6e66af73 Mon Sep 17 00:00:00 2001 From: deen-kakarot Date: Tue, 13 Feb 2024 18:32:56 +0530 Subject: [PATCH 2/4] Updated bns_by_owner function in libwalletapi --- src/wallet/api/wallet.cpp | 93 ++++++++++++++++++++++++++++++ src/wallet/api/wallet.h | 1 + src/wallet/api/wallet2_api.h | 10 ++++ tests/libwallet_api_tests/main.cpp | 24 ++++++++ 4 files changed, 128 insertions(+) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index fb9668ef14..4751843a28 100755 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2142,6 +2142,99 @@ bool WalletImpl::setBnsRecord(const std::string &name) return false; } +EXPORT +std::vector* WalletImpl::MyBns() const +{ + std::vector* my_bns = new std::vector; + + auto w = wallet(); + + std::vector> rpc_results; + std::vector requests(1); + + std::unordered_map cache = w->get_bns_cache(); + + for (uint32_t index = 0; index < w->get_num_subaddresses(0); ++index) + { + if (requests.back().entries.size() >= cryptonote::rpc::BNS_OWNERS_TO_NAMES::MAX_REQUEST_ENTRIES) + requests.emplace_back(); + requests.back().entries.push_back(w->get_subaddress_as_str({0, index})); + } + + rpc_results.reserve(requests.size()); + for (auto const &request : requests) + { + auto [success, result] = w->bns_owners_to_names(request); + if (!success) + { + setStatusError(tr("Connection to daemon failed when requesting BNS names")); + } + rpc_results.emplace_back(std::move(result)); + } + + auto nettype = w->nettype(); + for (size_t i = 0; i < rpc_results.size(); i++) + { + auto const &rpc = rpc_results[i]; + for (auto const &entry : rpc) + { + std::string_view name; + std::string value_bchat, value_wallet, value_belnet; + if (auto got = cache.find(entry.name_hash); got != cache.end()) + { + name = got->second.name; + //BCHAT + { + bns::mapping_value mv; + const auto type = bns::mapping_type::bchat; + if (bns::mapping_value::validate_encrypted(type, oxenc::from_hex(entry.encrypted_bchat_value), &mv) + && mv.decrypt(name, type)) + value_bchat = mv.to_readable_value(nettype, type); + } + //WALLET + { + bns::mapping_value mv; + const auto type = bns::mapping_type::wallet; + if (bns::mapping_value::validate_encrypted(type, oxenc::from_hex(entry.encrypted_wallet_value), &mv) + && mv.decrypt(name, type)) + value_wallet = mv.to_readable_value(nettype,type); + } + //BELNET + { + bns::mapping_value mv; + const auto type = bns::mapping_type::belnet; + if (bns::mapping_value::validate_encrypted(type, oxenc::from_hex(entry.encrypted_belnet_value), &mv) + && mv.decrypt(name, type)) + value_belnet = mv.to_readable_value(nettype, type); + } + } + auto &info = my_bns->emplace_back(); + info.name_hash = entry.name_hash; + if(!name.empty()) + info.name = std::string(name); + if (!value_bchat.empty()) + info.value_bchat = value_bchat; + if (!value_wallet.empty()) + info.value_wallet = value_wallet; + if (!value_belnet.empty()) + info.value_belnet = value_belnet; + info.owner = entry.owner; + if (entry.backup_owner) + info.backup_owner = *entry.backup_owner; + info.update_height = entry.update_height; + if (entry.expiration_height) + info.expiration_height = *entry.expiration_height; + if(!entry.encrypted_bchat_value.empty()) + info.encrypted_bchat_value = entry.encrypted_bchat_value; + if(!entry.encrypted_wallet_value.empty()) + info.encrypted_wallet_value = entry.encrypted_wallet_value; + if(!entry.encrypted_belnet_value.empty()) + info.encrypted_belnet_value = entry.encrypted_belnet_value; + } + } + return my_bns; +} + EXPORT PendingTransaction *WalletImpl::createSweepUnmixableTransaction() diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index d7a9d232c5..2bb404f919 100755 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -206,6 +206,7 @@ class WalletImpl : public Wallet uint32_t m_current_subaddress_account = 0, std::set subaddr_indices = {}) override; bool setBnsRecord(const std::string &name) override; + std::vector* MyBns() const override; PendingTransaction* createSweepUnmixableTransaction() override; bool submitTransaction(std::string_view filename) override; UnsignedTransaction* loadUnsignedTx(std::string_view unsigned_filename) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 1d4dfec00a..eb27743d4e 100755 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -420,6 +420,11 @@ struct stakeInfo{ bool decommissioned = false; }; +struct bnsInfo{ + uint64_t update_height, expiration_height; + std::string name_hash, name, owner, backup_owner, value_bchat, value_wallet, value_belnet, encrypted_bchat_value, encrypted_wallet_value, encrypted_belnet_value; +}; + /** * @brief Interface for wallet operations. * TODO: check if /include/IWallet.h is still actual @@ -934,6 +939,11 @@ struct Wallet */ virtual bool setBnsRecord(const std::string &name) = 0; + /*! + * \return struct bnsInfo + */ + virtual std::vector* MyBns() const = 0; + /*! * \brief createSweepUnmixableTransaction creates transaction with unmixable outputs. * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index fdb5fb1c9a..6d6f420edb 100755 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -930,6 +930,30 @@ TEST_F(WalletTest1, statusOfCountBns) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } +TEST_F(WalletTest1, bnsByOwner) +{ + Wallet::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Wallet::NetworkType::TESTNET); + ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); + std::vector data = *(wallet1->MyBns()); + + for (const auto& info : data) { + std::cout << "name_hash :" << info.name_hash << std::endl; + std::cout << "name :" << info.name << std::endl; + std::cout << "value_bchat :" << info.value_bchat << std::endl; + std::cout << "value_wallet :" << info.value_wallet << std::endl; + std::cout << "value_belnet :" << info.value_belnet << std::endl; + std::cout << "owner :" << info.owner << std::endl; + std::cout << "backup_owner :" << info.backup_owner << std::endl; + std::cout << "update_height :" << info.update_height << std::endl; + std::cout << "expiration_height :" << info.expiration_height << std::endl; + std::cout << "encrypted_bchat_value :" << info.encrypted_bchat_value << std::endl; + std::cout << "encrypted_wallet_value :" << info.encrypted_wallet_value << std::endl; + std::cout << "encrypted_belnet_value :" << info.encrypted_belnet_value << std::endl; + } + + ASSERT_TRUE(wmgr->closeWallet(wallet1)); +} + // TEST_F(WalletTest1, WalletTransactionWithMixin) // { // std::vector mixins; From 4b4de246e8f7d9604bd7c5ad03c1061f4a089d0f Mon Sep 17 00:00:00 2001 From: victor-tucci Date: Thu, 15 Feb 2024 17:28:31 +0530 Subject: [PATCH 3/4] setBnsRecord added in createBnsTransaction() --- src/wallet/api/wallet.cpp | 32 ++++++++++++++------------------ src/wallet/api/wallet2_api.h | 14 ++++++++++++-- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 4751843a28..6f2123fd77 100755 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1940,6 +1940,11 @@ PendingTransaction *WalletImpl::bnsUpdateTransaction(std::string& owner, std::st } pendingTxPostProcess(transaction); + if (good() && !setBnsRecord(name)) { + LOG_PRINT_L1(__FUNCTION__ << "BNS records are not being cached properly"); + break; + } + }catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? setStatusError(tr("daemon is busy. Please try again later.")); @@ -2210,26 +2215,17 @@ std::vector* WalletImpl::MyBns() const } auto &info = my_bns->emplace_back(); info.name_hash = entry.name_hash; - if(!name.empty()) - info.name = std::string(name); - if (!value_bchat.empty()) - info.value_bchat = value_bchat; - if (!value_wallet.empty()) - info.value_wallet = value_wallet; - if (!value_belnet.empty()) - info.value_belnet = value_belnet; + info.name = name.empty() ? "(none)" : std::string(name); + info.value_bchat = value_bchat.empty() ? "(none)" : value_bchat; + info.value_wallet = value_wallet.empty() ? "(none)" : value_wallet; + info.value_belnet = value_belnet.empty() ? "(none)" : value_belnet; info.owner = entry.owner; - if (entry.backup_owner) - info.backup_owner = *entry.backup_owner; + info.backup_owner = entry.backup_owner? *entry.backup_owner : "(none)"; info.update_height = entry.update_height; - if (entry.expiration_height) - info.expiration_height = *entry.expiration_height; - if(!entry.encrypted_bchat_value.empty()) - info.encrypted_bchat_value = entry.encrypted_bchat_value; - if(!entry.encrypted_wallet_value.empty()) - info.encrypted_wallet_value = entry.encrypted_wallet_value; - if(!entry.encrypted_belnet_value.empty()) - info.encrypted_belnet_value = entry.encrypted_belnet_value; + info.expiration_height = entry.expiration_height ? *entry.expiration_height : 0; + info.encrypted_bchat_value = entry.encrypted_bchat_value.empty() ? "(none)" : entry.encrypted_bchat_value; + info.encrypted_wallet_value = entry.encrypted_wallet_value.empty() ? "(none)" : entry.encrypted_wallet_value; + info.encrypted_belnet_value = entry.encrypted_belnet_value.empty() ? "(none)" : entry.encrypted_belnet_value; } } return my_bns; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index eb27743d4e..6418fb5b41 100755 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -421,8 +421,18 @@ struct stakeInfo{ }; struct bnsInfo{ - uint64_t update_height, expiration_height; - std::string name_hash, name, owner, backup_owner, value_bchat, value_wallet, value_belnet, encrypted_bchat_value, encrypted_wallet_value, encrypted_belnet_value; + uint64_t update_height; + uint64_t expiration_height; + std::string name_hash; + std::string name; + std::string owner; + std::string backup_owner; + std::string value_bchat; + std::string value_wallet; + std::string value_belnet; + std::string encrypted_bchat_value; + std::string encrypted_wallet_value; + std::string encrypted_belnet_value; }; /** From 0293c3ed7d6603c1829815056a65b44795b18c08 Mon Sep 17 00:00:00 2001 From: victor-tucci Date: Thu, 15 Feb 2024 17:34:03 +0530 Subject: [PATCH 4/4] additional validation did for setBnsRecord --- src/wallet/api/wallet.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 6f2123fd77..1511c26012 100755 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1826,6 +1826,11 @@ PendingTransaction *WalletImpl::createBnsTransaction(std::string& owner, std::st } pendingTxPostProcess(transaction); + if (good() && !setBnsRecord(name)) { + LOG_PRINT_L1(__FUNCTION__ << "BNS records are not being cached properly"); + break; + } + }catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? setStatusError(tr("daemon is busy. Please try again later."));