From 113dcf638f15380c52aa72310fc14cc936f71e35 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Fri, 30 Aug 2024 09:17:46 +0200 Subject: [PATCH 01/25] rebase --- src/wallet/api/wallet.cpp | 985 +++++++++++++++++++++++++++++- src/wallet/api/wallet.h | 77 ++- src/wallet/api/wallet2_api.h | 556 ++++++++++++++++- src/wallet/api/wallet_manager.cpp | 1 + 4 files changed, 1603 insertions(+), 16 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 6c50002dd1..568a9d4348 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -294,6 +294,10 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback } } + virtual void on_reorg(uint64_t height, uint64_t blocks_detached, size_t transfers_detached) { /* TODO */ } + virtual boost::optional on_get_password(const char *reason) { return boost::none; } + virtual void on_pool_tx_removed(const crypto::hash &txid) { /* TODO */ } + WalletListener * m_listener; WalletImpl * m_wallet; }; @@ -495,7 +499,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co return false; } // TODO: validate language - m_wallet->set_seed_language(language); + setSeedLanguage(language); crypto::secret_key recovery_val, secret_key; try { recovery_val = m_wallet->generate(path, password, secret_key, false, false); @@ -532,6 +536,7 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas setStatusError(error); return false; } + // TODO : Should we create a `WalletImpl` object for `view_wallet` instead of just using the `wallet2`? Figure out if that's even possible without much hassle. Then we can use the proposed `setSeedLanguage()` which also validates the language. // TODO: validate language view_wallet->set_seed_language(language); @@ -543,6 +548,9 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas view_wallet->generate(path, password, address, viewkey); // Export/Import outputs + // TODO : Depends on question from above, if `view_wallet` becomes `WalletImpl`. +// std::string outputs = exportOutputsToStr(true/*all*/); +// view_wallet->importOutputsFromStr(outputs); auto outputs = m_wallet->export_outputs(true/*all*/); view_wallet->import_outputs(outputs); @@ -556,11 +564,13 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas // copy confirmed outgoing payments std::list> out_payments; + // TODO : Depends on question from above, if `view_wallet` becomes `WalletImpl` & `getPaymentsOut()` is not implemented yet m_wallet->get_payments_out(out_payments, 0); view_wallet->import_payments_out(out_payments); // Export/Import key images // We already know the spent status from the outputs we exported, thus no need to check them again + // TODO : `exportKeyImages()` is only implemented to export to file, consider adding `exportKeyImagesToStr()` or something. auto key_images = m_wallet->export_key_images(true/*all*/); uint64_t spent = 0; uint64_t unspent = 0; @@ -572,6 +582,7 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas return false; } // Store wallet + // TODO : Depends on question from above, if `view_wallet` becomes `WalletImpl`. view_wallet->store(); return true; } @@ -718,6 +729,7 @@ bool WalletImpl::open(const std::string &path, const std::string &password) // Rebuilding wallet cache, using refresh height from .keys file m_rebuildWalletCache = true; } + // TODO NOW : CONTINUE HERE m_wallet->set_ring_database(get_default_ringdb_path(m_wallet->nettype())); m_wallet->load(path, password); @@ -761,7 +773,7 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c old_language = Language::English().get_language_name(); try { - m_wallet->set_seed_language(old_language); + setSeedLanguage(old_language); m_wallet->generate(path, password, recovery_key, true, false); } catch (const std::exception &e) { @@ -780,7 +792,7 @@ bool WalletImpl::close(bool store) // Do not store wallet with invalid status // Status Critical refers to errors on opening or creating wallets. if (status() != Status_Critical) - m_wallet->store(); + store(); else LOG_ERROR("Status_Critical - not saving wallet"); LOG_PRINT_L1("wallet::store done"); @@ -817,7 +829,11 @@ void WalletImpl::setSeedLanguage(const std::string &arg) { if (checkBackgroundSync("cannot set seed language")) return; - m_wallet->set_seed_language(arg); + + // QUESTION : We have some ~8year old TODOs stating we should validate the seed language. Will this suffice or should I make another PR for that? + // IMO it'd make sense now to add `setStatusError()` to this so it doesn't just silently do nothing. If this can stay, remove old TODOs. + if (crypto::ElectrumWords::is_valid_language(arg)) + m_wallet->set_seed_language(arg); } int WalletImpl::status() const @@ -1218,7 +1234,7 @@ bool WalletImpl::exportOutputs(const string &filename, bool all) try { - std::string data = m_wallet->export_outputs_to_str(all); + std::string data = exportOutputsToStr(all); bool r = m_wallet->save_to_file(filename, data); if (!r) { @@ -2218,13 +2234,18 @@ bool WalletImpl::checkReserveProof(const std::string &address, const std::string } } -std::string WalletImpl::signMessage(const std::string &message, const std::string &address) +std::string WalletImpl::signMessage(const std::string &message, const std::string &address, bool sign_with_view_key) { if (checkBackgroundSync("cannot sign message")) return ""; + // QUESTION : Can we get rid of this `clearStatus()`, because it's already called in `checkBackgroundSync()`, or should we leave this redundant call (I'd actually move it up to the top) so it's directly obvious that this `signMessage()` sets status error? + clearStatus(); + + tools::wallet2::message_signature_type_t sig_type = sign_with_view_key ? tools::wallet2::sign_with_view_key : tools::wallet2::sign_with_spend_key; + if (address.empty()) { - return m_wallet->sign(message, tools::wallet2::sign_with_spend_key); + return m_wallet->sign(message, sig_type); } cryptonote::address_parse_info info; @@ -2238,7 +2259,7 @@ std::string WalletImpl::signMessage(const std::string &message, const std::strin return ""; } - return m_wallet->sign(message, tools::wallet2::sign_with_spend_key, *index); + return m_wallet->sign(message, sig_type, *index); } bool WalletImpl::verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const @@ -2514,7 +2535,7 @@ bool WalletImpl::doInit(const string &daemon_address, const std::string &proxy_a // If daemon isn't synced a calculated block height will be used instead if (isNewWallet() && daemonSynced()) { LOG_PRINT_L2(__FUNCTION__ << ":New Wallet - fast refresh until " << daemonBlockChainHeight()); - m_wallet->set_refresh_from_block_height(daemonBlockChainHeight()); + setRefreshFromBlockHeight(daemonBlockChainHeight()); } if (m_rebuildWalletCache) @@ -2819,4 +2840,950 @@ uint64_t WalletImpl::getBytesSent() return m_wallet->get_bytes_sent(); } +//------------------------------------------------------------------------------------------------------------------- +std::string WalletImpl::getMultisigSeed(const std::string &seed_offset) +{ + clearStatus(); + + if (!multisig().isMultisig) + { + setStatusError(tr("Wallet is not multisig")); + return ""; + } + + epee::wipeable_string seed; + if (m_wallet) + m_wallet->get_multisig_seed(seed, seed_offset); + + return std::string(seed.data(), seed.size()); +} +//------------------------------------------------------------------------------------------------------------------- +std::pair WalletImpl::getSubaddressIndex(const std::string &address) +{ + clearStatus(); + + cryptonote::address_parse_info info; + std::pair indices{0, 0}; + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address)) + { + setStatusError(tr("Failed to parse address")); + return indices; + } + + auto index = m_wallet->get_subaddress_index(info.address); + if (!index) + setStatusError(tr("Address doesn't belong to the wallet")); + else + indices = std::make_pair(index.major, index.minor); + + return indices; +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::freeze(std::size_t idx) +{ + clearStatus(); + + try + { + m_wallet->freeze(idx); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::freeze(const std::string &key_image) +{ + try + { + freeze(getTransferIndex(key_image)); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::thaw(std::size_t idx) +{ + clearStatus(); + + try + { + m_wallet->thaw(idx); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::thaw(const std::string &key_image) +{ + try + { + thaw(getTransferIndex(key_image)); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::isFrozen(std::size_t idx) +{ + clearStatus(); + + try + { + return m_wallet->frozen(idx); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } + + return false; +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::isFrozen(const std::string &key_image) +{ + try + { + return isFrozen(getTransferIndex(key_image)); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } + + return false; +} +//------------------------------------------------------------------------------------------------------------------- +bool isFrozen(const PendingTransaction &multisig_ptxs) +{ + clearStatus(); + + try + { + checkMultisigWalletReady(m_wallet); + + tools::wallet2::multisig_tx_set multisig_tx_set; + multisig_tx_set.m_ptx = multisig_ptxs->m_pending_tx; + multisig_tx_set.m_signers = multisig_ptxs->m_signers; + + return m_wallet->frozen(multisig_tx_set); + } + catch (const exception &e) + { + setStatusError(e.what()); + } + + return false; +} +//------------------------------------------------------------------------------------------------------------------- +bool isFrozen(const std::string multisig_sign_data) +{ + clearStatus(); + + try + { + checkMultisigWalletReady(m_wallet); + + string multisig_sign_data_bin; + if (!epee::string_tools::parse_hexstr_to_binbuff(multisig_sign_data, multisig_sign_data_bin)) + throw runtime_error(tr("Failed to deserialize multisig transaction")); + + tools::wallet2::multisig_tx_set multisig_txs; + if (!m_wallet->load_multisig_tx(multisig_sign_data_bin, multisig_txs, {})) + throw runtime_error(tr("Failed to load multisig transaction")); + + return m_wallet->frozen(multisig_txs); + } + catch (const exception &e) + { + setStatusError(e.what()); + } + + return false; +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) +{ + m_wallet->create_one_off_subaddress({account_index, address_index}); + // TODO : Figure out if we need to call one of those after creating the one off subaddress. +// m_subaddress->refresh(accountIndex); +// m_subaddressAccount->refresh(); +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::isDeprecated() +{ + return m_wallet->is_deprecated(); +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::hasUnknownKeyImages() +{ + return m_wallet->has_unknown_key_images(); +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::rewrite(const std::string &wallet_name, const std::string &password) +{ + clearStatus(); + + try + { + m_wallet->rewrite(wallet_name, epee::wipeable_string(password.data(), password.size())); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) +{ + clearStatus(); + + try + { + m_wallet->write_watch_only_wallet(wallet_name, epee::wipeable_string(password.data(), password.size()), new_keys_file_name); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +std::map WalletImpl::balancePerSubaddress(std::uint32_t index_major, bool strict) +{ + return m_wallet->balance_per_subaddress(index_major, strict); +} +//------------------------------------------------------------------------------------------------------------------- +std::map>> WalletImpl::unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) +{ + return m_wallet->unlocked_balance_per_subaddress(index_major, strict); +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::isTransferUnlocked(std::uint64_t unlock_time, std::uint64_t block_height) +{ + return m_wallet->is_transfer_unlocked(unlock_time, block_height); +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::updatePoolState(std::vector> &process_txs, bool refreshed, bool try_incremental) +{ + clearStatus(); + + std::vector> process_txs_pod; + try + { + m_wallet->update_pool_state(process_txs_pod, refreshed, try_incremental); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + return; + } + + std::string tx_id; + process_txs.reserve(process_txs_pod.size()); + for (auto &tx : process_txs_pod) + { + if (!epee::string_tools::pod_to_hex(std::get<1>(tx), tx_id)) + { + setStatusError(tr("Failed to parse tx_id")); + return; + } + process_txs.push_back(std::make_tuple(std::get<0>(tx), tx_id, std::get<2>(tx))); + } +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::processPoolState(const std::vector> &txs) +{ + clearStatus(); + + std::vector> txs_pod; + crypto::hash tx_id; + for (auto &tx : txs) + { + if (!epee::string_tools::hex_to_pod(std::get<1>(tx), tx_id)) + { + setStatusError(tr("Failed to parse tx_id")); + return; + } + txs_pod.push_back(std::make_tuple(std::get<0>(tx), tx_id, std::get<2>(tx))); + } + + try + { + m_wallet->process_pool_state(txs_pod); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +std::string dumpMultisigTxToStr(const PendingTransaction &multisig_ptx) +{ + clearStatus(); + + try + { + checkMultisigWalletReady(m_wallet); + + tools::wallet2::multisig_tx_set multisig_tx_set; + multisig_tx_set.m_ptx = multisig_ptxs.m_pending_tx; + multisig_tx_set.m_signers = multisig_ptxs.m_signers; + + return m_wallet->save_multisig_tx(multisig_tx_set); + } + catch (const exception &e) + { + setStatusError(e.what()); + } + + return ""; +} +//------------------------------------------------------------------------------------------------------------------- +bool saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename) +{ + clearStatus(); + + try + { + checkMultisigWalletReady(m_wallet); + + tools::wallet2::multisig_tx_set multisig_tx_set; + multisig_tx_set.m_ptx = multisig_ptxs.m_pending_tx; + multisig_tx_set.m_signers = multisig_ptxs.m_signers; + + return m_wallet->save_multisig_tx(multisig_tx_set, filename); + } + catch (const exception &e) + { + setStatusError(e.what()); + } + + return false; +} +//------------------------------------------------------------------------------------------------------------------- +std::string dumpTxToStr(const PendingTransaction &ptxs) +{ + clearStatus(); + + std::string tx_dump = m_wallet->dump_tx_to_str(ptxs.m_pending_tx); + if (tx_dump.empty()) + { + setStatusError("Failed to dump pending tx to string"); + } + + return tx_dump; +} +//------------------------------------------------------------------------------------------------------------------- +bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) +{ + return m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set); +} +//------------------------------------------------------------------------------------------------------------------- +bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) +{ + clearStatus(); + + try + { + checkMultisigWalletReady(m_wallet); + + tools::wallet2::multisig_tx_set multisig_tx; + + if (!m_wallet->parse_multisig_tx_from_str(multisig_tx_str, multisig_tx)) + throw runtime_error(tr("Failed to parse multisig transaction from string.")); + + exported_txs.m_pending_tx = multisig_tx.m_ptx; + exported_txs.m_signers = multisig_tx.m_signers; + + return true; + } + catch (const exception &e) + { + setStatusError(e.what()); + } + + return false; +} +//------------------------------------------------------------------------------------------------------------------- +//bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) +//{ +// clearStatus(); +// +// try +// { +// checkMultisigWalletReady(m_wallet); +// +// tools::wallet2::multisig_tx_set multisig_tx; +// +// // QUESTION / TODO : How to translate the accept_func? +// if (!m_wallet->load_multisig_tx_from_file(filename, multisig_tx, accept_func)) +// throw runtime_error(tr("Failed to load multisig transaction from file.")); +// +// exported_txs.m_pending_tx = multisig_tx.m_ptx; +// exported_txs.m_signers = multisig_tx.m_signers; +// +// return true; +// } +// catch (const exception &e) +// { +// setStatusError(e.what()); +// } +// +// return false; +//} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t WalletImpl::getFeeMultiplier(std::uint32_t priority, int fee_algorithm) +{ + return m_wallet->get_fee_multiplier(priority, fee_algorithm); +} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t WalletImpl::getBaseFee() +{ + bool use_dyn_fee = useForkRules(HF_VERSION_DYNAMIC_FEE, -30 * 1); + if (!use_dyn_fee) + return FEE_PER_KB; + + return m_wallet->get_dynamic_base_fee_estimate(); +} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t WalletImpl::getMinRingSize() +{ + if (useForkRules(HF_VERSION_MIN_MIXIN_15, 0)) + return 16; + if (useForkRules(8, 10)) + return 11; + if (useForkRules(7, 10)) + return 7; + if (useForkRules(6, 10)) + return 5; + if (useForkRules(2, 10)) + return 3; + return 0; +} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t WalletImpl::adjustMixin(std::uint64_t mixin) +{ + return m_wallet->adjust_mixin(mixin); +} +//------------------------------------------------------------------------------------------------------------------- +std::uint32_t WalletImpl::adjustPriority(std::uint32_t priority) +{ + clearStatus(); + + try + { + return m_wallet->adjust_priority(priority); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(e.what()); + return m_wallet->adjust_priority(priority); + } +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::unsetRing(const std::vector &key_images) +{ + clearStatus(); + + crypto::key_image ki_pod; + std::vector key_images_pod; + for (std::string &ki : key_images) + { + if (!epee::string_tools::hex_to_pod(ki, ki_pod)) + { + // QUESTION : I think it may be a good idea to add the string that failed to parse to the error message as done below. + // Do you agree? Then I'll add it to other "Failed to parse ..." messages above, else I'll remove it from messages below. + setStatusError((boost::format(tr("Failed to parse key image: %s")) % ki).str()); + return false; + } + key_images_pod.push_back(ki_pod); + } + return m_wallet->unset_ring(key_images_pod); + // TODO : figure out how the API could handle m_ringdb and m_ringdb_key itself, to get rid of wallet2 for this function + // and we can improve error feedback, currently `m_wallet->unset_ring()` consumes the exception thrown by `m_ringdb->remove_rings()` +// try +// { +// return m_ringdb->remove_rings(getRingdbKey(), key_images_pod); +// } +// catch (const std::exception &e) +// { +// setStatusError(e.what()); +// } +// return false; +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::unsetRing(const std::string &tx_id) +{ + clearStatus(); + + crypto::hash tx_id_pod; + if (!epee::string_tools::hex_to_pod(tx_id, tx_id_pod)) + { + setStatusError((boost::format(tr("Failed to parse tx_id: %s")) % tx_id).str()); + return false; + } + + try + { + return m_wallet->unset_ring(tx_id_pod); + } + catch (const std::exception &e) + { + setStatusError(e.what()); + } + return false; +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::findAndSaveRings(bool force) +{ + clearStatus(); + + try + { + return m_wallet->find_and_save_rings(force); + } + catch (const std::exception &e) + { + setStatusError(e.what()); + } + return false; +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::isOutputBlackballed(const std::pair &output) +{ + return m_wallet->is_output_blackballed(output); +} +//------------------------------------------------------------------------------------------------------------------- +void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) +{ + clearStatus(); + + try + { + m_wallet->cold_tx_aux_import(ptx->m_pending_tx, tx_device_aux); + } + catch (const std::exception &e) + { + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- +// TODO : Somehow missed that we already had this in the API. Imo this should replace the old one because it handles error. +//bool WalletImpl::useForkRules(std::uint8_t version, std::int64_t early_blocks) +//{ +// clearStatus(); +// +// try +// { +// return m_wallet->use_fork_rules(version, early_blocks); +// } +// catch (const std::exception &e) +// { +// setStatusError((boost::format(tr("Failed to check if we use fork rules for version `%u` with `%d` early blocks. Error: %s")) % version % early_blocks % e.what()).str()); +// } +// return false; +//} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::discardUnmixableOutputs() +{ + clearStatus(); + + try + { + m_wallet->discard_unmixable_outputs(); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to discard unmixable outputs. Error: %s")) % e.what()).str()); + } +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) +{ + clearStatus(); + + crypto::hash txid_pod; + if (!epee::string_tools::hex_to_pod(txid, txid_pod)) + { + setStatusError((boost::format(tr("Failed to parse tx_id: %s")) % tx_id).str()); + return; + } + + crypto::secret_key tx_key_pod; + if (!epee::string_tools::hex_to_pod(tx_key, tx_key_pod)) + { + setStatusError((boost::format(tr("Failed to parse tx_key: %s")) % tx_key).str()); + return; + } + + std::vector additional_tx_keys_pod; + crypto::secret_key tmp_additional_tx_key_pod; + additional_tx_key_pod.reserve(additional_tx_keys.size()); + for (std::string additional_tx_key : additional_tx_keys) + { + if (!epee::string_tools::hex_to_pod(additional_tx_key, tmp_additional_tx_key_pod)) + { + setStatusError((boost::format(tr("Failed to parse additional_tx_key: %s")) % additional_tx_key).str()); + return; + } + additional_tx_keys_pod.push_back(tmp_additional_tx_key_pod); + } + + boost::optional single_destination_subaddress_pod = boost::none; + cryptonote::address_parse_info info; + if (single_destination_subaddress != boost::none) + { + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), single_destination_subaddress)) + { + setStatusError((boost::format(tr("Failed to parse subaddress: %s")) % single_destination_subaddress).str()); + return; + } + single_destination_subaddress_pod = info.address; + } + + try + { + m_wallet->setTxKey(txid_pod, tx_key_pod, additional_tx_keys_pod, info.address); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to set tx key. Error: %s")) % e.what()).str()); + } +} +//------------------------------------------------------------------------------------------------------------------- +std::string WalletImpl::getDaemonAddress() +{ + return m_wallet->get_daemon_address(); +} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t WalletImpl::getDaemonAdjustedTime() +{ + clearStatus(); + + try + { + return m_wallet->get_daemon_adjusted_time(); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to get daemon adjusted time. Error: %s")) % e.what()).str()); + } + return 0; +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::setCacheDescription(const std::string &description) +{ + m_wallet->set_description(description); + // TODO : Add ATTRIBUTE_DESCRIPTION to API and then call +// setCacheAttribute(ATTRIBUTE_DESCRIPTION, description); +} +//------------------------------------------------------------------------------------------------------------------- +std::string WalletImpl::getCacheDescription() +{ + return m_wallet->get_description(); + // TODO : Add ATTRIBUTE_DESCRIPTION to API and then call +// return getCacheAttribute(ATTRIBUTE_DESCRIPTION); +} +//------------------------------------------------------------------------------------------------------------------- +const std::pair, std::vector>& WalletImpl::getAccountTags() +{ + return m_wallet->get_account_tags(); +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::setAccountTag(const std::set &account_indices, const std::string &tag) +{ + clearStatus(); + + try + { + m_wallet->set_account_tag(account_indices, tag); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to set account tag. Error: %s")) % e.what()).str()); + } +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::setAccountTagDescription(const std::string &tag, const std::string &description) +{ + clearStatus(); + + try + { + m_wallet->set_account_tag_description(tag, description); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to set account tag description. Error: %s")) % e.what()).str()); + } +} +//------------------------------------------------------------------------------------------------------------------- +std::string WalletImpl::exportOutputsToStr(bool all, std::uint32_t start, std::uint32_t count) +{ + clearStatus(); + + try + { + return m_wallet->export_outputs_to_str(all, start, count); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to export outputs to string. Error: %s")) % e.what()).str()); + } + return ""; +} +//------------------------------------------------------------------------------------------------------------------- +std::size_t WalletImpl::importOutputsFromStr(const std::string &outputs_str) +{ + clearStatus(); + + try + { + return m_wallet->import_outputs_from_str(outputs_str); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to import outputs from string. Error: %s")) % e.what()).str()); + } + return 0; +} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t WalletImpl::getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) +{ + clearStatus(); + + try + { + return m_wallet->get_blockchain_height_by_date(year, month, day); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to get blockchain height by date. Error: %s")) % e.what()).str()); + } + return 0; +} +//------------------------------------------------------------------------------------------------------------------- +bool isSynced() +{ + clearStatus(); + + try + { + return m_wallet->is_synced(); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to check if wallet is synced. Error: %s")) % e.what()).str()); + } + return 0; +} +//------------------------------------------------------------------------------------------------------------------- +std::vector> WalletImpl::estimateBacklog(const std::vector> &fee_levels) +{ + clearStatus(); + + try + { + return m_wallet->estimate_backlog(fee_levels); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to estimate backlog. Error: %s")) % e.what()).str()); + } + return { std::make_pair(0, 0) }; +} +//------------------------------------------------------------------------------------------------------------------- +std::vector> WalletImpl::estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) +{ + clearStatus(); + + if (min_tx_weight == 0 || max_tx_weight == 0) + { + setStatusError("Invalid 0 weight"); + return { std::make_pair(0, 0) }; + } + for (std::uint64_t fee: fees) + { + if (fee == 0) + { + setStatusError("Invalid 0 fee"); + return { std::make_pair(0, 0) }; + } + } + + std::vector> fee_levels; + for (uint64_t fee: fees) + { + double our_fee_byte_min = fee / (double)min_tx_weight, our_fee_byte_max = fee / (double)max_tx_weight; + fee_levels.emplace_back(our_fee_byte_min, our_fee_byte_max); + } + return estimateBacklog(fee_levels); +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) +{ + return m_wallet->save_to_file(path_to_file, binary, is_printable); +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) +{ + return m_wallet->load_from_file(path_to_file, target_str, max_size); +} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t WalletImpl::hashTransfers(boost::optional transfer_height, std::string &hash) +{ + clearStatus(); + + try + { + return m_wallet->hash_m_transfers(transfer_height, hash); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to hash transfers. Error: %s")) % e.what()).str()); + } + return 0; +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) +{ + clearStatus(); + + try + { + m_wallet->finish_rescan_bc_keep_key_images(transfer_height, hash); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to finish rescan blockchain. Error: %s")) % e.what()).str()); + } +} +//------------------------------------------------------------------------------------------------------------------- +std::pair WalletImpl::estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) +{ + clearStatus(); + + try + { + return m_wallet->estimate_tx_size_and_weight(use_rct, n_inputs, ring_size, n_outputs, extra_size); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to estimate transaction size and weight. Error: %s")) % e.what()).str()); + } + return std::make_pair(0, 0); +} +//------------------------------------------------------------------------------------------------------------------- +std::uint64_t importKeyImages(const std::vector> &signed_key_images, size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent) +{ + clearStatus(); + + std::vector> signed_key_images_pod; + crypto::key_image tmp_key_image_pod; + crypto::signature tmp_signature_pod{}; + size_t sig_size = sizeof(crypto::signature); + + signed_key_images_pod.reserve(signed_key_images.size()); + + for (auto ski : signed_key_images) + { + if (!epee::string_tools::hex_to_pod(ski.first, tmp_key_image_pod)) + { + setStatusError((boost::format(tr("Failed to parse key_image: %s")) % ski.first).str()); + return false; + } + if (!epee::string_tools::hex_to_pod(ski.second.substr(0, sig_size/2), tmp_signature.c)) + { + setStatusError((boost::format(tr("Failed to parse signature.c: %s")) % ski.second.substr(0, sig_size/2)).str()); + return false; + } + if (!epee::string_tools::hex_to_pod(ski.second.substr(sig_size/2, sig_size), tmp_signature.r)) + { + setStatusError((boost::format(tr("Failed to parse signature.r: %s")) % ski.substr(sig_size/2, sig_size)).str()); + return false; + } + signed_key_images_pod.push_back(std::make_pair(tmp_key_image_pod, tmp_signature)); + } + + try + { + return m_wallet->importKeyImages(signed_key_images_pod, offset, spent, unspent, check_spent); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to import key images. Error: %s")) % e.what()).str()); + } + return false; +} +//------------------------------------------------------------------------------------------------------------------- +bool importKeyImages(std::vector key_images, size_t offset, boost::optional> selected_transfers = boost::none) +{ + clearStatus(); + + std::vector key_images_pod; + crypto::key_image tmp_key_image_pod; + key_images_pod.reserve(key_images.size()); + for (std::string key_image : key_images) + { + if (!epee::string_tools::hex_to_pod(key_image, tmp_key_image_pod)) + { + setStatusError((boost::format(tr("Failed to parse key_image: %s")) % key_image).str()); + return false; + } + key_images_pod.push_back(tmp_key_image_pod); + } + + try + { + return m_wallet->importKeyImages(key_images_pod, offset, selected_transfers); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to import key images. Error: %s")) % e.what()).str()); + } + return false; +} +//------------------------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------------------------------------- +// PRIVATE +//------------------------------------------------------------------------------------------------------------------- +std::size_t WalletImpl::getTransferIndex(const std::string &key_image) +{ + crypto::key_image ki; + if (!epee::string_tools::hex_to_pod(key_image, ki)) + throw runtime_error(tr("Failed to parse key image.")); + + return m_wallet->get_transfer_details(ki); +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::makeMultisigTxSet(PendingTransaction &ptx) +{ + if (!ptx->m_wallet->multisig().isMultisig) + throw runtime_error(tr("Wallet is not multisig")); + + auto multisig_tx = m_wallet->make_multisig_tx_set(ptx.m_pending_tx); + ptx.m_signers = multisig_tx.m_signers; + return true; +} +//------------------------------------------------------------------------------------------------------------------- + } // namespace diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index d48d7f130e..1428a3c6d1 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -207,7 +207,7 @@ class WalletImpl : public Wallet virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const override; virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const override; virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const override; - virtual std::string signMessage(const std::string &message, const std::string &address) override; + virtual std::string signMessage(const std::string &message, const std::string &address, bool sign_with_view_key = false) override; virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const override; virtual std::string signMultisigParticipant(const std::string &message) const override; virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const override; @@ -234,6 +234,67 @@ class WalletImpl : public Wallet virtual uint64_t getBytesReceived() override; virtual uint64_t getBytesSent() override; + std::string getMultisigSeed(const std::string &seed_offset) const override; + std::pair getSubaddressIndex(const std::string &address) const override; + void freeze(std::size_t idx) override; + void freeze(const std::string &key_image) override; + void thaw(std::size_t idx) override; + void thaw(const std::string &key_image) override; + bool isFrozen(std::size_t idx) const override; + bool isFrozen(const std::string &key_image) const override; + bool isFrozen(const PendingTransaction &multisig_ptxs) const override; + bool isFrozen(const std::string multisig_sign_data) const override; + void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) override; + bool isDeprecated() const override; + bool hasUnknownKeyImages() const override; + void rewrite(const std::string &wallet_name, const std::string &password) override; + void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) override; + std::map balancePerSubaddress(std::uint32_t index_major, bool strict) const override; + std::map>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const override; + bool isTransferUnlocked(std::uint64_t unlock_time, std::uint64_t block_height) const override; + void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; + void processPoolState(const std::vector> &txs) override; + std::string dumpMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; + bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; + std::string dumpTxToStr(const PendingTransaction &ptxs) const override; + bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; + bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; +// bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) const override; + std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; + std::uint64_t getBaseFee() const override; + std::uint64_t getMinRingSize() const override; + std::uint64_t adjustMixin(std::uint64_t mixin) const override; + std::uint32_t adjustPriority(std::uint32_t priority) const override; + bool unsetRing(const std::vector &key_images) override; + bool unsetRing(const std::string &tx_id) override; + bool findAndSaveRings(bool force = true) override; + bool isOutputBlackballed(const std::pair &output) const override; + void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const override; +// void coldSignTx(const std::vector& ptx_vector, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const override; +// const wallet2::transfer_details &getTransferDetails(std::size_t idx) const override; + void discardUnmixableOutputs() override; + void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) override; + std::string getDaemonAddress() const override; + std::uint64_t getDaemonAdjustedTime() const override; + void setCacheDescription(const std::string &description) override; + std::string getCacheDescription() const override; + const std::pair, std::vector>& getAccountTags() override; + void setAccountTag(const std::set &account_indices, const std::string &tag) override; + void setAccountTagDescription(const std::string &tag, const std::string &description) override; + std::string exportOutputsToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const override; + std::size_t importOutputsFromStr(const std::string &outputs_str) override; + std::uint64_t getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const override; + bool isSynced() const override; + std::vector> estimateBacklog(const std::vector> &fee_levels) const override; + std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const override; + bool saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const override; + bool loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const override; + std::uint64_t hashTransfers(boost::optional transfer_height, std::string &hash) const override; + void finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) override; + std::pair estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) const override; + std::uint64_t importKeyImages(const std::vector> &signed_key_images, size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) override; + bool importKeyImages(std::vector key_images, size_t offset = 0, boost::optional> selected_transfers = boost::none) override; + private: void clearStatus() const; void setStatusError(const std::string& message) const; @@ -248,6 +309,20 @@ class WalletImpl : public Wallet bool doInit(const std::string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit = 0, bool ssl = false); bool checkBackgroundSync(const std::string &message) const; + // QUESTION : Should I remove the private functions from this PR and work on them in another one? + /** + * brief: getTransferIndex - get the index of a stored transfer + * param: key_image - key image of transfer + * return: index in transfer storage + */ + std::size_t getTransferIndex(const std::string &key_image) const; + // TODO : consider changing the name and/or move to PendingTransaction + /** + * brief: makeMultisigTxSet - add multisig signers to pending transaction + * param: ptx - + */ + void makeMultisigTxSet(PendingTransaction &ptx) const; + private: friend class PendingTransactionImpl; friend class UnsignedTransactionImpl; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index c374d1574b..e222716844 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -40,6 +40,8 @@ #include #include +#include "cryptonote_basic/cryptonote_basic.h" + // Public interface for libwallet library namespace Monero { @@ -1043,12 +1045,15 @@ struct Wallet virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const = 0; virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const = 0; - /* - * \brief signMessage - sign a message with the spend private key - * \param message - the message to sign (arbitrary byte data) - * \return the signature - */ - virtual std::string signMessage(const std::string &message, const std::string &address = "") = 0; + /** + * brief: signMessage - sign a message with your private key (SigV2) + * param: message - message to sign (arbitrary byte data) + * param: address - address used to sign the message (use main address if empty) + * param: sign_with_view_key - (default: false, use spend key to sign) + * return: proof type prefix + base58 encoded signature, else empty string + * note: sets status error on fail + */ + virtual std::string signMessage(const std::string &message, const std::string &address = "", bool sign_with_view_key = false) = 0; /*! * \brief verifySignedMessage - verify a signature matches a given message * \param message - the message (arbitrary byte data) @@ -1144,6 +1149,545 @@ struct Wallet //! get bytes sent virtual uint64_t getBytesSent() = 0; + + /** + * brief: getMultisigSeed - get mnemonic seed phrase for multisig wallet + * param: seed_offset - passphrase + * return: mnemonic seed phrase if succeeded, else empty string + * note: sets status error on fail + */ + virtual std::string getMultisigSeed(const std::string &seed_offset) const = 0; + // TODO : Would this better fit in one of `Subaddress`/`SubaddressAccount` classes? + /** + * brief: getSubaddressIndex - get major and minor index of provided subaddress + * param: address - main- or sub-address to get the index from + * return: [major_index, minor_index] if succeeded + * note: sets status error on fail + */ + virtual std::pair getSubaddressIndex(const std::string &address) const = 0; + /** + * brief: freeze - freeze enote "so they don't appear in balance, nor are considered when creating a transaction, etc." (https://github.com/monero-project/monero/pull/5333) + * param: idx - index of enote in `m_transfers` + * param: key_image - key image of enote + * note: sets status error on fail + */ + virtual void freeze(std::size_t idx) = 0; + virtual void freeze(const std::string &key_image) = 0; + // QUESTION : Should we add the option to freeze by tx_id? Meaning: freeze all enotes that we received by a single transaction. +// virtual void freeze(const std::string &tx_id) = 0; + /** + * brief: thaw - thaw enote that is frozen, so it appears in balance and can be spent in a transaction + * param: idx - index of enote in `m_transfers` + * param: key_image - key image of enote + * note: sets status error on fail + */ + virtual void thaw(std::size_t idx) = 0; + virtual void thaw(const std::string &key_image) = 0; + // QUESTION : Should we add the option to thaw by tx_id? Meaning: thaw all enotes that we received by a single transaction. +// virtual void thaw(const std::string &tx_id) = 0; + /** + * brief: isFrozen - check if enote is frozen + * param: idx - index of enote in `m_transfers` + * param: key_image - key image of enote + * QUESTION : Which approach should we use? We probably don't need both. Or are there other suggestions? (See WalletImpl::isFrozen for implementation) + * Approach 1 : Use PendingTransaction, which just like tools::wallet2::multisig_tx_set has a vector of pending txs and an unordered set of signers pub keys. + * Approach 2 : Use the encrypted hex string generated with tools::wallet2::save_multisig_tx(). This approach is already used in WalletImpl::restoreMultisigTransaction. + * __________ Approach 1 __________ + * param: multisig_ptxs - + * __________ Approach 2 __________ + * param: multisig_sign_data - + * ________________________________ + * return : true if enote is frozen, else false + * note: sets status error on fail + */ + virtual bool isFrozen(std::size_t idx) const = 0; + virtual bool isFrozen(const std::string &key_image) const = 0; + virtual bool isFrozen(const PendingTransaction &multisig_ptxs) const = 0; + virtual bool isFrozen(const std::string multisig_sign_data) const = 0; + // QUESTION : Should we add the following function, which returns strings containing the key image for every frozen enote? I think it can be useful +// virtual std::vector getAllFrozenEnotes() const = 0; + // TODO : Would this better fit in one of `Subaddress`/`SubaddressAccount` classes? + /** + * brief: createOneOffSubaddress - create a subaddress for given index + * param: account_index - major index + * param: address_index - minor index + */ + virtual void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) = 0; + /** + * brief: isDeprecated - check if wallet file format is deprecated + * return: true if wallet file is old format (before becoming JSON), else false + */ + virtual bool isDeprecated() const = 0; + /** + * brief: hasUnknownKeyImages - check if any enotes have missing key images + * return: true if any stored enote is missing its key image, else false + */ + virtual bool hasUnknownKeyImages() const = 0; + /** + * brief: rewrite - rewrite the wallet file for wallet update + * param: wallet_name - name of the wallet file (should exist) + * param: password - wallet password + * note: sets status error on fail + */ + virtual void rewrite(const std::string &wallet_name, const std::string &password) = 0; + // QUESTION : Should we change this function from the current behavior in wallet2, so `wallet_name` is just the name of the new wallet instead of changing the `m_wallet_file` for the current wallet? + /** + * brief: writeWatchOnlyWallet - create a new watch-only wallet file with view keys from current wallet + * param: wallet_name - name of the current wallet file + * param: password - password for new watch-only wallet + * outparam: new_keys_file_name - wallet_name + "-watchonly.keys" + * note: sets status error on fail + */ + virtual void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) = 0; + /** + * brief: balancePerSubaddress - get balance for each subaddress in given account + * param: index_major - account index + * param: strict - + * return: [minor subaddress index: amount, ... ] + */ + virtual std::map balancePerSubaddress(std::uint32_t index_major, bool strict) const = 0; + /** + * brief: unlockedBalancePerSubaddress - get unlocked balance for each subaddresses in given account + * param: index_major - account index + * param: strict - + * return: [minor subaddress index: {amount, {blocks to unlock, time to unlock} }, ... ] + */ + virtual std::map>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const = 0; + // QUESTION : Can anyone help with this comment? There are other ones I'm not satisfied with, so if you have a better suggestion I'll change them. + /** + * brief: isTransferUnlocked - check if transfer is unlocked + * param: unlock_time - + * param: block_height - + * return: true if transfer is unlocked, else false + */ + virtual bool isTransferUnlocked(std::uint64_t unlock_time, std::uint64_t block_height) const = 0; + /** + * brief: updatePoolState - + * outparam: process_txs - [ [tx, tx_id, double_spend_seen], ... ] + * param: refreshed - (default: false) + * param: try_incremental - (default: false) + * note: sets status error on fail + * This public method is typically called to make sure that the wallet's pool state is up-to-date by + * clients like simplewallet and the RPC daemon. Before incremental update this was the same method + * that 'refresh' also used, but now it's more complicated because for the time being we support + * the "old" and the "new" way of updating the pool and because only the 'getblocks' call supports + * incremental update but we don't want any blocks here. + * + * simplewallet does NOT update the pool info during automatic refresh to avoid disturbing interactive + * messages and prompts. When it finally calls this method here "to catch up" so to say we can't use + * incremental update anymore, because with that we might miss some txs altogether. + */ + virtual void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) = 0; + /** + * brief: processPoolState - + * param: txs - [ [tx, tx_id, double_spend_seen], ... ] + * note: sets status error on fail + */ + virtual void processPoolState(const std::vector> &txs) = 0; + // TODO / QUESTION : How to translate the following types to a standard type for the API? + // - tools::wallet2::transfer_details & tools::wallet2::transfer_container (vector of tools::wallet2::transfer_details) + // - tools::wallet2::payment_details + // - tools::wallet2::confirmed_transfer_details + // - tools::wallet2::pool_payment_details + // - tools::wallet2::signed_tx + // - cryptonote::address_parse_info +// TODO : wallet2::transfer_container + /** + * brief: getTransfers - get all transfers + * outparam: transfers - + */ +// virtual void getTransfers(wallet2::transfer_container& transfers) const = 0; +// TODO : wallet2::payment_details + /** + * brief: getPayments - get incoming transfers + * param: payment_id - + * param: payments - + * param: min_height - + * param: subaddr_account - + * param: subaddr_indices - + */ +// virtual void getPayments(const std::string &payment_id, std::list &payments, std::uint64_t min_height, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; +// TODO : wallet2::payment_details + /** + * brief: getPayments - get incoming transfers + * param: payments - + * param: max_height - + */ +// virtual void getPayments(std::list> &payments, std::uint64_t min_height, std::uint64_t max_height, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; +// TODO : wallet2::confirmed_transfer_details + /** + * brief: getPaymentsOut - get outgoing transfers + * param: confirmed_payments - + */ +// virtual void getPaymentsOut(std::list> &confirmed_payments, std::uint64_t min_height, std::uint64_t max_height, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; +// TODO : wallet2::unconfirmed_transfer_details + /** + * brief: getUnconfirmedPaymentsOut - get unconfirmed transfers + * param: unconfirmed_payments - + */ +// virtual void getUnconfirmedPaymentsOut(std::list> &unconfirmed_payments, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; +// TODO : wallet2::pool_payment_details + /** + * brief: getUnconfirmedPayments - get pending transfers, currently in pool + * param: unconfirmed_payments - + */ +// virtual void getUnconfirmedPayments(std::list> &unconfirmed_payments, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; + /** + * brief: dumpMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction + * param: multisig_ptx - multisig pending transaction + * return: encrypted tx data as hex string if succeeded, else empty string + * note: sets status error on fail + */ + virtual std::string dumpMultisigTxToStr(const PendingTransaction &multisig_ptx) const = 0; + /** + * brief: saveMultisigTx - save a multisig pending transaction to file + * param: multisig_ptx - multisig pending transaction + * param: filename - + * return: true if succeeded + * note: sets status error on fail + */ + virtual bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const = 0; + /** + * brief: dumpTxToStr - get the encrypted data from a vector of pending transactions as hex string + * param: ptxs - + * return: unsigned tx data as encrypted hex string if succeeded, else empty string + */ + virtual std::string dumpTxToStr(const PendingTransaction &ptxs) const = 0; + /** + * brief: parseUnsignedTxFromStr - get an unsigned transaction set from encrypted unsigned transaction as hex string + * param: unsigned_tx_str - encrypted hex string + * outparam: exported_txs - + * return: true if succeeded + */ + virtual bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const = 0; +// TODO : wallet2::signed_tx_set + /** + * brief: signTxDumpToStr - get a signed transaction set from unsigned transaction set + * param: exported_txs - + * outparam: ptx - + * outparam: signed_txes - + * return: signed tx data as encrypted hex string + */ +// virtual std::string signTxDumpToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx, signed_tx_set &signed_txes) const = 0; +// TODO : accept_func with wallet2::signed_tx_set + /** + * brief: loadTx - load pending transactions from a file + * param: signed_filename - + * outparam: ptx - + * param: accept_func - callback function to verify the transaction + * return: true if succeeded + */ +// virtual bool loadTx(const std::string &signed_filename, PendingTransaction &ptx, std::function accept_func) const = 0; +// TODO : accept_func with wallet2::signed_tx_set + /** + * brief: parseTxFromStr - get transactions from encrypted signed transaction as hex string + * param: signed_tx_str - + * outparam: ptx - + * param: accept_func - callback function to verify the transaction + * return: true if succeeded + */ +// virtual bool parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx, std::function accept_func) const = 0; + /** + * brief: parseMultisigTxFromStr - get pending multisig transaction from encrypted unsigned multisig transaction as hex string + * param: multisig_tx_str - + * outparam: exported_txs - + * return: true if succeeded + * note: sets status error on fail + */ + virtual bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const = 0; +// TODO : accept_func with wallet2::multisig_tx_set + /** + * brief: loadMultisigTxFromFile - load a multisig transaction set from a file + * param: multisig_tx_str - + * outparam: exported_txs - + * return: true if succeeded + */ +// virtual bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) const = 0; +// TODO : accept_func with wallet2::multisig_tx_set + /** + * brief: signMultisigTxFromFile - load a multisig transaction set from a file, sign it and store to a file + * param: filename - load from and store to file with this filename + * outparam: txids - transaction ids of signed transactions + * param: accept_func - callback function to verify the transaction + * return: true if succeeded + */ +// virutal bool signMultisigTxFromFile(const std::string &filename, std::vector &txids, std::function accept_func) const = 0; + /** + * brief: getFeeMultiplier - + * param: priority - + * param: fee_algorithm - + * return: fee multiplier + */ + virtual std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const = 0; + /** + * brief: getBaseFee - + * return: dynamic base fee estimate if using dynamic fee, else FEE_PER_KB + */ + virtual std::uint64_t getBaseFee() const = 0; + /** + * brief: getMinRingSize - get the minimum allowed ring size + * return: min ring size + */ + virtual std::uint64_t getMinRingSize() const = 0; + // TODO : Should we make this static? + /** + * brief: adjustMixin - adjust mixin to fit into min and max ring size + * param: mixin - + * return: adjusted mixin + */ + virtual std::uint64_t adjustMixin(std::uint64_t mixin) const = 0; + /** + * brief: adjustPriority - adjust priority depending on how "full" last N blocks are + * param: priority - + * return: adjusted priority + * note: sets status error on fail + */ + virtual std::uint32_t adjustPriority(std::uint32_t priority) const = 0; + // QUESTION : Can anyone help with these comments? I looked at the command descriptions in `simplewallet::simplewallet()`, but I think they're too vague and imo they don't really help understand what these functions do. + /** + * brief: unsetRing - + * param: key_images - + * param: tx_id - + * return: true if succeeded + * note: sets status error on fail + */ + virtual bool unsetRing(const std::vector &key_images) = 0; + virtual bool unsetRing(const std::string &tx_id) = 0; + /** + * brief: findAndSaveRings - + * param: force - force save (default: true) + * return: true if succeeded + * note: sets status error on fail + */ + virtual bool findAndSaveRings(bool force = true) = 0; + // QUESTION : Other "blackball" functions that were implemented before this PR use std::string for the output index, should we stay consistent with that? Else I'd prefer using a pair of uint64_t. + /** + * brief: isOutputBlackballed - + * param: output - [amount, offset] for ringdb index + * return: true if succeeded + * note: sets status error on fail + */ + virtual bool isOutputBlackballed(const std::pair &output) const = 0; + // QUESTION : Any suggestion for the two comments below? + /** + * brief: coldTxAuxImport - + * param: ptx - + * param: tx_device_aux - + * note: sets status error on fail + */ + virtual void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const = 0; +// TODO : wallet2::signed_tx_set & cryptonote::address_parse_info + /** + * brief: coldSignTx - + * param: ptx - + * param: exported_txs - + * param: dsts_info - + * param: tx_device_aux - + */ +// virtual void coldSignTx(const PendingTransaction &ptx, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const = 0; + // TODO : this already exists, remove after checking + /** + * brief: useForkRules - check if the wallet uses the rules for hard fork version at current block height - early_blocks + * param: version - hard fork version + * param: early_blocks - + * return: true if fork rules are used + * note: sets status error on fail + */ +// virtual bool useForkRules(std::uint8_t version, std::int64_t early_blocks) const = 0; +// TODO : wallet2::transfer_details + /** + * brief: getTransferDetails - + * param: idx - index in transfer storage + * return: transfer details for given index + * note: sets status error on fail + */ +// virtual const wallet2::transfer_details &getTransferDetails(std::size_t idx) const = 0; + /** + * brief: discardUnmixableOutputs - freeze all unmixable outputs + * note: sets status error on fail + */ + virtual void discardUnmixableOutputs() = 0; + /** + * brief: setTxKey - set the transaction key (r) for a given in case the tx was made by some other device or 3rd party wallet + * param: txid - + * param: tx_key - secret transaction key r + * param: additional_tx_keys - + * param: single_destination_subaddress - + * note: sets status error on fail + */ + // QUESTION : There were some cases already where I wished to have boost::optional in here. I have no explicit example, but in general e.g. for functions that return a bool, but have to return early on error, it would be cleaner to return boost::none instead of true/false, because the API user could forget to check the error status and may use an incorrect value. Similar for uint*_t, where we can't use e.g. -1 on error. + // If we add access to boost::optional revisit all new functions to see which would benefit from it. + virtual void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) = 0; + /** + * brief: getDaemonAddress - + * return: daemon address + */ + virtual std::string getDaemonAddress() const = 0; + /** + * brief: getDaemonAdjustedTime - + * return: daemon adjusted time + * note: sets status error on fail + */ + virtual std::uint64_t getDaemonAdjustedTime() const = 0; + /** + * brief: setCacheDescription - set wallet cache attribute with key ATTRIBUTE_DESCRIPTION + * param: description - + */ + virtual void setCacheDescription(const std::string &description) = 0; + /** + * brief: getCacheDescription - get wallet cache attribute with key ATTRIBUTE_DESCRIPTION + * return: description + */ + virtual std::string getCacheDescription() const = 0; + /** + * brief: getAccountTags - get the list of registered account tags + * return: first.Key=(tag's name), first.Value=(tag's label), second[i]=(i-th account's tag) + */ + virtual const std::pair, std::vector>& getAccountTags() = 0; + /** + * brief: setAccountTag - set a tag to a set of subaddress accounts by index + * param: account_index - major index + * param: tag - + * note: sets status error on fail + */ + virtual void setAccountTag(const std::set &account_indices, const std::string &tag) = 0; + /** + * brief: setAccountTagDescription - set a description for a tag, tag must already exist + * param: tag - + * param: description - + * note: sets status error on fail + */ + virtual void setAccountTagDescription(const std::string &tag, const std::string &description) = 0; + /** + * brief: exportOutputsToStr - export outputs and return encrypted data + * param: all - go from `start` for `count` outputs if true, else go incremental from last exported output for `count` outputs (default: false) + * param: start - offset index in transfer storage, needs to be 0 for incremental mode (default: 0) + * param: count - try to export this amount of outputs (default: 0xffffffff) + * return: encrypted data as hex string if succeeded, else empty string + * note: sets status error on fail + */ + virtual std::string exportOutputsToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const = 0; + /** + * brief: importOutputsFromStr - import outputs from encrypted hex string + * param: outputs_str - outputs data as encrypted hex string + * return: total size of transfer storage + * note: sets status error on fail + */ + virtual std::size_t importOutputsFromStr(const std::string &outputs_str) = 0; + /** + * brief: getBlockchainHeightByDate - + * param: year - + * param: month - in range 1-12 + * param: day - in range 1-31 + * return: blockchain height + * note: sets status error on fail + */ + virtual std::uint64_t getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const = 0; + /** + * brief: isSynced - + * return: true if wallet is synced with daemon, else false + * note: sets status error on fail + */ + virtual bool isSynced() const = 0; + // QUESTION : Can anyone help with these comments? + /** + * brief: estimateBacklog - + * param: fee_levels - [ [fee per byte min, fee per byte max], ... ] + * param: min_tx_weight - + * param: max_tx_weight - + * param: fees - + * return: [ [number of blocks min, number of blocks max], ... ] + * note: sets status error on fail + */ + virtual std::vector> estimateBacklog(const std::vector> &fee_levels) const = 0; + virtual std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const = 0; +// TODO : mms::multisig_wallet_state - from a quick search for get_multisig_wallet_state in simplewallet.cpp this will be complicated to replace + /** + * brief: getMultisigWalletState - + * return: + */ +// virtual mms::multisig_wallet_state getMultisigWalletState() const = 0; + /** + * brief: saveToFile - save hex string to file + * param: path_to_file - file name + * param: binary - hex string data + * param: is_printable - (default: false) + * return: true if succeeded + */ + virtual bool saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const = 0; + /** + * brief: loadFromFile - load hex string from file + * param: path_to_file - file name + * outparam: target_str - hex string data + * param: max_size - maximum size in bytes (default: 1000000000) + * return: true if succeeded + */ + virtual bool loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const = 0; + /** + * brief: hashTransfers - + * param: transfer_height - + * outparam: hash - hash of all transfers from wallet transfer storage up until `transfer_height` + * return: amount of hashed transfers + * note: sets status error on fail + */ + virtual std::uint64_t hashTransfers(boost::optional transfer_height, std::string &hash) const = 0; + /** + * brief: finishRescanBcKeepKeyImages - + * param: transfer_height - + * param: hash - + * note: sets status error on fail + */ + virtual void finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) = 0; +// QUESTION : Should we just `#include "rpc/core_rpc_server_commands_defs.h"` for cryptonote::public_node? +// TODO : cryptonote::public_node + /** + * brief: getPublicNodes - + * param: white_only - include gray nodes if false (default: true) + * return: vector of public nodes + * note: sets status error on fail + */ +// virtual std::vector getPublicNodes(bool white_only = true) const = 0; + /** + * brief: estimateTxSizeAndWeight - + * param: use_rct - + * param: n_inputs - number of inputs + * param: ring_size - + * param: n_outputs - number of outputs + * param: extra_size - size of tx_extra + * return: [estimated tx size, estimated tx weight] + * note: sets status error on fail + */ + virtual std::pair estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) const = 0; + /** + * brief: importKeyImages - + * param: signed_key_images - [ [key_image, signature c || signature r], ... ] + * param: offset - offset in local transfer storage + * outparam: spent - total spent amount of the wallet + * outparam: unspent - total unspent amount of the wallet + * param: check_spent - + * return: blockchain height of last signed key image, can be 0 if height unknown + * note: sets status error on fail + */ + virtual std::uint64_t importKeyImages(const std::vector> &signed_key_images, size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) = 0; + /** + * brief: importKeyImages - + * param: key_images - + * param: offset - offset in local transfer storage + * param: selected_transfers - + * return: true if succeeded + * note: sets status error on fail + */ + virtual bool importKeyImages(std::vector key_images, size_t offset=0, boost::optional> selected_transfers = boost::none) = 0; +// TODO : wallet2::signed_tx_set + /** + * brief: importKeyImages - + * param: signed_tx - + * param: offset - offset in local transfer storage + * param: only_selected_transfers - + * return: true if succeeded + * note: sets status error on fail + */ +// virtual bool importKeyImages(signed_tx_set & signed_tx, size_t offset=0, bool only_selected_transfers = false) = 0; }; /** diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 97895990b2..d013aaf825 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -231,6 +231,7 @@ std::string WalletManagerImpl::errorString() const return m_errorString; } +// TODO : figure out if this is a sufficient replacement for wallet2::set_daemon() void WalletManagerImpl::setDaemonAddress(const std::string &address) { m_http_client.set_server(address, boost::none); From 12c35d1316eac547187c5376ce8f0afe14c78e77 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Sun, 1 Sep 2024 11:06:00 +0200 Subject: [PATCH 02/25] use API functions instead of wallet2 where possible --- src/wallet/api/wallet.cpp | 92 +++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 568a9d4348..68ad4fc081 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -61,7 +61,7 @@ using namespace cryptonote; #define LOCK_REFRESH() \ bool refresh_enabled = m_refreshEnabled; \ m_refreshEnabled = false; \ - m_wallet->stop(); \ + stop(); \ m_refreshCV.notify_one(); \ boost::mutex::scoped_lock lock(m_refreshMutex); \ boost::mutex::scoped_lock lock2(m_refreshMutex2); \ @@ -80,7 +80,7 @@ using namespace cryptonote; setStatusError(tr("HW wallet cannot use background sync")); \ return false; \ } \ - if (m_wallet->watch_only()) \ + if (watchOnly()) \ { \ setStatusError(tr("View only wallet cannot use background sync")); \ return false; \ @@ -485,6 +485,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co m_recoveringFromDevice = false; bool keys_file_exists; bool wallet_file_exists; + // QUESTION : I think we can change `WalletManagerImpl::walletExists()` which returns true if `key_file_exists` is true, to take the same outparams as `tools::wallet2::wallet_exists()` (but make them optional) and make the method static. Or do you think it's easier/cleaner to add `WalletImpl::walletExists()` with the described behaviour and leave the one in `WalletManagerImpl` as is? tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); LOG_PRINT_L3("wallet_path: " << path << ""); LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha @@ -524,6 +525,7 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas bool keys_file_exists; bool wallet_file_exists; + // QUESTION / TODO : same as above tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); LOG_PRINT_L3("wallet_path: " << path << ""); LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha @@ -724,12 +726,14 @@ bool WalletImpl::open(const std::string &path, const std::string &password) // Check if wallet cache exists bool keys_file_exists; bool wallet_file_exists; + // QUESTION / TODO : same as above, actually here we could just do: +// if(!WalletManagerImpl::walletExists(path)){ + // even though we check if `wallet_file_exists`, the comment states that we're actually interested in the .keys file. tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); if(!wallet_file_exists){ // Rebuilding wallet cache, using refresh height from .keys file m_rebuildWalletCache = true; } - // TODO NOW : CONTINUE HERE m_wallet->set_ring_database(get_default_ringdb_path(m_wallet->nettype())); m_wallet->load(path, password); @@ -798,7 +802,7 @@ bool WalletImpl::close(bool store) LOG_PRINT_L1("wallet::store done"); } LOG_PRINT_L1("Calling wallet::stop..."); - m_wallet->stop(); + stop(); LOG_PRINT_L1("wallet::stop done"); m_wallet->deinit(); result = true; @@ -832,6 +836,7 @@ void WalletImpl::setSeedLanguage(const std::string &arg) // QUESTION : We have some ~8year old TODOs stating we should validate the seed language. Will this suffice or should I make another PR for that? // IMO it'd make sense now to add `setStatusError()` to this so it doesn't just silently do nothing. If this can stay, remove old TODOs. + // Update : Actually after rebasing we now already set the status in the `checkBackgroundSync()` call above. if (crypto::ElectrumWords::is_valid_language(arg)) m_wallet->set_seed_language(arg); } @@ -1082,8 +1087,6 @@ bool WalletImpl::synchronized() const bool WalletImpl::refresh() { clearStatus(); - //TODO: make doRefresh return bool to know whether the error occured during refresh or not - //otherwise one may try, say, to send transaction, transfer fails and this method returns false doRefresh(); return status() == Status_Ok; } @@ -1156,6 +1159,7 @@ bool WalletImpl::submitTransaction(const string &fileName) { return false; std::unique_ptr transaction(new PendingTransactionImpl(*this)); + // TODO : use WalletImpl::loadTx() if ready bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx); if (!r) { setStatus(Status_Ok, tr("Failed to load transaction from file")); @@ -1172,7 +1176,7 @@ bool WalletImpl::submitTransaction(const string &fileName) { bool WalletImpl::exportKeyImages(const string &filename, bool all) { - if (m_wallet->watch_only()) + if (watchOnly()) { setStatusError(tr("Wallet is view only")); return false; @@ -1235,7 +1239,7 @@ bool WalletImpl::exportOutputs(const string &filename, bool all) try { std::string data = exportOutputsToStr(all); - bool r = m_wallet->save_to_file(filename, data); + bool r = saveToFile(filename, data); if (!r) { LOG_ERROR("Failed to save file " << filename); @@ -1265,7 +1269,7 @@ bool WalletImpl::importOutputs(const string &filename) } std::string data; - bool r = m_wallet->load_from_file(filename, data); + bool r = loadFromFile(filename, data); if (!r) { LOG_ERROR("Failed to read file: " << filename); @@ -1275,7 +1279,9 @@ bool WalletImpl::importOutputs(const string &filename) try { - size_t n_outputs = m_wallet->import_outputs_from_str(data); + size_t n_outputs = importOutputsFromStr(data); + if (status() != Status_Ok) + throw runtime_error(errorString()); LOG_PRINT_L2(std::to_string(n_outputs) << " outputs imported"); } catch (const std::exception &e) @@ -1492,7 +1498,7 @@ string WalletImpl::makeMultisig(const vector& info, const uint32_t thres try { clearStatus(); - if (m_wallet->get_multisig_status().multisig_is_active) { + if (multisig().isMultisig) { throw runtime_error("Wallet is already multisig"); } @@ -1639,10 +1645,16 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectoradjust_priority(static_cast(priority)); - PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); + uint32_t adjusted_priority = adjustPriority(static_cast(priority)); + // TODO : Consider adding a function that returns `status() == Status_Ok`: +// if (!isStatusOk()) + if (status() != Status_Ok) + { + return transaction; + } + do { if (checkBackgroundSync("cannot create transactions")) break; @@ -1694,7 +1706,7 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectorget_num_subaddresses(subaddr_account); ++index) + for (uint32_t index = 0; index < numSubaddresses(subaddr_account); ++index) subaddr_indices.insert(index); } } @@ -1707,8 +1719,8 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector 0 ? mixin_count : m_wallet->default_mixin(); - fake_outs_count = m_wallet->adjust_mixin(mixin_count); + size_t fake_outs_count = mixin_count > 0 ? mixin_count : defaultMixin(); + fake_outs_count = adjustMixin(mixin_count); if (amount) { transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, @@ -1722,9 +1734,7 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectormake_multisig_tx_set(transaction->m_pending_tx); - transaction->m_pending_tx = tx_set.m_ptx; - transaction->m_signers = tx_set.m_signers; + makeMultisigTxSet(transaction); } } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? @@ -1902,17 +1912,17 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vectorestimate_fee( - m_wallet->use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0), - m_wallet->use_fork_rules(4, 0), + useForkRules(HF_VERSION_PER_BYTE_FEE, 0), + useForkRules(4, 0), 1, - m_wallet->get_min_ring_size() - 1, + getMinRingSize() - 1, destinations.size() + 1, extra_size, - m_wallet->use_fork_rules(8, 0), - m_wallet->use_fork_rules(HF_VERSION_CLSAG, 0), - m_wallet->use_fork_rules(HF_VERSION_BULLETPROOF_PLUS, 0), - m_wallet->use_fork_rules(HF_VERSION_VIEW_TAGS, 0), - m_wallet->get_base_fee(priority), + useForkRules(8, 0), + useForkRules(HF_VERSION_CLSAG, 0), + useForkRules(HF_VERSION_BULLETPROOF_PLUS, 0), + useForkRules(HF_VERSION_VIEW_TAGS, 0), + getBaseFee(priority), m_wallet->get_fee_quantization_mask()); } @@ -2539,7 +2549,7 @@ bool WalletImpl::doInit(const string &daemon_address, const std::string &proxy_a } if (m_rebuildWalletCache) - LOG_PRINT_L2(__FUNCTION__ << ": Rebuilding wallet cache, fast refresh until block " << m_wallet->get_refresh_from_block_height()); + LOG_PRINT_L2(__FUNCTION__ << ": Rebuilding wallet cache, fast refresh until block " << getRefreshFromBlockHeight()); if (Utils::isAddressLocal(daemon_address)) { this->setTrustedDaemon(true); @@ -2852,10 +2862,17 @@ std::string WalletImpl::getMultisigSeed(const std::string &seed_offset) } epee::wipeable_string seed; - if (m_wallet) - m_wallet->get_multisig_seed(seed, seed_offset); - - return std::string(seed.data(), seed.size()); + try + { + if (m_wallet->get_multisig_seed(seed, seed_offset)) + return std::string(seed.data(), seed.size()); + } + catch (const std::exception &e) + { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + setStatusError(string(tr("Failed to get multisig seed: ")) + e.what()); + } + return ""; } //------------------------------------------------------------------------------------------------------------------- std::pair WalletImpl::getSubaddressIndex(const std::string &address) @@ -3294,9 +3311,9 @@ std::uint32_t WalletImpl::adjustPriority(std::uint32_t priority) catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); - return m_wallet->adjust_priority(priority); + setStatusError(string(tr("Failed to adjust priority: ")) + e.what()); } + return 0; } //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::unsetRing(const std::vector &key_images) @@ -3461,7 +3478,7 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co try { - m_wallet->setTxKey(txid_pod, tx_key_pod, additional_tx_keys_pod, info.address); + m_wallet->set_tx_key(txid_pod, tx_key_pod, additional_tx_keys_pod, info.address); } catch (const std::exception &e) { @@ -3725,7 +3742,7 @@ std::uint64_t importKeyImages(const std::vectorimportKeyImages(signed_key_images_pod, offset, spent, unspent, check_spent); + return m_wallet->import_key_images(signed_key_images_pod, offset, spent, unspent, check_spent); } catch (const std::exception &e) { @@ -3753,7 +3770,7 @@ bool importKeyImages(std::vector key_images, size_t offset, boost:: try { - return m_wallet->importKeyImages(key_images_pod, offset, selected_transfers); + return m_wallet->import_key_images(key_images_pod, offset, selected_transfers); } catch (const std::exception &e) { @@ -3782,7 +3799,6 @@ void WalletImpl::makeMultisigTxSet(PendingTransaction &ptx) auto multisig_tx = m_wallet->make_multisig_tx_set(ptx.m_pending_tx); ptx.m_signers = multisig_tx.m_signers; - return true; } //------------------------------------------------------------------------------------------------------------------- From 9ab569479011285c0c636a6914f39865746336af Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 2 Sep 2024 11:19:26 +0200 Subject: [PATCH 03/25] rbrunner7 review --- src/wallet/api/wallet.cpp | 15 +++++++++------ src/wallet/api/wallet.h | 6 +++--- src/wallet/api/wallet2_api.h | 31 +++++++++++++++++-------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 68ad4fc081..def08d0b96 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3040,9 +3040,12 @@ void WalletImpl::createOneOffSubaddress(std::uint32_t account_index, std::uint32 // m_subaddressAccount->refresh(); } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::isDeprecated() +WalletState WalletImpl::getWalletState() { - return m_wallet->is_deprecated(); + WalletState wallet_state{}; + wallet_state.is_deprecated = m_wallet->is_deprecated(); + + return wallet_state; } //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::hasUnknownKeyImages() @@ -3151,7 +3154,7 @@ void WalletImpl::processPoolState(const std::vectordump_tx_to_str(ptxs.m_pending_tx); if (tx_dump.empty()) { - setStatusError("Failed to dump pending tx to string"); + setStatusError("Failed to convert pending tx to string"); } return tx_dump; diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 1428a3c6d1..43c14f02c4 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -245,7 +245,7 @@ class WalletImpl : public Wallet bool isFrozen(const PendingTransaction &multisig_ptxs) const override; bool isFrozen(const std::string multisig_sign_data) const override; void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) override; - bool isDeprecated() const override; + virtual WalletState getWalletState() const = 0; bool hasUnknownKeyImages() const override; void rewrite(const std::string &wallet_name, const std::string &password) override; void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) override; @@ -254,9 +254,9 @@ class WalletImpl : public Wallet bool isTransferUnlocked(std::uint64_t unlock_time, std::uint64_t block_height) const override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; void processPoolState(const std::vector> &txs) override; - std::string dumpMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; + std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; - std::string dumpTxToStr(const PendingTransaction &ptxs) const override; + std::string convertTxToStr(const PendingTransaction &ptxs) const override; bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; // bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index e222716844..6af9034d2d 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -454,6 +454,10 @@ struct Wallet BackgroundSync_CustomPassword = 2 }; + struct WalletState { + bool is_deprecated; + }; + virtual ~Wallet() = 0; virtual std::string seed(const std::string& seed_offset = "") const = 0; virtual std::string getSeedLanguage() const = 0; @@ -1173,8 +1177,6 @@ struct Wallet */ virtual void freeze(std::size_t idx) = 0; virtual void freeze(const std::string &key_image) = 0; - // QUESTION : Should we add the option to freeze by tx_id? Meaning: freeze all enotes that we received by a single transaction. -// virtual void freeze(const std::string &tx_id) = 0; /** * brief: thaw - thaw enote that is frozen, so it appears in balance and can be spent in a transaction * param: idx - index of enote in `m_transfers` @@ -1183,12 +1185,11 @@ struct Wallet */ virtual void thaw(std::size_t idx) = 0; virtual void thaw(const std::string &key_image) = 0; - // QUESTION : Should we add the option to thaw by tx_id? Meaning: thaw all enotes that we received by a single transaction. -// virtual void thaw(const std::string &tx_id) = 0; /** * brief: isFrozen - check if enote is frozen * param: idx - index of enote in `m_transfers` * param: key_image - key image of enote + // TODO : Investigate if this can get dropped too. On first sight I thought someone who uses the API can just loop over `PendingTransaction.m_key_images` and call `isFrozen(key_image)`, but it seems `wallet2::frozen(const multisig_tx_set txs)` does more than that. * QUESTION : Which approach should we use? We probably don't need both. Or are there other suggestions? (See WalletImpl::isFrozen for implementation) * Approach 1 : Use PendingTransaction, which just like tools::wallet2::multisig_tx_set has a vector of pending txs and an unordered set of signers pub keys. * Approach 2 : Use the encrypted hex string generated with tools::wallet2::save_multisig_tx(). This approach is already used in WalletImpl::restoreMultisigTransaction. @@ -1204,9 +1205,10 @@ struct Wallet virtual bool isFrozen(const std::string &key_image) const = 0; virtual bool isFrozen(const PendingTransaction &multisig_ptxs) const = 0; virtual bool isFrozen(const std::string multisig_sign_data) const = 0; - // QUESTION : Should we add the following function, which returns strings containing the key image for every frozen enote? I think it can be useful -// virtual std::vector getAllFrozenEnotes() const = 0; - // TODO : Would this better fit in one of `Subaddress`/`SubaddressAccount` classes? + // QUESTION : Should we add a note/warning that this should only be used in special cases? (Also addSubaddress & addSubaddressAccount do not refresh the known account/subaddress, if that's not for a good reason (that I don't see) I would either add refresh or at least give the same warning like the second line from the comment below. Seems the GUI only uses the addRow functions: https://github.com/search?q=repo%3Amonero-project/monero-gui%20addRow&type=code not the addSubaddress* ones https://github.com/search?q=repo%3Amonero-project/monero-gui%20addSubaddress&type=code ) e.g. something like: + // brief: createOneOffSubaddress - create a new account or subaddress for given index without adding it to known accounts and subaddresses. + // use `SubaddressAccount::addRow()` or `Subaddress::addRow()` instead to make sure the wallet keeps track of accounts and subaddresses + /** * brief: createOneOffSubaddress - create a subaddress for given index * param: account_index - major index @@ -1214,10 +1216,11 @@ struct Wallet */ virtual void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) = 0; /** - * brief: isDeprecated - check if wallet file format is deprecated - * return: true if wallet file is old format (before becoming JSON), else false + * brief: getWalletState - get information about the wallet + * - is wallet file format deprecated + * return: WalletState object */ - virtual bool isDeprecated() const = 0; + virtual WalletState getWalletState() const = 0; /** * brief: hasUnknownKeyImages - check if any enotes have missing key images * return: true if any stored enote is missing its key image, else false @@ -1333,12 +1336,12 @@ struct Wallet */ // virtual void getUnconfirmedPayments(std::list> &unconfirmed_payments, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; /** - * brief: dumpMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction + * brief: convertMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction * param: multisig_ptx - multisig pending transaction * return: encrypted tx data as hex string if succeeded, else empty string * note: sets status error on fail */ - virtual std::string dumpMultisigTxToStr(const PendingTransaction &multisig_ptx) const = 0; + virtual std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const = 0; /** * brief: saveMultisigTx - save a multisig pending transaction to file * param: multisig_ptx - multisig pending transaction @@ -1348,11 +1351,11 @@ struct Wallet */ virtual bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const = 0; /** - * brief: dumpTxToStr - get the encrypted data from a vector of pending transactions as hex string + * brief: convertTxToStr - get the encrypted data from a vector of pending transactions as hex string * param: ptxs - * return: unsigned tx data as encrypted hex string if succeeded, else empty string */ - virtual std::string dumpTxToStr(const PendingTransaction &ptxs) const = 0; + virtual std::string convertTxToStr(const PendingTransaction &ptxs) const = 0; /** * brief: parseUnsignedTxFromStr - get an unsigned transaction set from encrypted unsigned transaction as hex string * param: unsigned_tx_str - encrypted hex string From 8fb991384ecaf1df260756b3205eb51628bb3b4f Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Fri, 6 Sep 2024 14:11:10 +0200 Subject: [PATCH 04/25] remove blackball & ringdb --- src/wallet/api/wallet.cpp | 73 ------------------------------------ src/wallet/api/wallet.h | 4 -- src/wallet/api/wallet2_api.h | 28 +------------- 3 files changed, 2 insertions(+), 103 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index def08d0b96..ee34720962 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3319,79 +3319,6 @@ std::uint32_t WalletImpl::adjustPriority(std::uint32_t priority) return 0; } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::unsetRing(const std::vector &key_images) -{ - clearStatus(); - - crypto::key_image ki_pod; - std::vector key_images_pod; - for (std::string &ki : key_images) - { - if (!epee::string_tools::hex_to_pod(ki, ki_pod)) - { - // QUESTION : I think it may be a good idea to add the string that failed to parse to the error message as done below. - // Do you agree? Then I'll add it to other "Failed to parse ..." messages above, else I'll remove it from messages below. - setStatusError((boost::format(tr("Failed to parse key image: %s")) % ki).str()); - return false; - } - key_images_pod.push_back(ki_pod); - } - return m_wallet->unset_ring(key_images_pod); - // TODO : figure out how the API could handle m_ringdb and m_ringdb_key itself, to get rid of wallet2 for this function - // and we can improve error feedback, currently `m_wallet->unset_ring()` consumes the exception thrown by `m_ringdb->remove_rings()` -// try -// { -// return m_ringdb->remove_rings(getRingdbKey(), key_images_pod); -// } -// catch (const std::exception &e) -// { -// setStatusError(e.what()); -// } -// return false; -} -//------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::unsetRing(const std::string &tx_id) -{ - clearStatus(); - - crypto::hash tx_id_pod; - if (!epee::string_tools::hex_to_pod(tx_id, tx_id_pod)) - { - setStatusError((boost::format(tr("Failed to parse tx_id: %s")) % tx_id).str()); - return false; - } - - try - { - return m_wallet->unset_ring(tx_id_pod); - } - catch (const std::exception &e) - { - setStatusError(e.what()); - } - return false; -} -//------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::findAndSaveRings(bool force) -{ - clearStatus(); - - try - { - return m_wallet->find_and_save_rings(force); - } - catch (const std::exception &e) - { - setStatusError(e.what()); - } - return false; -} -//------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::isOutputBlackballed(const std::pair &output) -{ - return m_wallet->is_output_blackballed(output); -} -//------------------------------------------------------------------------------------------------------------------- void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 43c14f02c4..0e5906127e 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -265,10 +265,6 @@ class WalletImpl : public Wallet std::uint64_t getMinRingSize() const override; std::uint64_t adjustMixin(std::uint64_t mixin) const override; std::uint32_t adjustPriority(std::uint32_t priority) const override; - bool unsetRing(const std::vector &key_images) override; - bool unsetRing(const std::string &tx_id) override; - bool findAndSaveRings(bool force = true) override; - bool isOutputBlackballed(const std::pair &output) const override; void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const override; // void coldSignTx(const std::vector& ptx_vector, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const override; // const wallet2::transfer_details &getTransferDetails(std::size_t idx) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 6af9034d2d..f07f8f0883 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1100,6 +1100,7 @@ struct Wallet virtual void setOffline(bool offline) = 0; virtual bool isOffline() const = 0; + // QUESTION : Removing these three functions should be done in a separate PR? //! blackballs a set of outputs virtual bool blackballOutputs(const std::vector &outputs, bool add) = 0; @@ -1446,32 +1447,7 @@ struct Wallet * note: sets status error on fail */ virtual std::uint32_t adjustPriority(std::uint32_t priority) const = 0; - // QUESTION : Can anyone help with these comments? I looked at the command descriptions in `simplewallet::simplewallet()`, but I think they're too vague and imo they don't really help understand what these functions do. - /** - * brief: unsetRing - - * param: key_images - - * param: tx_id - - * return: true if succeeded - * note: sets status error on fail - */ - virtual bool unsetRing(const std::vector &key_images) = 0; - virtual bool unsetRing(const std::string &tx_id) = 0; - /** - * brief: findAndSaveRings - - * param: force - force save (default: true) - * return: true if succeeded - * note: sets status error on fail - */ - virtual bool findAndSaveRings(bool force = true) = 0; - // QUESTION : Other "blackball" functions that were implemented before this PR use std::string for the output index, should we stay consistent with that? Else I'd prefer using a pair of uint64_t. - /** - * brief: isOutputBlackballed - - * param: output - [amount, offset] for ringdb index - * return: true if succeeded - * note: sets status error on fail - */ - virtual bool isOutputBlackballed(const std::pair &output) const = 0; - // QUESTION : Any suggestion for the two comments below? + // QUESTION : Any suggestion for the function description below? /** * brief: coldTxAuxImport - * param: ptx - From 8d630d3e0a803984cc07af4ff447027ea94a5a10 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Sat, 7 Sep 2024 21:01:32 +0200 Subject: [PATCH 05/25] WIP rbrunner7 review round 2 --- src/wallet/api/transaction_info.h | 20 +++++++ src/wallet/api/wallet.cpp | 52 +++--------------- src/wallet/api/wallet.h | 7 +-- src/wallet/api/wallet2_api.h | 87 +++++++++++++++++-------------- 4 files changed, 76 insertions(+), 90 deletions(-) diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 0510fb216d..7bd5265090 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -82,6 +82,26 @@ class TransactionInfoImpl : public TransactionInfo uint64_t m_confirmations; uint64_t m_unlock_time; +// TODO : If it's certain that we need these, then add getter functions (to `TransactionInfo` in wallet2_api.h and `TransactionInfoImpl` in transaction_info.*) and add values to new members where applicable (e.g. in `TransactionHistoryImpl`) + +// from unconfirmed_transfer_details + uint64_t m_change; + // QUESTION : Can someone confirm that we don't need m_dests, because we have: + // - amount = m_transfers[i].amount + // - address = m_transfers[i].address + // - is_subaddress = m_subaddrIndex[i] != 0 + // I'm especially unsure about this assumption, wasn't able to verify it: + // - is_integrated = WalletImpl::integratedAddress(m_paymentid) == m_transfers[i].address + // And I haven't figured this one out yet + // - original = + std::vector m_dests; + enum { pending, pending_in_pool, failed, confirmed } m_tx_state; + // QUESTION : Any comments if we need this? Haven't investigated yet. + std::vector>> m_rings; // relative + +// from unconfirmed_payments + bool m_double_spend_seen; + friend class TransactionHistoryImpl; }; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index ee34720962..54d0262624 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1087,6 +1087,8 @@ bool WalletImpl::synchronized() const bool WalletImpl::refresh() { clearStatus(); + //TODO: make doRefresh return bool to know whether the error occured during refresh or not + //otherwise one may try, say, to send transaction, transfer fails and this method returns false doRefresh(); return status() == Status_Ok; } @@ -3043,7 +3045,10 @@ void WalletImpl::createOneOffSubaddress(std::uint32_t account_index, std::uint32 WalletState WalletImpl::getWalletState() { WalletState wallet_state{}; + wallet_state.is_deprecated = m_wallet->is_deprecated(); + wallet_state.ring_size = 16; + wallet_state.daemon_address = m_wallet->get_daemon_address(); return wallet_state; } @@ -3053,7 +3058,7 @@ bool WalletImpl::hasUnknownKeyImages() return m_wallet->has_unknown_key_images(); } //------------------------------------------------------------------------------------------------------------------- -void WalletImpl::rewrite(const std::string &wallet_name, const std::string &password) +void WalletImpl::rewriteWalletFile(const std::string &wallet_name, const std::string &password) { clearStatus(); @@ -3093,11 +3098,6 @@ std::mapunlocked_balance_per_subaddress(index_major, strict); } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::isTransferUnlocked(std::uint64_t unlock_time, std::uint64_t block_height) -{ - return m_wallet->is_transfer_unlocked(unlock_time, block_height); -} -//------------------------------------------------------------------------------------------------------------------- void WalletImpl::updatePoolState(std::vector> &process_txs, bool refreshed, bool try_incremental) { clearStatus(); @@ -3283,26 +3283,6 @@ std::uint64_t WalletImpl::getBaseFee() return m_wallet->get_dynamic_base_fee_estimate(); } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::getMinRingSize() -{ - if (useForkRules(HF_VERSION_MIN_MIXIN_15, 0)) - return 16; - if (useForkRules(8, 10)) - return 11; - if (useForkRules(7, 10)) - return 7; - if (useForkRules(6, 10)) - return 5; - if (useForkRules(2, 10)) - return 3; - return 0; -} -//------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::adjustMixin(std::uint64_t mixin) -{ - return m_wallet->adjust_mixin(mixin); -} -//------------------------------------------------------------------------------------------------------------------- std::uint32_t WalletImpl::adjustPriority(std::uint32_t priority) { clearStatus(); @@ -3416,11 +3396,6 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co } } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::getDaemonAddress() -{ - return m_wallet->get_daemon_address(); -} -//------------------------------------------------------------------------------------------------------------------- std::uint64_t WalletImpl::getDaemonAdjustedTime() { clearStatus(); @@ -3528,21 +3503,6 @@ std::uint64_t WalletImpl::getBlockchainHeightByDate(std::uint16_t year, std::uin return 0; } //------------------------------------------------------------------------------------------------------------------- -bool isSynced() -{ - clearStatus(); - - try - { - return m_wallet->is_synced(); - } - catch (const std::exception &e) - { - setStatusError((boost::format(tr("Failed to check if wallet is synced. Error: %s")) % e.what()).str()); - } - return 0; -} -//------------------------------------------------------------------------------------------------------------------- std::vector> WalletImpl::estimateBacklog(const std::vector> &fee_levels) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 0e5906127e..c61cad1719 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -247,11 +247,10 @@ class WalletImpl : public Wallet void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) override; virtual WalletState getWalletState() const = 0; bool hasUnknownKeyImages() const override; - void rewrite(const std::string &wallet_name, const std::string &password) override; + void rewriteWalletFile(const std::string &wallet_name, const std::string &password) override; void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) override; std::map balancePerSubaddress(std::uint32_t index_major, bool strict) const override; std::map>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const override; - bool isTransferUnlocked(std::uint64_t unlock_time, std::uint64_t block_height) const override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; void processPoolState(const std::vector> &txs) override; std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; @@ -262,15 +261,12 @@ class WalletImpl : public Wallet // bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; std::uint64_t getBaseFee() const override; - std::uint64_t getMinRingSize() const override; - std::uint64_t adjustMixin(std::uint64_t mixin) const override; std::uint32_t adjustPriority(std::uint32_t priority) const override; void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const override; // void coldSignTx(const std::vector& ptx_vector, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const override; // const wallet2::transfer_details &getTransferDetails(std::size_t idx) const override; void discardUnmixableOutputs() override; void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) override; - std::string getDaemonAddress() const override; std::uint64_t getDaemonAdjustedTime() const override; void setCacheDescription(const std::string &description) override; std::string getCacheDescription() const override; @@ -280,7 +276,6 @@ class WalletImpl : public Wallet std::string exportOutputsToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const override; std::size_t importOutputsFromStr(const std::string &outputs_str) override; std::uint64_t getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const override; - bool isSynced() const override; std::vector> estimateBacklog(const std::vector> &fee_levels) const override; std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const override; bool saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index f07f8f0883..4b0d232d17 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -69,6 +69,51 @@ enum NetworkType : uint8_t { bool set; }; +/** +* brief: EnoteDetails - Container for all the necessary information that belongs to an enote +*/ +struct EnoteDetails +{ +// from seraphis legacy enote types + // Ko + rct::key onetime_address; + /// a + rct::xmr_amount amount; + /// C + rct::key amount_commitment; + /// enc(x) + rct::key encoded_amount_blinding_factor; + /// enc(a) + rct::key encoded_amount; + /// view_tag + crypto::view_tag view_tag; + + // TODO : figure out if we need other members from transfer_details too, these are the ones that are not part of `TransactionInfo`, but my first impression is we could have an overlap so we can find TransactionInfo from EnoteDetails and vice versa. +// from transfer_details: + cryptonote::transaction_prefix m_tx; + // index in m_tx.vout + uint64_t m_internal_output_index; + uint64_t m_global_output_index; + bool m_spent; + bool m_frozen; + uint64_t m_spent_height; + crypto::key_image m_key_image; + rct::key m_mask; + bool m_rct; + bool m_key_image_known; + bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested + // TODO : fwiw so far this only is used for get_tx_pub_key_from_extra, figure out if actually needed. + uint64_t m_pk_index; + // TODO : This gets only filled by `wallet2::process_new_transaction` and only if `wallet2::m_track_uses` is true (default is false). Figure out if it's "too exotic" or do we need it. + std::vector> m_uses; + +// QUESTION : Any input on these multisig members? + // Multisig + bool m_key_image_partial; + std::vector m_multisig_k; + std::vector m_multisig_info; // one per other participant +}; + /** * @brief Transaction-like interface for sending money */ @@ -456,6 +501,8 @@ struct Wallet struct WalletState { bool is_deprecated; + std::uint64_t ring_rize; + std::string daemon_address; }; virtual ~Wallet() = 0; @@ -1162,7 +1209,6 @@ struct Wallet * note: sets status error on fail */ virtual std::string getMultisigSeed(const std::string &seed_offset) const = 0; - // TODO : Would this better fit in one of `Subaddress`/`SubaddressAccount` classes? /** * brief: getSubaddressIndex - get major and minor index of provided subaddress * param: address - main- or sub-address to get the index from @@ -1206,10 +1252,6 @@ struct Wallet virtual bool isFrozen(const std::string &key_image) const = 0; virtual bool isFrozen(const PendingTransaction &multisig_ptxs) const = 0; virtual bool isFrozen(const std::string multisig_sign_data) const = 0; - // QUESTION : Should we add a note/warning that this should only be used in special cases? (Also addSubaddress & addSubaddressAccount do not refresh the known account/subaddress, if that's not for a good reason (that I don't see) I would either add refresh or at least give the same warning like the second line from the comment below. Seems the GUI only uses the addRow functions: https://github.com/search?q=repo%3Amonero-project/monero-gui%20addRow&type=code not the addSubaddress* ones https://github.com/search?q=repo%3Amonero-project/monero-gui%20addSubaddress&type=code ) e.g. something like: - // brief: createOneOffSubaddress - create a new account or subaddress for given index without adding it to known accounts and subaddresses. - // use `SubaddressAccount::addRow()` or `Subaddress::addRow()` instead to make sure the wallet keeps track of accounts and subaddresses - /** * brief: createOneOffSubaddress - create a subaddress for given index * param: account_index - major index @@ -1228,12 +1270,12 @@ struct Wallet */ virtual bool hasUnknownKeyImages() const = 0; /** - * brief: rewrite - rewrite the wallet file for wallet update + * brief: rewriteWalletFile - rewrite the wallet file for wallet update * param: wallet_name - name of the wallet file (should exist) * param: password - wallet password * note: sets status error on fail */ - virtual void rewrite(const std::string &wallet_name, const std::string &password) = 0; + virtual void rewriteWalletFile(const std::string &wallet_name, const std::string &password) = 0; // QUESTION : Should we change this function from the current behavior in wallet2, so `wallet_name` is just the name of the new wallet instead of changing the `m_wallet_file` for the current wallet? /** * brief: writeWatchOnlyWallet - create a new watch-only wallet file with view keys from current wallet @@ -1257,14 +1299,6 @@ struct Wallet * return: [minor subaddress index: {amount, {blocks to unlock, time to unlock} }, ... ] */ virtual std::map>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const = 0; - // QUESTION : Can anyone help with this comment? There are other ones I'm not satisfied with, so if you have a better suggestion I'll change them. - /** - * brief: isTransferUnlocked - check if transfer is unlocked - * param: unlock_time - - * param: block_height - - * return: true if transfer is unlocked, else false - */ - virtual bool isTransferUnlocked(std::uint64_t unlock_time, std::uint64_t block_height) const = 0; /** * brief: updatePoolState - * outparam: process_txs - [ [tx, tx_id, double_spend_seen], ... ] @@ -1429,18 +1463,6 @@ struct Wallet */ virtual std::uint64_t getBaseFee() const = 0; /** - * brief: getMinRingSize - get the minimum allowed ring size - * return: min ring size - */ - virtual std::uint64_t getMinRingSize() const = 0; - // TODO : Should we make this static? - /** - * brief: adjustMixin - adjust mixin to fit into min and max ring size - * param: mixin - - * return: adjusted mixin - */ - virtual std::uint64_t adjustMixin(std::uint64_t mixin) const = 0; - /** * brief: adjustPriority - adjust priority depending on how "full" last N blocks are * param: priority - * return: adjusted priority @@ -1498,11 +1520,6 @@ struct Wallet // If we add access to boost::optional revisit all new functions to see which would benefit from it. virtual void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) = 0; /** - * brief: getDaemonAddress - - * return: daemon address - */ - virtual std::string getDaemonAddress() const = 0; - /** * brief: getDaemonAdjustedTime - * return: daemon adjusted time * note: sets status error on fail @@ -1562,12 +1579,6 @@ struct Wallet * note: sets status error on fail */ virtual std::uint64_t getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const = 0; - /** - * brief: isSynced - - * return: true if wallet is synced with daemon, else false - * note: sets status error on fail - */ - virtual bool isSynced() const = 0; // QUESTION : Can anyone help with these comments? /** * brief: estimateBacklog - From 49371c6c0c6fd7e291cac53047a83f1b5dc2d090 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 16 Sep 2024 15:14:20 +0200 Subject: [PATCH 06/25] TransactionInfo, EnoteDetails, some clean-up --- src/wallet/api/transaction_history.cpp | 12 +++ src/wallet/api/transaction_info.cpp | 15 +++ src/wallet/api/transaction_info.h | 28 ++---- src/wallet/api/wallet.cpp | 50 +++++++++- src/wallet/api/wallet.h | 1 + src/wallet/api/wallet2_api.h | 123 +++++++++++-------------- 6 files changed, 134 insertions(+), 95 deletions(-) diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 4dc869d5cb..75512a68dc 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -193,6 +193,10 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; + // QUESTION : Don't we want the unlock time? + ti->m_unlock_time = pd.m_unlock_time; + ti->m_change = pd->m_change; + ti->m_tx_state = TransactionInfo::confirmed; // single output transaction might contain multiple transfers for (const auto &d: pd.m_dests) { @@ -229,6 +233,10 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; + // QUESTION : Don't we want the unlock time? + ti->m_unlock_time = pd.m_tx.unlock_time; + ti->m_change = pd->m_change; + ti->m_tx_state = pd->m_state; for (const auto &d : pd.m_dests) { ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); @@ -258,6 +266,10 @@ void TransactionHistoryImpl::refresh() ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index); ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; + // QUESTION : Don't we want the unlock time? + ti->m_unlock_time = pd.m_unlock_time; + ti->m_tx_state = TransactionInfo::pending_in_pool; + ti->m_double_spend_seen = i->second.m_double_spend_seen; m_history.push_back(ti); LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount); diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 909c770864..9b6d20d656 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -149,4 +149,19 @@ uint64_t TransactionInfoImpl::unlockTime() const return m_unlock_time; } +std::uint64_t TransactionInfoImpl::receivedChangeAmount() const +{ + return m_change; +} + +int TransactionInfoImpl::txState() const +{ + return m_tx_state; +} + +bool TransactionInfoImpl::isDoubleSpendSeen() const +{ + return m_double_spend_seen; +} + } // namespace diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 7bd5265090..7a26dec2fc 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -63,6 +63,10 @@ class TransactionInfoImpl : public TransactionInfo virtual uint64_t confirmations() const override; virtual uint64_t unlockTime() const override; + std::uint64_t receivedChangeAmount() const override; + int txState() const override; + bool isDoubleSpendSeen() const override; + private: int m_direction; bool m_pending; @@ -81,25 +85,11 @@ class TransactionInfoImpl : public TransactionInfo std::vector m_transfers; uint64_t m_confirmations; uint64_t m_unlock_time; - -// TODO : If it's certain that we need these, then add getter functions (to `TransactionInfo` in wallet2_api.h and `TransactionInfoImpl` in transaction_info.*) and add values to new members where applicable (e.g. in `TransactionHistoryImpl`) - -// from unconfirmed_transfer_details - uint64_t m_change; - // QUESTION : Can someone confirm that we don't need m_dests, because we have: - // - amount = m_transfers[i].amount - // - address = m_transfers[i].address - // - is_subaddress = m_subaddrIndex[i] != 0 - // I'm especially unsure about this assumption, wasn't able to verify it: - // - is_integrated = WalletImpl::integratedAddress(m_paymentid) == m_transfers[i].address - // And I haven't figured this one out yet - // - original = - std::vector m_dests; - enum { pending, pending_in_pool, failed, confirmed } m_tx_state; - // QUESTION : Any comments if we need this? Haven't investigated yet. - std::vector>> m_rings; // relative - -// from unconfirmed_payments + // received change amount from outgoing transaction + std::uint64_t m_change; + // enum TxState + int m_tx_state; + // is double spend seen bool m_double_spend_seen; friend class TransactionHistoryImpl; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 54d0262624..0dba3c57a3 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3154,7 +3154,47 @@ void WalletImpl::processPoolState(const std::vector enote_details) const +{ + wallet2::transfer_container tc; + m_wallet->get_transfers(tc); + enote_details.reserve(tc.size()); + + for (auto &td : tc) + { + EnoteDetails ed{}; + + cryptonote::txout_target_v txout_v = td.m_tx.vout[tx.m_internal_output_index]; + crypto::public_key pub_key_pod; + if (txout_v.type() == typeid(cryptonote::txout_to_key)) + ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); + else if (txout_v.type() == typeid(cryptonote::txout_to_tagged_key)) + { + ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); + ed.m_view_tag = epee::string_tools::pod_to_hex(boost::get(txout_v).view_tag); + } + + ed.m_tx_id = td.m_txid; + ed.m_internal_output_index = td.m_internal_output_index; + ed.m_global_output_index = td.m_global_output_index; + ed.m_spent = td.m_spent; + ed.m_frozen = td.m_frozen; + ed.m_spent_height = td.m_spent_height; + ed.m_key_image = td.m_key_image; + ed.m_mask = td.m_mask; + ed.m_amount = td.m_mask; + ed.m_rct = td.m_rct; +// ed.m_protocol_version = td.m_rct ? EnoteDetails::rct : EnoteDetails::cn; + ed.m_key_image_known = td.m_key_image_known; + ed.m_key_image_request = td.m_key_image_request; + ed.m_pk_index = td.m_pk_index; + ed.m_uses = td.m_uses; + + enote_details.push_back(ed); + } +} +//------------------------------------------------------------------------------------------------------------------- +std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisig_ptx) { clearStatus(); @@ -3176,7 +3216,7 @@ std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) return ""; } //------------------------------------------------------------------------------------------------------------------- -bool saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename) +bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename) { clearStatus(); @@ -3198,7 +3238,7 @@ bool saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string & return false; } //------------------------------------------------------------------------------------------------------------------- -std::string convertTxToStr(const PendingTransaction &ptxs) +std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs) { clearStatus(); @@ -3211,12 +3251,12 @@ std::string convertTxToStr(const PendingTransaction &ptxs) return tx_dump; } //------------------------------------------------------------------------------------------------------------------- -bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) +bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) { return m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set); } //------------------------------------------------------------------------------------------------------------------- -bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) +bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c61cad1719..92b7363675 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -253,6 +253,7 @@ class WalletImpl : public Wallet std::map>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; void processPoolState(const std::vector> &txs) override; + void getEnoteDetails(std::vector enote_details) const override; std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 4b0d232d17..698d29de6d 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -74,44 +74,50 @@ enum NetworkType : uint8_t { */ struct EnoteDetails { -// from seraphis legacy enote types // Ko - rct::key onetime_address; - /// a - rct::xmr_amount amount; - /// C - rct::key amount_commitment; - /// enc(x) - rct::key encoded_amount_blinding_factor; - /// enc(a) - rct::key encoded_amount; - /// view_tag - crypto::view_tag view_tag; - - // TODO : figure out if we need other members from transfer_details too, these are the ones that are not part of `TransactionInfo`, but my first impression is we could have an overlap so we can find TransactionInfo from EnoteDetails and vice versa. -// from transfer_details: - cryptonote::transaction_prefix m_tx; - // index in m_tx.vout - uint64_t m_internal_output_index; - uint64_t m_global_output_index; + std::string m_onetime_address; + // view_tag + std::string m_view_tag; + // QUESTION : I'd argue block height for enote is redundant, you can get this information from TransactionHistory. Or any different opinions? +// std::uint64_t m_block_height; + // relative index in tx + std::uint64_t m_internal_output_index; + // absolute index from `cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry.output_indices` + std::uint64_t m_global_output_index; + // is spent bool m_spent; + // is frozen bool m_frozen; - uint64_t m_spent_height; - crypto::key_image m_key_image; - rct::key m_mask; + // blockchain height, set if spent + std::uint64_t m_spent_height; + // key image + std::string m_key_image; + // QUESTION : Is this comment correct? + // x, blinding factor in amount commitment C = x G + a H + std::string m_mask; + // a + std::uint64_t m_amount; + // QUESTION : Should we change m_rct to this enum to be prepared for the future? We could also add CryptoNote as cn before rct if that would make sense!? +// enum { rct, fcmp } m_protocol_version; + // or +// enum { cn, rct, fcmp } m_protocol_version; + // is ring confidential transaction bool m_rct; + // is key image known bool m_key_image_known; - bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested - // TODO : fwiw so far this only is used for get_tx_pub_key_from_extra, figure out if actually needed. + // view wallets: we want to request it; cold wallets: it was requested + bool m_key_image_request; + // public key index in tx_extra uint64_t m_pk_index; - // TODO : This gets only filled by `wallet2::process_new_transaction` and only if `wallet2::m_track_uses` is true (default is false). Figure out if it's "too exotic" or do we need it. - std::vector> m_uses; - -// QUESTION : Any input on these multisig members? + // track uses of this enote in the blockchain in the format [ [block_height, tx_id], ... ] if `wallet2::m_track_uses` is true (default is false) + std::vector> m_uses; +// QUESTION : Any input on these multisig members? I'd ignore them for now. // Multisig + /* bool m_key_image_partial; std::vector m_multisig_k; std::vector m_multisig_info; // one per other participant + */ }; /** @@ -220,6 +226,15 @@ struct TransactionInfo Direction_Out }; + // QUESTION : We already have a bool for "pending" and "failed", but should we rather add two more bools (`m_pending_in_pool` & `m_confirmed`) or switch to an enum like this? I'd prefer the enum, but I guess removing `m_pending` and `m_failed` is not an option? + // If there is justificatin to keep this, any suggestions for a better name? E.g. TxTransmissionState? + enum TxState { + pending, + pending_in_pool, + failed, + confirmed + }; + struct Transfer { Transfer(uint64_t _amount, const std::string &address); const uint64_t amount; @@ -246,6 +261,10 @@ struct TransactionInfo virtual std::string paymentId() const = 0; //! only applicable for output transactions virtual const std::vector & transfers() const = 0; + + virtual std::uint64_t receivedChangeAmount() const = 0; + virtual int txState() const = 0; + virtual bool isDoubleSpendSeen() const = 0; }; /** * @brief The TransactionHistory - interface for displaying transaction history @@ -1323,53 +1342,15 @@ struct Wallet */ virtual void processPoolState(const std::vector> &txs) = 0; // TODO / QUESTION : How to translate the following types to a standard type for the API? - // - tools::wallet2::transfer_details & tools::wallet2::transfer_container (vector of tools::wallet2::transfer_details) - // - tools::wallet2::payment_details - // - tools::wallet2::confirmed_transfer_details - // - tools::wallet2::pool_payment_details // - tools::wallet2::signed_tx // - cryptonote::address_parse_info -// TODO : wallet2::transfer_container - /** - * brief: getTransfers - get all transfers - * outparam: transfers - - */ -// virtual void getTransfers(wallet2::transfer_container& transfers) const = 0; -// TODO : wallet2::payment_details - /** - * brief: getPayments - get incoming transfers - * param: payment_id - - * param: payments - - * param: min_height - - * param: subaddr_account - - * param: subaddr_indices - - */ -// virtual void getPayments(const std::string &payment_id, std::list &payments, std::uint64_t min_height, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; -// TODO : wallet2::payment_details - /** - * brief: getPayments - get incoming transfers - * param: payments - - * param: max_height - - */ -// virtual void getPayments(std::list> &payments, std::uint64_t min_height, std::uint64_t max_height, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; -// TODO : wallet2::confirmed_transfer_details - /** - * brief: getPaymentsOut - get outgoing transfers - * param: confirmed_payments - - */ -// virtual void getPaymentsOut(std::list> &confirmed_payments, std::uint64_t min_height, std::uint64_t max_height, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; -// TODO : wallet2::unconfirmed_transfer_details - /** - * brief: getUnconfirmedPaymentsOut - get unconfirmed transfers - * param: unconfirmed_payments - - */ -// virtual void getUnconfirmedPaymentsOut(std::list> &unconfirmed_payments, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; -// TODO : wallet2::pool_payment_details + /** - * brief: getUnconfirmedPayments - get pending transfers, currently in pool - * param: unconfirmed_payments - + * brief: getEnoteDetails - get information about all enotes + * outparam: enote_details - */ -// virtual void getUnconfirmedPayments(std::list> &unconfirmed_payments, const boost::optional &subaddr_account, const std::set &subaddr_indices) const = 0; + virtual void getEnoteDetails(std::vector enote_details) const = 0; + /** * brief: convertMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction * param: multisig_ptx - multisig pending transaction From 55c8463c2ca4720795684fd54f902c9fdbcf4e0b Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 16 Sep 2024 17:37:39 +0200 Subject: [PATCH 07/25] still WIP rbrunner7 review round 2 --- src/wallet/api/wallet.cpp | 44 ------------------------------- src/wallet/api/wallet.h | 6 ----- src/wallet/api/wallet2_api.h | 51 +++--------------------------------- 3 files changed, 3 insertions(+), 98 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 0dba3c57a3..8194089805 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3053,11 +3053,6 @@ WalletState WalletImpl::getWalletState() return wallet_state; } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::hasUnknownKeyImages() -{ - return m_wallet->has_unknown_key_images(); -} -//------------------------------------------------------------------------------------------------------------------- void WalletImpl::rewriteWalletFile(const std::string &wallet_name, const std::string &password) { clearStatus(); @@ -3088,16 +3083,6 @@ void WalletImpl::writeWatchOnlyWallet(const std::string &wallet_name, const std: } } //------------------------------------------------------------------------------------------------------------------- -std::map WalletImpl::balancePerSubaddress(std::uint32_t index_major, bool strict) -{ - return m_wallet->balance_per_subaddress(index_major, strict); -} -//------------------------------------------------------------------------------------------------------------------- -std::map>> WalletImpl::unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) -{ - return m_wallet->unlocked_balance_per_subaddress(index_major, strict); -} -//------------------------------------------------------------------------------------------------------------------- void WalletImpl::updatePoolState(std::vector> &process_txs, bool refreshed, bool try_incremental) { clearStatus(); @@ -3436,35 +3421,6 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co } } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::getDaemonAdjustedTime() -{ - clearStatus(); - - try - { - return m_wallet->get_daemon_adjusted_time(); - } - catch (const std::exception &e) - { - setStatusError((boost::format(tr("Failed to get daemon adjusted time. Error: %s")) % e.what()).str()); - } - return 0; -} -//------------------------------------------------------------------------------------------------------------------- -void WalletImpl::setCacheDescription(const std::string &description) -{ - m_wallet->set_description(description); - // TODO : Add ATTRIBUTE_DESCRIPTION to API and then call -// setCacheAttribute(ATTRIBUTE_DESCRIPTION, description); -} -//------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::getCacheDescription() -{ - return m_wallet->get_description(); - // TODO : Add ATTRIBUTE_DESCRIPTION to API and then call -// return getCacheAttribute(ATTRIBUTE_DESCRIPTION); -} -//------------------------------------------------------------------------------------------------------------------- const std::pair, std::vector>& WalletImpl::getAccountTags() { return m_wallet->get_account_tags(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 92b7363675..9f46fdd799 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -246,11 +246,8 @@ class WalletImpl : public Wallet bool isFrozen(const std::string multisig_sign_data) const override; void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) override; virtual WalletState getWalletState() const = 0; - bool hasUnknownKeyImages() const override; void rewriteWalletFile(const std::string &wallet_name, const std::string &password) override; void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) override; - std::map balancePerSubaddress(std::uint32_t index_major, bool strict) const override; - std::map>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; void processPoolState(const std::vector> &txs) override; void getEnoteDetails(std::vector enote_details) const override; @@ -268,9 +265,6 @@ class WalletImpl : public Wallet // const wallet2::transfer_details &getTransferDetails(std::size_t idx) const override; void discardUnmixableOutputs() override; void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) override; - std::uint64_t getDaemonAdjustedTime() const override; - void setCacheDescription(const std::string &description) override; - std::string getCacheDescription() const override; const std::pair, std::vector>& getAccountTags() override; void setAccountTag(const std::set &account_indices, const std::string &tag) override; void setAccountTagDescription(const std::string &tag, const std::string &description) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 698d29de6d..49a7568931 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1284,11 +1284,6 @@ struct Wallet */ virtual WalletState getWalletState() const = 0; /** - * brief: hasUnknownKeyImages - check if any enotes have missing key images - * return: true if any stored enote is missing its key image, else false - */ - virtual bool hasUnknownKeyImages() const = 0; - /** * brief: rewriteWalletFile - rewrite the wallet file for wallet update * param: wallet_name - name of the wallet file (should exist) * param: password - wallet password @@ -1305,20 +1300,6 @@ struct Wallet */ virtual void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) = 0; /** - * brief: balancePerSubaddress - get balance for each subaddress in given account - * param: index_major - account index - * param: strict - - * return: [minor subaddress index: amount, ... ] - */ - virtual std::map balancePerSubaddress(std::uint32_t index_major, bool strict) const = 0; - /** - * brief: unlockedBalancePerSubaddress - get unlocked balance for each subaddresses in given account - * param: index_major - account index - * param: strict - - * return: [minor subaddress index: {amount, {blocks to unlock, time to unlock} }, ... ] - */ - virtual std::map>> unlockedBalancePerSubaddress(std::uint32_t index_major, bool strict) const = 0; - /** * brief: updatePoolState - * outparam: process_txs - [ [tx, tx_id, double_spend_seen], ... ] * param: refreshed - (default: false) @@ -1341,16 +1322,11 @@ struct Wallet * note: sets status error on fail */ virtual void processPoolState(const std::vector> &txs) = 0; - // TODO / QUESTION : How to translate the following types to a standard type for the API? - // - tools::wallet2::signed_tx - // - cryptonote::address_parse_info - /** * brief: getEnoteDetails - get information about all enotes * outparam: enote_details - */ virtual void getEnoteDetails(std::vector enote_details) const = 0; - /** * brief: convertMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction * param: multisig_ptx - multisig pending transaction @@ -1379,6 +1355,9 @@ struct Wallet * return: true if succeeded */ virtual bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const = 0; + // TODO / QUESTION : How to translate the following types to a standard type for the API? + // - tools::wallet2::signed_tx + // - cryptonote::address_parse_info // TODO : wallet2::signed_tx_set /** * brief: signTxDumpToStr - get a signed transaction set from unsigned transaction set @@ -1476,14 +1455,6 @@ struct Wallet * note: sets status error on fail */ // virtual bool useForkRules(std::uint8_t version, std::int64_t early_blocks) const = 0; -// TODO : wallet2::transfer_details - /** - * brief: getTransferDetails - - * param: idx - index in transfer storage - * return: transfer details for given index - * note: sets status error on fail - */ -// virtual const wallet2::transfer_details &getTransferDetails(std::size_t idx) const = 0; /** * brief: discardUnmixableOutputs - freeze all unmixable outputs * note: sets status error on fail @@ -1501,22 +1472,6 @@ struct Wallet // If we add access to boost::optional revisit all new functions to see which would benefit from it. virtual void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) = 0; /** - * brief: getDaemonAdjustedTime - - * return: daemon adjusted time - * note: sets status error on fail - */ - virtual std::uint64_t getDaemonAdjustedTime() const = 0; - /** - * brief: setCacheDescription - set wallet cache attribute with key ATTRIBUTE_DESCRIPTION - * param: description - - */ - virtual void setCacheDescription(const std::string &description) = 0; - /** - * brief: getCacheDescription - get wallet cache attribute with key ATTRIBUTE_DESCRIPTION - * return: description - */ - virtual std::string getCacheDescription() const = 0; - /** * brief: getAccountTags - get the list of registered account tags * return: first.Key=(tag's name), first.Value=(tag's label), second[i]=(i-th account's tag) */ From 42d61a7f84ffab7cad5118424496fb440f882e3d Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Sun, 22 Sep 2024 16:03:29 +0200 Subject: [PATCH 08/25] resolve some TODOs, QUESTIONs and clean up --- src/wallet/api/transaction_history.cpp | 14 ++- src/wallet/api/wallet.cpp | 118 ++++++++++--------------- src/wallet/api/wallet.h | 11 ++- src/wallet/api/wallet2_api.h | 51 +++-------- 4 files changed, 76 insertions(+), 118 deletions(-) diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 75512a68dc..d6818ff545 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -150,6 +150,11 @@ void TransactionHistoryImpl::refresh() ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; ti->m_unlock_time = pd.m_unlock_time; + // not used for payment_details + ti->m_change = 0; + ti->m_tx_state = TransactionInfo::confirmed; + // not used for payment_details + ti->m_double_spend_seen = false; m_history.push_back(ti); } @@ -193,10 +198,11 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; - // QUESTION : Don't we want the unlock time? ti->m_unlock_time = pd.m_unlock_time; ti->m_change = pd->m_change; ti->m_tx_state = TransactionInfo::confirmed; + // not used for confirmed_transfer_details + ti->m_double_spend_seen = false; // single output transaction might contain multiple transfers for (const auto &d: pd.m_dests) { @@ -233,10 +239,11 @@ void TransactionHistoryImpl::refresh() ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; - // QUESTION : Don't we want the unlock time? ti->m_unlock_time = pd.m_tx.unlock_time; ti->m_change = pd->m_change; ti->m_tx_state = pd->m_state; + // not used for unconfirmed_transfer_details + ti->m_double_spend_seen = false; for (const auto &d : pd.m_dests) { ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); @@ -266,8 +273,9 @@ void TransactionHistoryImpl::refresh() ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index); ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; - // QUESTION : Don't we want the unlock time? ti->m_unlock_time = pd.m_unlock_time; + // not used for pool_payment_details + ti->m_change = 0; ti->m_tx_state = TransactionInfo::pending_in_pool; ti->m_double_spend_seen = i->second.m_double_spend_seen; m_history.push_back(ti); diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 8194089805..eb60aa4898 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2634,6 +2634,21 @@ bool WalletImpl::useForkRules(uint8_t version, int64_t early_blocks) const { return m_wallet->use_fork_rules(version,early_blocks); } +// QUESTION : The method above doesn't handle error, can I replace the body with the following in this PR? +//{ +// clearStatus(); +// +// try +// { +// return m_wallet->use_fork_rules(version, early_blocks); +// } +// catch (const std::exception &e) +// { +// setStatusError((boost::format(tr("Failed to check if we use fork rules for version `%u` with `%d` early blocks. Error: %s")) % version % early_blocks % e.what()).str()); +// } +// return false; +//} +//------------------------------------------------------------------------------------------------------------------- bool WalletImpl::blackballOutputs(const std::vector &outputs, bool add) { @@ -2986,54 +3001,6 @@ bool WalletImpl::isFrozen(const std::string &key_image) return false; } //------------------------------------------------------------------------------------------------------------------- -bool isFrozen(const PendingTransaction &multisig_ptxs) -{ - clearStatus(); - - try - { - checkMultisigWalletReady(m_wallet); - - tools::wallet2::multisig_tx_set multisig_tx_set; - multisig_tx_set.m_ptx = multisig_ptxs->m_pending_tx; - multisig_tx_set.m_signers = multisig_ptxs->m_signers; - - return m_wallet->frozen(multisig_tx_set); - } - catch (const exception &e) - { - setStatusError(e.what()); - } - - return false; -} -//------------------------------------------------------------------------------------------------------------------- -bool isFrozen(const std::string multisig_sign_data) -{ - clearStatus(); - - try - { - checkMultisigWalletReady(m_wallet); - - string multisig_sign_data_bin; - if (!epee::string_tools::parse_hexstr_to_binbuff(multisig_sign_data, multisig_sign_data_bin)) - throw runtime_error(tr("Failed to deserialize multisig transaction")); - - tools::wallet2::multisig_tx_set multisig_txs; - if (!m_wallet->load_multisig_tx(multisig_sign_data_bin, multisig_txs, {})) - throw runtime_error(tr("Failed to load multisig transaction")); - - return m_wallet->frozen(multisig_txs); - } - catch (const exception &e) - { - setStatusError(e.what()); - } - - return false; -} -//------------------------------------------------------------------------------------------------------------------- void WalletImpl::createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) { m_wallet->create_one_off_subaddress({account_index, address_index}); @@ -3241,6 +3208,27 @@ bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, Unsi return m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set); } //------------------------------------------------------------------------------------------------------------------- +std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const +{ + clearStatus(); + + std::string signed_tx_data; + + try + { + tools::wallet2::signed_tx_set signed_txes; + signed_tx_data = m_wallet->sign_tx_dump_to_str(exported_txs.m_unsigned_tx_set, ptx.m_pending_tx, signed_txes); + } + catch (const exception &e) + { + setStatusError(string(tr("Failed to sign tx: ")) + e.what()); + return {}; + } + + ptx.m_key_images = signed_txs.key_images; + return signed_tx_data; +} +//------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) { clearStatus(); @@ -3338,22 +3326,6 @@ void coldTxAuxImport(const PendingTransaction &ptx, const std::vectoruse_fork_rules(version, early_blocks); -// } -// catch (const std::exception &e) -// { -// setStatusError((boost::format(tr("Failed to check if we use fork rules for version `%u` with `%d` early blocks. Error: %s")) % version % early_blocks % e.what()).str()); -// } -// return false; -//} -//------------------------------------------------------------------------------------------------------------------- void WalletImpl::discardUnmixableOutputs() { clearStatus(); @@ -3368,7 +3340,7 @@ void WalletImpl::discardUnmixableOutputs() } } //------------------------------------------------------------------------------------------------------------------- -void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) +void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const std::string &single_destination_subaddress) { clearStatus(); @@ -3401,11 +3373,11 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co boost::optional single_destination_subaddress_pod = boost::none; cryptonote::address_parse_info info; - if (single_destination_subaddress != boost::none) + if (!single_destination_subaddress.empty()) { if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), single_destination_subaddress)) { - setStatusError((boost::format(tr("Failed to parse subaddress: %s")) % single_destination_subaddress).str()); + setStatusError((boost::format(tr("Failed to get account address from string: %s")) % single_destination_subaddress).str()); return; } single_destination_subaddress_pod = info.address; @@ -3551,13 +3523,14 @@ bool WalletImpl::loadFromFile(const std::string &path_to_file, std::string &targ return m_wallet->load_from_file(path_to_file, target_str, max_size); } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::hashTransfers(boost::optional transfer_height, std::string &hash) +std::uint64_t WalletImpl::hashTransfers(std::uint64_t transfer_height, std::string &hash) { clearStatus(); try { - return m_wallet->hash_m_transfers(transfer_height, hash); + boost::optional _transfer_height = transfer_height == 0 ? boost::none : transfer_height; + return m_wallet->hash_m_transfers(_transfer_height, hash); } catch (const std::exception &e) { @@ -3595,7 +3568,7 @@ std::pair WalletImpl::estimateTxSizeAndWeight(bool u return std::make_pair(0, 0); } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t importKeyImages(const std::vector> &signed_key_images, size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent) +std::uint64_t importKeyImages(const std::vector> &signed_key_images, std::size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent) { clearStatus(); @@ -3637,7 +3610,7 @@ std::uint64_t importKeyImages(const std::vector key_images, size_t offset, boost::optional> selected_transfers = boost::none) +bool importKeyImages(std::vector key_images, std::size_t offset, std::unordered_set selected_transfers) { clearStatus(); @@ -3656,7 +3629,8 @@ bool importKeyImages(std::vector key_images, size_t offset, boost:: try { - return m_wallet->import_key_images(key_images_pod, offset, selected_transfers); + boost::optional> _selected_transfers = selected_transfers.empty() ? boost::none : selected_transfers; + return m_wallet->import_key_images(key_images_pod, offset, _selected_transfers); } catch (const std::exception &e) { diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 9f46fdd799..5c7f6679e7 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -242,8 +242,6 @@ class WalletImpl : public Wallet void thaw(const std::string &key_image) override; bool isFrozen(std::size_t idx) const override; bool isFrozen(const std::string &key_image) const override; - bool isFrozen(const PendingTransaction &multisig_ptxs) const override; - bool isFrozen(const std::string multisig_sign_data) const override; void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) override; virtual WalletState getWalletState() const = 0; void rewriteWalletFile(const std::string &wallet_name, const std::string &password) override; @@ -255,6 +253,7 @@ class WalletImpl : public Wallet bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; + std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; // bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; @@ -264,7 +263,7 @@ class WalletImpl : public Wallet // void coldSignTx(const std::vector& ptx_vector, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const override; // const wallet2::transfer_details &getTransferDetails(std::size_t idx) const override; void discardUnmixableOutputs() override; - void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) override; + void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const std::string &single_destination_subaddress) override; const std::pair, std::vector>& getAccountTags() override; void setAccountTag(const std::set &account_indices, const std::string &tag) override; void setAccountTagDescription(const std::string &tag, const std::string &description) override; @@ -275,11 +274,11 @@ class WalletImpl : public Wallet std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const override; bool saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const override; bool loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const override; - std::uint64_t hashTransfers(boost::optional transfer_height, std::string &hash) const override; + std::uint64_t hashTransfers(std::uint64_t transfer_height, std::string &hash) const override; void finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) override; std::pair estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) const override; - std::uint64_t importKeyImages(const std::vector> &signed_key_images, size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) override; - bool importKeyImages(std::vector key_images, size_t offset = 0, boost::optional> selected_transfers = boost::none) override; + std::uint64_t importKeyImages(const std::vector> &signed_key_images, std::size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) override; + bool importKeyImages(std::vector key_images, std::size_t offset = 0, std::unordered_set selected_transfers = {}) override; private: void clearStatus() const; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 49a7568931..2fdbb9cb8e 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -78,8 +78,8 @@ struct EnoteDetails std::string m_onetime_address; // view_tag std::string m_view_tag; - // QUESTION : I'd argue block height for enote is redundant, you can get this information from TransactionHistory. Or any different opinions? -// std::uint64_t m_block_height; + // this enote was received at block height + std::uint64_t m_block_height; // relative index in tx std::uint64_t m_internal_output_index; // absolute index from `cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry.output_indices` @@ -92,7 +92,7 @@ struct EnoteDetails std::uint64_t m_spent_height; // key image std::string m_key_image; - // QUESTION : Is this comment correct? + // QUESTION : Is this comment correct? (This is the `rct::key m_mask` from wallet2::transfer_details) // x, blinding factor in amount commitment C = x G + a H std::string m_mask; // a @@ -370,6 +370,7 @@ struct SubaddressAccountRow { std::string m_balance; std::string m_unlockedBalance; public: + // QUESTION : afaik this is unused, can we remove it? std::string extra; std::string getAddress() const {return m_address;} std::string getLabel() const {return m_label;} @@ -519,6 +520,7 @@ struct Wallet }; struct WalletState { + // is wallet file format deprecated bool is_deprecated; std::uint64_t ring_rize; std::string daemon_address; @@ -1255,22 +1257,11 @@ struct Wallet * brief: isFrozen - check if enote is frozen * param: idx - index of enote in `m_transfers` * param: key_image - key image of enote - // TODO : Investigate if this can get dropped too. On first sight I thought someone who uses the API can just loop over `PendingTransaction.m_key_images` and call `isFrozen(key_image)`, but it seems `wallet2::frozen(const multisig_tx_set txs)` does more than that. - * QUESTION : Which approach should we use? We probably don't need both. Or are there other suggestions? (See WalletImpl::isFrozen for implementation) - * Approach 1 : Use PendingTransaction, which just like tools::wallet2::multisig_tx_set has a vector of pending txs and an unordered set of signers pub keys. - * Approach 2 : Use the encrypted hex string generated with tools::wallet2::save_multisig_tx(). This approach is already used in WalletImpl::restoreMultisigTransaction. - * __________ Approach 1 __________ - * param: multisig_ptxs - - * __________ Approach 2 __________ - * param: multisig_sign_data - - * ________________________________ * return : true if enote is frozen, else false * note: sets status error on fail */ virtual bool isFrozen(std::size_t idx) const = 0; virtual bool isFrozen(const std::string &key_image) const = 0; - virtual bool isFrozen(const PendingTransaction &multisig_ptxs) const = 0; - virtual bool isFrozen(const std::string multisig_sign_data) const = 0; /** * brief: createOneOffSubaddress - create a subaddress for given index * param: account_index - major index @@ -1279,7 +1270,6 @@ struct Wallet virtual void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) = 0; /** * brief: getWalletState - get information about the wallet - * - is wallet file format deprecated * return: WalletState object */ virtual WalletState getWalletState() const = 0; @@ -1356,17 +1346,15 @@ struct Wallet */ virtual bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const = 0; // TODO / QUESTION : How to translate the following types to a standard type for the API? - // - tools::wallet2::signed_tx // - cryptonote::address_parse_info -// TODO : wallet2::signed_tx_set /** - * brief: signTxDumpToStr - get a signed transaction set from unsigned transaction set - * param: exported_txs - - * outparam: ptx - - * outparam: signed_txes - + * brief: signTxToStr - get a signed pending transaction from an unsigned transaction + * param: exported_txs - unsigned transaction + * outparam: ptx - signed pending transaction * return: signed tx data as encrypted hex string + * note: sets status error on fail */ -// virtual std::string signTxDumpToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx, signed_tx_set &signed_txes) const = 0; + virtual std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const = 0; // TODO : accept_func with wallet2::signed_tx_set /** * brief: loadTx - load pending transactions from a file @@ -1446,15 +1434,6 @@ struct Wallet * param: tx_device_aux - */ // virtual void coldSignTx(const PendingTransaction &ptx, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const = 0; - // TODO : this already exists, remove after checking - /** - * brief: useForkRules - check if the wallet uses the rules for hard fork version at current block height - early_blocks - * param: version - hard fork version - * param: early_blocks - - * return: true if fork rules are used - * note: sets status error on fail - */ -// virtual bool useForkRules(std::uint8_t version, std::int64_t early_blocks) const = 0; /** * brief: discardUnmixableOutputs - freeze all unmixable outputs * note: sets status error on fail @@ -1468,9 +1447,7 @@ struct Wallet * param: single_destination_subaddress - * note: sets status error on fail */ - // QUESTION : There were some cases already where I wished to have boost::optional in here. I have no explicit example, but in general e.g. for functions that return a bool, but have to return early on error, it would be cleaner to return boost::none instead of true/false, because the API user could forget to check the error status and may use an incorrect value. Similar for uint*_t, where we can't use e.g. -1 on error. - // If we add access to boost::optional revisit all new functions to see which would benefit from it. - virtual void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const boost::optional &single_destination_subaddress) = 0; + virtual void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const std::string &single_destination_subaddress) = 0; /** * brief: getAccountTags - get the list of registered account tags * return: first.Key=(tag's name), first.Value=(tag's label), second[i]=(i-th account's tag) @@ -1556,7 +1533,7 @@ struct Wallet * return: amount of hashed transfers * note: sets status error on fail */ - virtual std::uint64_t hashTransfers(boost::optional transfer_height, std::string &hash) const = 0; + virtual std::uint64_t hashTransfers(std::uint64_t transfer_height, std::string &hash) const = 0; /** * brief: finishRescanBcKeepKeyImages - * param: transfer_height - @@ -1594,7 +1571,7 @@ struct Wallet * return: blockchain height of last signed key image, can be 0 if height unknown * note: sets status error on fail */ - virtual std::uint64_t importKeyImages(const std::vector> &signed_key_images, size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) = 0; + virtual std::uint64_t importKeyImages(const std::vector> &signed_key_images, std::size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) = 0; /** * brief: importKeyImages - * param: key_images - @@ -1603,7 +1580,7 @@ struct Wallet * return: true if succeeded * note: sets status error on fail */ - virtual bool importKeyImages(std::vector key_images, size_t offset=0, boost::optional> selected_transfers = boost::none) = 0; + virtual bool importKeyImages(std::vector key_images, std::size_t offset=0, std::unordered_set selected_transfers = {}) = 0; // TODO : wallet2::signed_tx_set /** * brief: importKeyImages - From d39fc1f6569ce9b4f7a6c5a4da6d3a8847003984 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Sun, 22 Sep 2024 17:25:43 +0200 Subject: [PATCH 09/25] rbrunner7 review round 3 --- src/wallet/api/wallet.cpp | 3 +-- src/wallet/api/wallet2_api.h | 12 ++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index eb60aa4898..11314ac1ed 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3135,8 +3135,7 @@ void WalletImpl::getEnoteDetails(std::vector enote_details) const ed.m_key_image = td.m_key_image; ed.m_mask = td.m_mask; ed.m_amount = td.m_mask; - ed.m_rct = td.m_rct; -// ed.m_protocol_version = td.m_rct ? EnoteDetails::rct : EnoteDetails::cn; + ed.m_protocol_version = td.m_rct ? EnoteDetails::rct : EnoteDetails::cn; ed.m_key_image_known = td.m_key_image_known; ed.m_key_image_request = td.m_key_image_request; ed.m_pk_index = td.m_pk_index; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 2fdbb9cb8e..76ea1aa374 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -97,12 +97,8 @@ struct EnoteDetails std::string m_mask; // a std::uint64_t m_amount; - // QUESTION : Should we change m_rct to this enum to be prepared for the future? We could also add CryptoNote as cn before rct if that would make sense!? -// enum { rct, fcmp } m_protocol_version; - // or -// enum { cn, rct, fcmp } m_protocol_version; - // is ring confidential transaction - bool m_rct; + // protocol version : cn = CryptoNote, rct = RingCT + enum { cn, rct } m_protocol_version; // is key image known bool m_key_image_known; // view wallets: we want to request it; cold wallets: it was requested @@ -226,8 +222,6 @@ struct TransactionInfo Direction_Out }; - // QUESTION : We already have a bool for "pending" and "failed", but should we rather add two more bools (`m_pending_in_pool` & `m_confirmed`) or switch to an enum like this? I'd prefer the enum, but I guess removing `m_pending` and `m_failed` is not an option? - // If there is justificatin to keep this, any suggestions for a better name? E.g. TxTransmissionState? enum TxState { pending, pending_in_pool, @@ -243,7 +237,9 @@ struct TransactionInfo virtual ~TransactionInfo() = 0; virtual int direction() const = 0; + // legacy : use txState() instead virtual bool isPending() const = 0; + // legacy : use txState() instead virtual bool isFailed() const = 0; virtual bool isCoinbase() const = 0; virtual uint64_t amount() const = 0; From 7cddeb25d64d1720bc65615b75bd9bf344f1c87f Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 23 Sep 2024 18:20:26 +0200 Subject: [PATCH 10/25] clean up, work on TODOs --- src/wallet/api/wallet.cpp | 87 +++++++++++++++++++++++++++--------- src/wallet/api/wallet.h | 9 ++-- src/wallet/api/wallet2_api.h | 24 +++++----- 3 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 11314ac1ed..927027d2c7 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2868,7 +2868,7 @@ uint64_t WalletImpl::getBytesSent() } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::getMultisigSeed(const std::string &seed_offset) +std::string WalletImpl::getMultisigSeed(const std::string &seed_offset) const { clearStatus(); @@ -2892,7 +2892,7 @@ std::string WalletImpl::getMultisigSeed(const std::string &seed_offset) return ""; } //------------------------------------------------------------------------------------------------------------------- -std::pair WalletImpl::getSubaddressIndex(const std::string &address) +std::pair WalletImpl::getSubaddressIndex(const std::string &address) const { clearStatus(); @@ -2969,7 +2969,7 @@ void WalletImpl::thaw(const std::string &key_image) } } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::isFrozen(std::size_t idx) +bool WalletImpl::isFrozen(std::size_t idx) const { clearStatus(); @@ -2986,7 +2986,7 @@ bool WalletImpl::isFrozen(std::size_t idx) return false; } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::isFrozen(const std::string &key_image) +bool WalletImpl::isFrozen(const std::string &key_image) const { try { @@ -3009,7 +3009,7 @@ void WalletImpl::createOneOffSubaddress(std::uint32_t account_index, std::uint32 // m_subaddressAccount->refresh(); } //------------------------------------------------------------------------------------------------------------------- -WalletState WalletImpl::getWalletState() +WalletState WalletImpl::getWalletState() const { WalletState wallet_state{}; @@ -3145,7 +3145,7 @@ void WalletImpl::getEnoteDetails(std::vector enote_details) const } } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisig_ptx) +std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const { clearStatus(); @@ -3167,7 +3167,7 @@ std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisi return ""; } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename) +bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename) const { clearStatus(); @@ -3189,7 +3189,7 @@ bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptxs, const s return false; } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs) +std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs) const { clearStatus(); @@ -3202,7 +3202,7 @@ std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs) return tx_dump; } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) +bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const { return m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set); } @@ -3228,7 +3228,7 @@ std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, Pen return signed_tx_data; } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) +bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const { clearStatus(); @@ -3281,12 +3281,12 @@ bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, Pend // return false; //} //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::getFeeMultiplier(std::uint32_t priority, int fee_algorithm) +std::uint64_t WalletImpl::getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const { return m_wallet->get_fee_multiplier(priority, fee_algorithm); } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::getBaseFee() +std::uint64_t WalletImpl::getBaseFee() const { bool use_dyn_fee = useForkRules(HF_VERSION_DYNAMIC_FEE, -30 * 1); if (!use_dyn_fee) @@ -3311,7 +3311,7 @@ std::uint32_t WalletImpl::adjustPriority(std::uint32_t priority) return 0; } //------------------------------------------------------------------------------------------------------------------- -void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) +void WalletImpl::coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const { clearStatus(); @@ -3325,6 +3325,27 @@ void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &dsts_info) const +{ + clearStatus(); + + try + { + tools::wallet2::signed_tx_set signed_txs; + + m_wallet->cold_sign_tx(ptx_in->m_pending_tx, signed_txs, dsts_info, exported_txs_out->m_tx_device_aux); + exported_txs_out->m_key_images = signed_txs.key_images; + exported_txs_out->m_pending_tx = signed_txs.ptx; + // TODO : figure out if we need signed_txs.tx_key_images here, afaik they're used for selfsend/change enotes + // if needed we can probably add a member like `m_selfsend_key_images` to `PendingTransaction` + // guess then `PendingTransaction` would be a proper replacement for `wallet2::signed_tx_set` + } + catch (const std::exception &e) + { + setStatusError(e.what()); + } +} +//------------------------------------------------------------------------------------------------------------------- void WalletImpl::discardUnmixableOutputs() { clearStatus(); @@ -3392,7 +3413,7 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co } } //------------------------------------------------------------------------------------------------------------------- -const std::pair, std::vector>& WalletImpl::getAccountTags() +const std::pair, std::vector>& WalletImpl::getAccountTags() const { return m_wallet->get_account_tags(); } @@ -3425,7 +3446,7 @@ void WalletImpl::setAccountTagDescription(const std::string &tag, const std::str } } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::exportOutputsToStr(bool all, std::uint32_t start, std::uint32_t count) +std::string WalletImpl::exportOutputsToStr(bool all, std::uint32_t start, std::uint32_t count) const { clearStatus(); @@ -3455,7 +3476,7 @@ std::size_t WalletImpl::importOutputsFromStr(const std::string &outputs_str) return 0; } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) +std::uint64_t WalletImpl::getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const { clearStatus(); @@ -3470,7 +3491,7 @@ std::uint64_t WalletImpl::getBlockchainHeightByDate(std::uint16_t year, std::uin return 0; } //------------------------------------------------------------------------------------------------------------------- -std::vector> WalletImpl::estimateBacklog(const std::vector> &fee_levels) +std::vector> WalletImpl::estimateBacklog(const std::vector> &fee_levels) const { clearStatus(); @@ -3485,7 +3506,7 @@ std::vector> WalletImpl::estimateBacklog return { std::make_pair(0, 0) }; } //------------------------------------------------------------------------------------------------------------------- -std::vector> WalletImpl::estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) +std::vector> WalletImpl::estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const { clearStatus(); @@ -3512,17 +3533,17 @@ std::vector> WalletImpl::estimateBacklog return estimateBacklog(fee_levels); } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) +bool WalletImpl::saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const { return m_wallet->save_to_file(path_to_file, binary, is_printable); } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) +bool WalletImpl::loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const { return m_wallet->load_from_file(path_to_file, target_str, max_size); } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::hashTransfers(std::uint64_t transfer_height, std::string &hash) +std::uint64_t WalletImpl::hashTransfers(std::uint64_t transfer_height, std::string &hash) const { clearStatus(); @@ -3552,7 +3573,29 @@ void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t transfer_height, cons } } //------------------------------------------------------------------------------------------------------------------- -std::pair WalletImpl::estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) +std::vector> WalletImpl::getPublicNodes(bool white_only = true) const +{ + clearStatus(); + + std::vector public_nodes; + std::vector> public_nodes_out; + try + { + public_nodes m_wallet->get_public_nodes(white_only); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to get public nodes. Error: %s")) % e.what()).str()); + return std::vector>{}; + } + + for (auto pub_node : public_nodes) + public_nodes_out.push_back(std::tuple{pub_note.host, pub_note.rpc_port, pub_note.last_seen}); + + return public_nodes_out; +} +//------------------------------------------------------------------------------------------------------------------- +std::pair WalletImpl::estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) const { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 5c7f6679e7..3a304e4fca 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -255,16 +255,14 @@ class WalletImpl : public Wallet bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; -// bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; std::uint64_t getBaseFee() const override; - std::uint32_t adjustPriority(std::uint32_t priority) const override; + std::uint32_t adjustPriority(std::uint32_t priority) override; void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const override; -// void coldSignTx(const std::vector& ptx_vector, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const override; -// const wallet2::transfer_details &getTransferDetails(std::size_t idx) const override; + void coldSignTx(const PendingTransaction &ptx_in, PendingTransaction &exported_txs_out, std::vector &dsts_info) const override; void discardUnmixableOutputs() override; void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const std::string &single_destination_subaddress) override; - const std::pair, std::vector>& getAccountTags() override; + const std::pair, std::vector>& getAccountTags() const override; void setAccountTag(const std::set &account_indices, const std::string &tag) override; void setAccountTagDescription(const std::string &tag, const std::string &description) override; std::string exportOutputsToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const override; @@ -276,6 +274,7 @@ class WalletImpl : public Wallet bool loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const override; std::uint64_t hashTransfers(std::uint64_t transfer_height, std::string &hash) const override; void finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) override; + std::vector> getPublicNodes(bool white_only = true) const override; std::pair estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) const override; std::uint64_t importKeyImages(const std::vector> &signed_key_images, std::size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) override; bool importKeyImages(std::vector key_images, std::size_t offset = 0, std::unordered_set selected_transfers = {}) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 76ea1aa374..733513fad4 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -41,6 +41,7 @@ #include #include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/cryptonote_basic_impl.h" // Public interface for libwallet library namespace Monero { @@ -74,6 +75,7 @@ enum NetworkType : uint8_t { */ struct EnoteDetails { + // QUESTION : If this struct is done, should I create the files "src/wallet/api/enote_details.[h/cpp]", put all the member variables inside the header and only set virtual getter functions in here, like it's done for other structs below? // Ko std::string m_onetime_address; // view_tag @@ -1341,8 +1343,6 @@ struct Wallet * return: true if succeeded */ virtual bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const = 0; - // TODO / QUESTION : How to translate the following types to a standard type for the API? - // - cryptonote::address_parse_info /** * brief: signTxToStr - get a signed pending transaction from an unsigned transaction * param: exported_txs - unsigned transaction @@ -1412,7 +1412,7 @@ struct Wallet * return: adjusted priority * note: sets status error on fail */ - virtual std::uint32_t adjustPriority(std::uint32_t priority) const = 0; + virtual std::uint32_t adjustPriority(std::uint32_t priority) = 0; // QUESTION : Any suggestion for the function description below? /** * brief: coldTxAuxImport - @@ -1421,15 +1421,13 @@ struct Wallet * note: sets status error on fail */ virtual void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const = 0; -// TODO : wallet2::signed_tx_set & cryptonote::address_parse_info /** * brief: coldSignTx - - * param: ptx - - * param: exported_txs - + * param: ptx_in - + * outparam: exported_txs_out - * param: dsts_info - - * param: tx_device_aux - */ -// virtual void coldSignTx(const PendingTransaction &ptx, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux) const = 0; + virtual void coldSignTx(const PendingTransaction &ptx_in, PendingTransaction &exported_txs_out, std::vector &dsts_info) const = 0; /** * brief: discardUnmixableOutputs - freeze all unmixable outputs * note: sets status error on fail @@ -1448,7 +1446,7 @@ struct Wallet * brief: getAccountTags - get the list of registered account tags * return: first.Key=(tag's name), first.Value=(tag's label), second[i]=(i-th account's tag) */ - virtual const std::pair, std::vector>& getAccountTags() = 0; + virtual const std::pair, std::vector>& getAccountTags() const = 0; /** * brief: setAccountTag - set a tag to a set of subaddress accounts by index * param: account_index - major index @@ -1537,15 +1535,13 @@ struct Wallet * note: sets status error on fail */ virtual void finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) = 0; -// QUESTION : Should we just `#include "rpc/core_rpc_server_commands_defs.h"` for cryptonote::public_node? -// TODO : cryptonote::public_node /** - * brief: getPublicNodes - + * brief: getPublicNodes - get a list of public notes with information when they were last seen * param: white_only - include gray nodes if false (default: true) - * return: vector of public nodes + * return: [ [ host_ip, host_rpc_port, last_seen ], ... ] * note: sets status error on fail */ -// virtual std::vector getPublicNodes(bool white_only = true) const = 0; + virtual std::vector> getPublicNodes(bool white_only = true) const = 0; /** * brief: estimateTxSizeAndWeight - * param: use_rct - From e92942fb1be2f4ac2a8fa2b126c4129d0aa94343 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 23 Sep 2024 18:21:04 +0200 Subject: [PATCH 11/25] remove accept function from loadTx() --- src/wallet/api/wallet.cpp | 8 ++++++-- src/wallet/api/wallet.h | 1 + src/wallet/api/wallet2_api.h | 5 ++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 927027d2c7..64d302a677 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1161,8 +1161,7 @@ bool WalletImpl::submitTransaction(const string &fileName) { return false; std::unique_ptr transaction(new PendingTransactionImpl(*this)); - // TODO : use WalletImpl::loadTx() if ready - bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx); + bool r = m_wallet->loadTx(fileName, transaction); if (!r) { setStatus(Status_Ok, tr("Failed to load transaction from file")); return false; @@ -3228,6 +3227,11 @@ std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, Pen return signed_tx_data; } //------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::loadTx(const std::string &signed_filename, PendingTransaction &ptx) const +{ + return m_wallet->load_tx(signed_filename, ptx.m_pending_tx); +} +//------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 3a304e4fca..fc62ad8757 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -254,6 +254,7 @@ class WalletImpl : public Wallet std::string convertTxToStr(const PendingTransaction &ptxs) const override; bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const override; + bool loadTx(const std::string &signed_filename, PendingTransaction &ptx) const override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; std::uint64_t getBaseFee() const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 733513fad4..c499db51dd 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1351,15 +1351,14 @@ struct Wallet * note: sets status error on fail */ virtual std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const = 0; -// TODO : accept_func with wallet2::signed_tx_set + // TODO : if it's fine to drop the accept_func, do it for all the functions below /** * brief: loadTx - load pending transactions from a file * param: signed_filename - * outparam: ptx - - * param: accept_func - callback function to verify the transaction * return: true if succeeded */ -// virtual bool loadTx(const std::string &signed_filename, PendingTransaction &ptx, std::function accept_func) const = 0; + virtual bool loadTx(const std::string &signed_filename, PendingTransaction &ptx) const = 0; // TODO : accept_func with wallet2::signed_tx_set /** * brief: parseTxFromStr - get transactions from encrypted signed transaction as hex string From 50d5711e838fd6b4ba7a4368291fde0225075c3c Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Fri, 27 Sep 2024 19:04:13 +0200 Subject: [PATCH 12/25] clean-up, work on TODOs and QUESTIONs --- src/wallet/api/wallet.cpp | 29 +++++++---------------------- src/wallet/api/wallet.h | 15 ++++----------- src/wallet/api/wallet2_api.h | 14 ++------------ src/wallet/api/wallet_manager.cpp | 2 +- 4 files changed, 14 insertions(+), 46 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 64d302a677..136c3ccfad 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -525,7 +525,6 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas bool keys_file_exists; bool wallet_file_exists; - // QUESTION / TODO : same as above tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); LOG_PRINT_L3("wallet_path: " << path << ""); LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha @@ -538,7 +537,6 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas setStatusError(error); return false; } - // TODO : Should we create a `WalletImpl` object for `view_wallet` instead of just using the `wallet2`? Figure out if that's even possible without much hassle. Then we can use the proposed `setSeedLanguage()` which also validates the language. // TODO: validate language view_wallet->set_seed_language(language); @@ -550,9 +548,6 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas view_wallet->generate(path, password, address, viewkey); // Export/Import outputs - // TODO : Depends on question from above, if `view_wallet` becomes `WalletImpl`. -// std::string outputs = exportOutputsToStr(true/*all*/); -// view_wallet->importOutputsFromStr(outputs); auto outputs = m_wallet->export_outputs(true/*all*/); view_wallet->import_outputs(outputs); @@ -566,7 +561,6 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas // copy confirmed outgoing payments std::list> out_payments; - // TODO : Depends on question from above, if `view_wallet` becomes `WalletImpl` & `getPaymentsOut()` is not implemented yet m_wallet->get_payments_out(out_payments, 0); view_wallet->import_payments_out(out_payments); @@ -584,7 +578,6 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas return false; } // Store wallet - // TODO : Depends on question from above, if `view_wallet` becomes `WalletImpl`. view_wallet->store(); return true; } @@ -1735,7 +1728,8 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectormakeMultisigTxSet(transaction->m_pending_tx); + transaction->m_signers = tx_set.m_signers; } } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? @@ -2931,7 +2925,7 @@ void WalletImpl::freeze(const std::string &key_image) { try { - freeze(getTransferIndex(key_image)); + freeze(getEnoteIndex(key_image)); } catch (const std::exception &e) { @@ -2959,7 +2953,7 @@ void WalletImpl::thaw(const std::string &key_image) { try { - thaw(getTransferIndex(key_image)); + thaw(getEnoteIndex(key_image)); } catch (const std::exception &e) { @@ -2989,7 +2983,7 @@ bool WalletImpl::isFrozen(const std::string &key_image) const { try { - return isFrozen(getTransferIndex(key_image)); + return isFrozen(getEnoteIndex(key_image)); } catch (const std::exception &e) { @@ -3656,7 +3650,7 @@ std::uint64_t importKeyImages(const std::vector key_images, std::size_t offset, std::unordered_set selected_transfers) +bool WalletImpl::importKeyImages(std::vector key_images, std::size_t offset, std::unordered_set selected_transfers) { clearStatus(); @@ -3689,7 +3683,7 @@ bool importKeyImages(std::vector key_images, std::size_t offset, st //------------------------------------------------------------------------------------------------------------------- // PRIVATE //------------------------------------------------------------------------------------------------------------------- -std::size_t WalletImpl::getTransferIndex(const std::string &key_image) +std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) { crypto::key_image ki; if (!epee::string_tools::hex_to_pod(key_image, ki)) @@ -3698,14 +3692,5 @@ std::size_t WalletImpl::getTransferIndex(const std::string &key_image) return m_wallet->get_transfer_details(ki); } //------------------------------------------------------------------------------------------------------------------- -void WalletImpl::makeMultisigTxSet(PendingTransaction &ptx) -{ - if (!ptx->m_wallet->multisig().isMultisig) - throw runtime_error(tr("Wallet is not multisig")); - - auto multisig_tx = m_wallet->make_multisig_tx_set(ptx.m_pending_tx); - ptx.m_signers = multisig_tx.m_signers; -} -//------------------------------------------------------------------------------------------------------------------- } // namespace diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index fc62ad8757..95ce7b664d 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -294,19 +294,12 @@ class WalletImpl : public Wallet bool doInit(const std::string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit = 0, bool ssl = false); bool checkBackgroundSync(const std::string &message) const; - // QUESTION : Should I remove the private functions from this PR and work on them in another one? /** - * brief: getTransferIndex - get the index of a stored transfer - * param: key_image - key image of transfer - * return: index in transfer storage + * brief: getEnoteIndex - get the index of an enote in local enote storage + * param: key_image - key image to identify the enote + * return: enote index */ - std::size_t getTransferIndex(const std::string &key_image) const; - // TODO : consider changing the name and/or move to PendingTransaction - /** - * brief: makeMultisigTxSet - add multisig signers to pending transaction - * param: ptx - - */ - void makeMultisigTxSet(PendingTransaction &ptx) const; + std::size_t getEnoteIndex(const std::string &key_image) const; private: friend class PendingTransactionImpl; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index c499db51dd..c7711e6740 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1351,7 +1351,7 @@ struct Wallet * note: sets status error on fail */ virtual std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const = 0; - // TODO : if it's fine to drop the accept_func, do it for all the functions below + // TODO : if it's fine to drop the accept_func, do it for all the functions below (where possible, meaning accept_func is optional in wallet2 params) /** * brief: loadTx - load pending transactions from a file * param: signed_filename - @@ -1571,17 +1571,7 @@ struct Wallet * return: true if succeeded * note: sets status error on fail */ - virtual bool importKeyImages(std::vector key_images, std::size_t offset=0, std::unordered_set selected_transfers = {}) = 0; -// TODO : wallet2::signed_tx_set - /** - * brief: importKeyImages - - * param: signed_tx - - * param: offset - offset in local transfer storage - * param: only_selected_transfers - - * return: true if succeeded - * note: sets status error on fail - */ -// virtual bool importKeyImages(signed_tx_set & signed_tx, size_t offset=0, bool only_selected_transfers = false) = 0; + virtual bool importKeyImages(std::vector key_images, std::size_t offset = 0, std::unordered_set selected_transfers = {}) = 0; }; /** diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index d013aaf825..94886b727d 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -231,7 +231,7 @@ std::string WalletManagerImpl::errorString() const return m_errorString; } -// TODO : figure out if this is a sufficient replacement for wallet2::set_daemon() +// TODO : figure out if we rather modify this to take daemon_login, trusted_daemon and ssl_options as arguments, so this function acts as a replacement for `wallet2::set_daemon()` or should we add a new `setDaemon()` to `WalletImpl` void WalletManagerImpl::setDaemonAddress(const std::string &address) { m_http_client.set_server(address, boost::none); From 14d35de523faf99cd266894d9dd6d0f7addcc94b Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Fri, 27 Sep 2024 19:30:25 +0200 Subject: [PATCH 13/25] rbrunner7 review round 4: rename outputs to enotes --- src/wallet/api/wallet.cpp | 14 +++++++------- src/wallet/api/wallet.h | 8 ++++---- src/wallet/api/wallet2_api.h | 33 +++++++++++++++++---------------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 136c3ccfad..26dc7eed2f 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1232,7 +1232,7 @@ bool WalletImpl::exportOutputs(const string &filename, bool all) try { - std::string data = exportOutputsToStr(all); + std::string data = exportEnotesToStr(all); bool r = saveToFile(filename, data); if (!r) { @@ -1273,7 +1273,7 @@ bool WalletImpl::importOutputs(const string &filename) try { - size_t n_outputs = importOutputsFromStr(data); + size_t n_outputs = importEnotesFromStr(data); if (status() != Status_Ok) throw runtime_error(errorString()); LOG_PRINT_L2(std::to_string(n_outputs) << " outputs imported"); @@ -3344,7 +3344,7 @@ void WalletImpl::coldSignTx(const PendingTransaction &ptx_in, PendingTransaction } } //------------------------------------------------------------------------------------------------------------------- -void WalletImpl::discardUnmixableOutputs() +void WalletImpl::discardUnmixableEnotes() { clearStatus(); @@ -3354,7 +3354,7 @@ void WalletImpl::discardUnmixableOutputs() } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to discard unmixable outputs. Error: %s")) % e.what()).str()); + setStatusError((boost::format(tr("Failed to discard unmixable enotes. Error: %s")) % e.what()).str()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3444,7 +3444,7 @@ void WalletImpl::setAccountTagDescription(const std::string &tag, const std::str } } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::exportOutputsToStr(bool all, std::uint32_t start, std::uint32_t count) const +std::string WalletImpl::exportEnotesToStr(bool all, std::uint32_t start, std::uint32_t count) const { clearStatus(); @@ -3459,13 +3459,13 @@ std::string WalletImpl::exportOutputsToStr(bool all, std::uint32_t start, std::u return ""; } //------------------------------------------------------------------------------------------------------------------- -std::size_t WalletImpl::importOutputsFromStr(const std::string &outputs_str) +std::size_t WalletImpl::importEnotesFromStr(const std::string &enotes_str) { clearStatus(); try { - return m_wallet->import_outputs_from_str(outputs_str); + return m_wallet->import_outputs_from_str(enotes_str); } catch (const std::exception &e) { diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 95ce7b664d..c6305db32a 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -243,7 +243,7 @@ class WalletImpl : public Wallet bool isFrozen(std::size_t idx) const override; bool isFrozen(const std::string &key_image) const override; void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) override; - virtual WalletState getWalletState() const = 0; + WalletState getWalletState() const override; void rewriteWalletFile(const std::string &wallet_name, const std::string &password) override; void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; @@ -261,13 +261,13 @@ class WalletImpl : public Wallet std::uint32_t adjustPriority(std::uint32_t priority) override; void coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const override; void coldSignTx(const PendingTransaction &ptx_in, PendingTransaction &exported_txs_out, std::vector &dsts_info) const override; - void discardUnmixableOutputs() override; + void discardUnmixableEnotes() override; void setTxKey(const std::string &txid, const std::string &tx_key, const std::vector &additional_tx_keys, const std::string &single_destination_subaddress) override; const std::pair, std::vector>& getAccountTags() const override; void setAccountTag(const std::set &account_indices, const std::string &tag) override; void setAccountTagDescription(const std::string &tag, const std::string &description) override; - std::string exportOutputsToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const override; - std::size_t importOutputsFromStr(const std::string &outputs_str) override; + std::string exportEnotesToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const override; + std::size_t importEnotesFromStr(const std::string &enotes_str) override; std::uint64_t getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const override; std::vector> estimateBacklog(const std::vector> &fee_levels) const override; std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index c7711e6740..f515076ae1 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -83,9 +83,9 @@ struct EnoteDetails // this enote was received at block height std::uint64_t m_block_height; // relative index in tx - std::uint64_t m_internal_output_index; + std::uint64_t m_internal_enote_index; // absolute index from `cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry.output_indices` - std::uint64_t m_global_output_index; + std::uint64_t m_global_enote_index; // is spent bool m_spent; // is frozen @@ -1428,10 +1428,10 @@ struct Wallet */ virtual void coldSignTx(const PendingTransaction &ptx_in, PendingTransaction &exported_txs_out, std::vector &dsts_info) const = 0; /** - * brief: discardUnmixableOutputs - freeze all unmixable outputs + * brief: discardUnmixableEnotes - freeze all unmixable enotes * note: sets status error on fail */ - virtual void discardUnmixableOutputs() = 0; + virtual void discardUnmixableEnotes() = 0; /** * brief: setTxKey - set the transaction key (r) for a given in case the tx was made by some other device or 3rd party wallet * param: txid - @@ -1461,21 +1461,22 @@ struct Wallet */ virtual void setAccountTagDescription(const std::string &tag, const std::string &description) = 0; /** - * brief: exportOutputsToStr - export outputs and return encrypted data - * param: all - go from `start` for `count` outputs if true, else go incremental from last exported output for `count` outputs (default: false) - * param: start - offset index in transfer storage, needs to be 0 for incremental mode (default: 0) - * param: count - try to export this amount of outputs (default: 0xffffffff) - * return: encrypted data as hex string if succeeded, else empty string + * brief: exportEnotesToStr - export enotes and return encrypted data + * (comparable with legacy exportOutputs(), with the difference that this returns a string, the other one saves to file) + * param: all - go from `start` for `count` enotes if true, else go incremental from last exported enote for `count` enotes (default: false) + * param: start - offset index in enote storage, needs to be 0 for incremental mode (default: 0) + * param: count - try to export this amount of enotes (default: 0xffffffff) + * return: encrypted data of exported enotes as hex string if succeeded, else empty string * note: sets status error on fail */ - virtual std::string exportOutputsToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const = 0; + virtual std::string exportEnotesToStr(bool all = false, std::uint32_t start = 0, std::uint32_t count = 0xffffffff) const = 0; /** - * brief: importOutputsFromStr - import outputs from encrypted hex string - * param: outputs_str - outputs data as encrypted hex string - * return: total size of transfer storage + * brief: importEnotesFromStr - import enotes from encrypted hex string + * param: enotes_str - enotes data as encrypted hex string + * return: total size of enote storage * note: sets status error on fail */ - virtual std::size_t importOutputsFromStr(const std::string &outputs_str) = 0; + virtual std::size_t importEnotesFromStr(const std::string &enotes_str) = 0; /** * brief: getBlockchainHeightByDate - * param: year - @@ -1544,9 +1545,9 @@ struct Wallet /** * brief: estimateTxSizeAndWeight - * param: use_rct - - * param: n_inputs - number of inputs + * param: n_inputs - number of input enotes * param: ring_size - - * param: n_outputs - number of outputs + * param: n_outputs - number of output enotes * param: extra_size - size of tx_extra * return: [estimated tx size, estimated tx weight] * note: sets status error on fail From 11f698de06e47a4ba69e3153c0c276f85a56b4cc Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Fri, 27 Sep 2024 21:14:13 +0200 Subject: [PATCH 14/25] rbrunner7 review round 4: writeWatchOnlyWallet; remove QUESTIONs --- src/wallet/api/wallet.cpp | 4 ++-- src/wallet/api/wallet.h | 2 +- src/wallet/api/wallet2_api.h | 12 +++--------- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 26dc7eed2f..8ec4503072 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3028,13 +3028,13 @@ void WalletImpl::rewriteWalletFile(const std::string &wallet_name, const std::st } } //------------------------------------------------------------------------------------------------------------------- -void WalletImpl::writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) +void WalletImpl::writeWatchOnlyWallet(const std::string &password, std::string &new_keys_file_name) { clearStatus(); try { - m_wallet->write_watch_only_wallet(wallet_name, epee::wipeable_string(password.data(), password.size()), new_keys_file_name); + m_wallet->write_watch_only_wallet(m_wallet->get_wallet_file(), epee::wipeable_string(password.data(), password.size()), new_keys_file_name); } catch (const std::exception &e) { diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c6305db32a..c0c38828b5 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -245,7 +245,7 @@ class WalletImpl : public Wallet void createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) override; WalletState getWalletState() const override; void rewriteWalletFile(const std::string &wallet_name, const std::string &password) override; - void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) override; + void writeWatchOnlyWallet(const std::string &password, std::string &new_keys_file_name) override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; void processPoolState(const std::vector> &txs) override; void getEnoteDetails(std::vector enote_details) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index f515076ae1..12c9fc3b76 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -94,7 +94,6 @@ struct EnoteDetails std::uint64_t m_spent_height; // key image std::string m_key_image; - // QUESTION : Is this comment correct? (This is the `rct::key m_mask` from wallet2::transfer_details) // x, blinding factor in amount commitment C = x G + a H std::string m_mask; // a @@ -368,8 +367,6 @@ struct SubaddressAccountRow { std::string m_balance; std::string m_unlockedBalance; public: - // QUESTION : afaik this is unused, can we remove it? - std::string extra; std::string getAddress() const {return m_address;} std::string getLabel() const {return m_label;} std::string getBalance() const {return m_balance;} @@ -1166,7 +1163,6 @@ struct Wallet virtual void setOffline(bool offline) = 0; virtual bool isOffline() const = 0; - // QUESTION : Removing these three functions should be done in a separate PR? //! blackballs a set of outputs virtual bool blackballOutputs(const std::vector &outputs, bool add) = 0; @@ -1222,9 +1218,9 @@ struct Wallet virtual uint64_t getBytesSent() = 0; /** - * brief: getMultisigSeed - get mnemonic seed phrase for multisig wallet + * brief: getMultisigSeed - get seed for multisig wallet * param: seed_offset - passphrase - * return: mnemonic seed phrase if succeeded, else empty string + * return: seed if succeeded, else empty string * note: sets status error on fail */ virtual std::string getMultisigSeed(const std::string &seed_offset) const = 0; @@ -1278,15 +1274,13 @@ struct Wallet * note: sets status error on fail */ virtual void rewriteWalletFile(const std::string &wallet_name, const std::string &password) = 0; - // QUESTION : Should we change this function from the current behavior in wallet2, so `wallet_name` is just the name of the new wallet instead of changing the `m_wallet_file` for the current wallet? /** * brief: writeWatchOnlyWallet - create a new watch-only wallet file with view keys from current wallet - * param: wallet_name - name of the current wallet file * param: password - password for new watch-only wallet * outparam: new_keys_file_name - wallet_name + "-watchonly.keys" * note: sets status error on fail */ - virtual void writeWatchOnlyWallet(const std::string &wallet_name, const std::string &password, std::string &new_keys_file_name) = 0; + virtual void writeWatchOnlyWallet(const std::string &password, std::string &new_keys_file_name) = 0; /** * brief: updatePoolState - * outparam: process_txs - [ [tx, tx_id, double_spend_seen], ... ] From 6fafd267bc929f2e0fe7aac707f9d6e8ae9dee73 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 30 Sep 2024 17:52:28 +0200 Subject: [PATCH 15/25] work on TODOs & QUESTIONs --- src/wallet/api/wallet.cpp | 66 ++++++++++++++---------------------- src/wallet/api/wallet2_api.h | 8 +++++ 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 8ec4503072..34bd4d297f 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -401,6 +401,12 @@ uint64_t Wallet::maximumAllowedAmount() return std::numeric_limits::max(); } +bool Wallet::walletExists(const std::string &path, bool &key_file_exists, bool &wallet_file_exists) +{ + tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); + return (keys_file_exists || wallet_file_exists) +} + void Wallet::init(const char *argv0, const char *default_log_base_name, const std::string &log_path, bool console) { #ifdef WIN32 // Activate UTF-8 support for Boost filesystem classes on Windows @@ -485,8 +491,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co m_recoveringFromDevice = false; bool keys_file_exists; bool wallet_file_exists; - // QUESTION : I think we can change `WalletManagerImpl::walletExists()` which returns true if `key_file_exists` is true, to take the same outparams as `tools::wallet2::wallet_exists()` (but make them optional) and make the method static. Or do you think it's easier/cleaner to add `WalletImpl::walletExists()` with the described behaviour and leave the one in `WalletManagerImpl` as is? - tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); + Wallet::walletExists(path, keys_file_exists, wallet_file_exists); LOG_PRINT_L3("wallet_path: " << path << ""); LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha << " wallet_file_exists: " << std::boolalpha << wallet_file_exists << std::noboolalpha); @@ -499,7 +504,6 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co setStatusCritical(error); return false; } - // TODO: validate language setSeedLanguage(language); crypto::secret_key recovery_val, secret_key; try { @@ -525,7 +529,7 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas bool keys_file_exists; bool wallet_file_exists; - tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); + Wallet::walletExists(path, keys_file_exists, wallet_file_exists); LOG_PRINT_L3("wallet_path: " << path << ""); LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha << " wallet_file_exists: " << std::boolalpha << wallet_file_exists << std::noboolalpha); @@ -719,10 +723,7 @@ bool WalletImpl::open(const std::string &path, const std::string &password) // Check if wallet cache exists bool keys_file_exists; bool wallet_file_exists; - // QUESTION / TODO : same as above, actually here we could just do: -// if(!WalletManagerImpl::walletExists(path)){ - // even though we check if `wallet_file_exists`, the comment states that we're actually interested in the .keys file. - tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); + Wallet::walletExists(path, keys_file_exists, wallet_file_exists); if(!wallet_file_exists){ // Rebuilding wallet cache, using refresh height from .keys file m_rebuildWalletCache = true; @@ -779,13 +780,13 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c return status() == Status_Ok; } -bool WalletImpl::close(bool store) +bool WalletImpl::close(bool do_store) { bool result = false; LOG_PRINT_L1("closing wallet..."); try { - if (store) { + if (do_store) { // Do not store wallet with invalid status // Status Critical refers to errors on opening or creating wallets. if (status() != Status_Critical) @@ -827,11 +828,10 @@ void WalletImpl::setSeedLanguage(const std::string &arg) if (checkBackgroundSync("cannot set seed language")) return; - // QUESTION : We have some ~8year old TODOs stating we should validate the seed language. Will this suffice or should I make another PR for that? - // IMO it'd make sense now to add `setStatusError()` to this so it doesn't just silently do nothing. If this can stay, remove old TODOs. - // Update : Actually after rebasing we now already set the status in the `checkBackgroundSync()` call above. if (crypto::ElectrumWords::is_valid_language(arg)) m_wallet->set_seed_language(arg); + else + setStatusError(string(tr("Failed to set seed language. Language not valid: ")) + arg); } int WalletImpl::status() const @@ -1642,8 +1642,6 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector(priority)); - // TODO : Consider adding a function that returns `status() == Status_Ok`: -// if (!isStatusOk()) if (status() != Status_Ok) { return transaction; @@ -1728,11 +1726,10 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vectormakeMultisigTxSet(transaction->m_pending_tx); + auto tx_set = m_wallet->make_multisig_tx_set(transaction->m_pending_tx); transaction->m_signers = tx_set.m_signers; } } catch (const tools::error::daemon_busy&) { - // TODO: make it translatable with "tr"? setStatusError(tr("daemon is busy. Please try again later.")); } catch (const tools::error::no_connection_to_daemon&) { setStatusError(tr("no connection to daemon. Please make sure daemon is running.")); @@ -1826,7 +1823,6 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction() pendingTxPostProcess(transaction); } catch (const tools::error::daemon_busy&) { - // TODO: make it translatable with "tr"? setStatusError(tr("daemon is busy. Please try again later.")); } catch (const tools::error::no_connection_to_daemon&) { setStatusError(tr("no connection to daemon. Please make sure daemon is running.")); @@ -1910,7 +1906,7 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vectorget_min_ring_size() - 1, destinations.size() + 1, extra_size, useForkRules(8, 0), @@ -2244,9 +2240,6 @@ std::string WalletImpl::signMessage(const std::string &message, const std::strin if (checkBackgroundSync("cannot sign message")) return ""; - // QUESTION : Can we get rid of this `clearStatus()`, because it's already called in `checkBackgroundSync()`, or should we leave this redundant call (I'd actually move it up to the top) so it's directly obvious that this `signMessage()` sets status error? - clearStatus(); - tools::wallet2::message_signature_type_t sig_type = sign_with_view_key ? tools::wallet2::sign_with_view_key : tools::wallet2::sign_with_spend_key; if (address.empty()) { @@ -2625,22 +2618,18 @@ void WalletImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height) const bool WalletImpl::useForkRules(uint8_t version, int64_t early_blocks) const { - return m_wallet->use_fork_rules(version,early_blocks); + clearStatus(); + + try + { + return m_wallet->use_fork_rules(version, early_blocks); + } + catch (const std::exception &e) + { + setStatusError((boost::format(tr("Failed to check if we use fork rules for version `%u` with `%d` early blocks. Error: %s")) % version % early_blocks % e.what()).str()); + } + return false; } -// QUESTION : The method above doesn't handle error, can I replace the body with the following in this PR? -//{ -// clearStatus(); -// -// try -// { -// return m_wallet->use_fork_rules(version, early_blocks); -// } -// catch (const std::exception &e) -// { -// setStatusError((boost::format(tr("Failed to check if we use fork rules for version `%u` with `%d` early blocks. Error: %s")) % version % early_blocks % e.what()).str()); -// } -// return false; -//} //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::blackballOutputs(const std::vector &outputs, bool add) @@ -2997,9 +2986,6 @@ bool WalletImpl::isFrozen(const std::string &key_image) const void WalletImpl::createOneOffSubaddress(std::uint32_t account_index, std::uint32_t address_index) { m_wallet->create_one_off_subaddress({account_index, address_index}); - // TODO : Figure out if we need to call one of those after creating the one off subaddress. -// m_subaddress->refresh(accountIndex); -// m_subaddressAccount->refresh(); } //------------------------------------------------------------------------------------------------------------------- WalletState WalletImpl::getWalletState() const diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 12c9fc3b76..fa14d5f892 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -768,6 +768,14 @@ struct Wallet return paymentIdFromAddress(str, testnet ? TESTNET : MAINNET); } static uint64_t maximumAllowedAmount(); + /** + * brief: walletExists - check if wallet file and .keys file exist for given path + * param: path - filename + * outparam: keys_file_exists - + * outparam: wallet_file_exists - + * return: true if (key_file_exists || wallet_file_exists) + */ + static bool walletExists(const std::string &path, bool &key_file_exists, bool &wallet_file_exists); // Easylogger wrapper static void init(const char *argv0, const char *default_log_base_name) { init(argv0, default_log_base_name, "", true); } static void init(const char *argv0, const char *default_log_base_name, const std::string &log_path, bool console); From 1ad0c552edc16019e40ffc3d7a335e1ea1ea3ef0 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 30 Sep 2024 19:26:36 +0200 Subject: [PATCH 16/25] improve error messages and handling --- src/wallet/api/wallet.cpp | 137 ++++++++++++++++++----------------- src/wallet/api/wallet2_api.h | 5 +- 2 files changed, 75 insertions(+), 67 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 34bd4d297f..45a7892ba2 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2626,7 +2626,7 @@ bool WalletImpl::useForkRules(uint8_t version, int64_t early_blocks) const } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to check if we use fork rules for version `%u` with `%d` early blocks. Error: %s")) % version % early_blocks % e.what()).str()); + setStatusError((boost::format(tr("Failed to check if fork rules for version `%u` with `%d` early blocks should be used: %s")) % version % early_blocks % e.what()).str()); } return false; } @@ -2854,15 +2854,11 @@ std::string WalletImpl::getMultisigSeed(const std::string &seed_offset) const { clearStatus(); - if (!multisig().isMultisig) - { - setStatusError(tr("Wallet is not multisig")); - return ""; - } - - epee::wipeable_string seed; try { + checkMultisigWalletReady(m_wallet); + + epee::wipeable_string seed; if (m_wallet->get_multisig_seed(seed, seed_offset)) return std::string(seed.data(), seed.size()); } @@ -2882,13 +2878,13 @@ std::pair WalletImpl::getSubaddressIndex(const std std::pair indices{0, 0}; if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address)) { - setStatusError(tr("Failed to parse address")); + setStatusError(string(tr("Failed to parse address: ") + address)); return indices; } auto index = m_wallet->get_subaddress_index(info.address); if (!index) - setStatusError(tr("Address doesn't belong to the wallet")); + setStatusError(string(tr("Address doesn't belong to the wallet: ") + address)); else indices = std::make_pair(index.major, index.minor); @@ -2906,7 +2902,7 @@ void WalletImpl::freeze(std::size_t idx) catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError((boost::format(tr("Failed to freeze enote with index `%zu`: %s")) % idx % e.what()).str()); } } //------------------------------------------------------------------------------------------------------------------- @@ -2919,7 +2915,7 @@ void WalletImpl::freeze(const std::string &key_image) catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError((boost::format(tr("Failed to freeze enote with key image `%s`: %s")) % key_image % e.what()).str()); } } //------------------------------------------------------------------------------------------------------------------- @@ -2934,7 +2930,7 @@ void WalletImpl::thaw(std::size_t idx) catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError((boost::format(tr("Failed to thaw enote with index `%zu`: %s")) % idx % e.what()).str()); } } //------------------------------------------------------------------------------------------------------------------- @@ -2947,7 +2943,7 @@ void WalletImpl::thaw(const std::string &key_image) catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError((boost::format(tr("Failed to thaw enote with key image `%s`: %s")) % key_image % e.what()).str()); } } //------------------------------------------------------------------------------------------------------------------- @@ -2962,7 +2958,7 @@ bool WalletImpl::isFrozen(std::size_t idx) const catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError((boost::format(tr("Failed to determine if enote with index `%zu` is frozen: %s")) % idx % e.what()).str()); } return false; @@ -2977,7 +2973,7 @@ bool WalletImpl::isFrozen(const std::string &key_image) const catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError((boost::format(tr("Failed to determine if enote with key image `%s` is frozen: %s")) % key_image % e.what()).str()); } return false; @@ -3010,7 +3006,7 @@ void WalletImpl::rewriteWalletFile(const std::string &wallet_name, const std::st catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError((boost::format(tr("Failed to rewrite wallet file with wallet name `%s`: %s")) % wallet_name % e.what()).str()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3025,7 +3021,7 @@ void WalletImpl::writeWatchOnlyWallet(const std::string &password, std::string & catch (const std::exception &e) { LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(e.what()); + setStatusError(string(tr("Failed to write watch only wallet: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3041,7 +3037,7 @@ void WalletImpl::updatePoolState(std::vector(tx), tx_id)) { - setStatusError(tr("Failed to parse tx_id")); + setStatusError(string(tr("Failed to parse tx_id: ")) + std::get<1>(tx)); return; } process_txs.push_back(std::make_tuple(std::get<0>(tx), tx_id, std::get<2>(tx))); @@ -3068,7 +3064,7 @@ void WalletImpl::processPoolState(const std::vector(tx), tx_id)) { - setStatusError(tr("Failed to parse tx_id")); + setStatusError(string(tr("Failed to parse tx_id: ")) + std::get<1>(tx)); return; } txs_pod.push_back(std::make_tuple(std::get<0>(tx), tx_id, std::get<2>(tx))); @@ -3081,7 +3077,7 @@ void WalletImpl::processPoolState(const std::vectordump_tx_to_str(ptxs.m_pending_tx); if (tx_dump.empty()) - { - setStatusError("Failed to convert pending tx to string"); - } + setStatusError(tr("Failed to convert pending tx to string")); return tx_dump; } //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const { - return m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set); + if (!m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set)) + { + setStatusError(tr("Failed to parse unsigned tx from string. For more info see log file")); + return false; + } + return true; } //------------------------------------------------------------------------------------------------------------------- std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const @@ -3200,7 +3199,7 @@ std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, Pen catch (const exception &e) { setStatusError(string(tr("Failed to sign tx: ")) + e.what()); - return {}; + return ""; } ptx.m_key_images = signed_txs.key_images; @@ -3209,7 +3208,14 @@ std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, Pen //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::loadTx(const std::string &signed_filename, PendingTransaction &ptx) const { - return m_wallet->load_tx(signed_filename, ptx.m_pending_tx); + clearStatus(); + + if (!m_wallet->load_tx(signed_filename, ptx.m_pending_tx)) + { + setStatusError((boost::format(tr("Failed to load tx from file with filename `%s`. For more info see log file")) % signed_filename).str()); + return false; + } + return true; } //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const @@ -3267,7 +3273,17 @@ bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, Pend //------------------------------------------------------------------------------------------------------------------- std::uint64_t WalletImpl::getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const { - return m_wallet->get_fee_multiplier(priority, fee_algorithm); + clearStatus(); + + try + { + return m_wallet->get_fee_multiplier(priority, fee_algorithm); + } + catch + { + setStatusError((boost::format(tr("Failed to get fee multiplier for priority `%u` and fee algorithm `%d`: %s")) % priority % fee_algorithm % e.what()).str()); + } + return 0; } //------------------------------------------------------------------------------------------------------------------- std::uint64_t WalletImpl::getBaseFee() const @@ -3281,18 +3297,7 @@ std::uint64_t WalletImpl::getBaseFee() const //------------------------------------------------------------------------------------------------------------------- std::uint32_t WalletImpl::adjustPriority(std::uint32_t priority) { - clearStatus(); - - try - { - return m_wallet->adjust_priority(priority); - } - catch (const std::exception &e) - { - LOG_ERROR(__FUNCTION__ << " error: " << e.what()); - setStatusError(string(tr("Failed to adjust priority: ")) + e.what()); - } - return 0; + return m_wallet->adjust_priority(priority); } //------------------------------------------------------------------------------------------------------------------- void WalletImpl::coldTxAuxImport(const PendingTransaction &ptx, const std::vector &tx_device_aux) const @@ -3305,7 +3310,7 @@ void WalletImpl::coldTxAuxImport(const PendingTransaction &ptx, const std::vecto } catch (const std::exception &e) { - setStatusError(e.what()); + setStatusError(string(tr("Failed to import cold tx aux: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3326,7 +3331,7 @@ void WalletImpl::coldSignTx(const PendingTransaction &ptx_in, PendingTransaction } catch (const std::exception &e) { - setStatusError(e.what()); + setStatusError(string(tr("Failed to cold sign tx: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3340,7 +3345,7 @@ void WalletImpl::discardUnmixableEnotes() } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to discard unmixable enotes. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to discard unmixable enotes: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3351,14 +3356,14 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co crypto::hash txid_pod; if (!epee::string_tools::hex_to_pod(txid, txid_pod)) { - setStatusError((boost::format(tr("Failed to parse tx_id: %s")) % tx_id).str()); + setStatusError(string(tr("Failed to parse tx id: ")) + txid); return; } crypto::secret_key tx_key_pod; if (!epee::string_tools::hex_to_pod(tx_key, tx_key_pod)) { - setStatusError((boost::format(tr("Failed to parse tx_key: %s")) % tx_key).str()); + setStatusError(tr("Failed to parse tx key")); return; } @@ -3369,7 +3374,7 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co { if (!epee::string_tools::hex_to_pod(additional_tx_key, tmp_additional_tx_key_pod)) { - setStatusError((boost::format(tr("Failed to parse additional_tx_key: %s")) % additional_tx_key).str()); + setStatusError(string(tr("Failed to parse additional tx key: ")) + additionaL_tx_key); return; } additional_tx_keys_pod.push_back(tmp_additional_tx_key_pod); @@ -3381,7 +3386,7 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co { if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), single_destination_subaddress)) { - setStatusError((boost::format(tr("Failed to get account address from string: %s")) % single_destination_subaddress).str()); + setStatusError(string(tr("Failed to get account address from string: ")) + single_destination_subaddress); return; } single_destination_subaddress_pod = info.address; @@ -3393,7 +3398,7 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to set tx key. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to set tx key: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3412,7 +3417,7 @@ void WalletImpl::setAccountTag(const std::set &account_indices, const } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to set account tag. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to set account tag: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3426,7 +3431,7 @@ void WalletImpl::setAccountTagDescription(const std::string &tag, const std::str } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to set account tag description. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to set account tag description: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3440,7 +3445,7 @@ std::string WalletImpl::exportEnotesToStr(bool all, std::uint32_t start, std::ui } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to export outputs to string. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to export enotes to string: ")) + e.what()); } return ""; } @@ -3455,7 +3460,7 @@ std::size_t WalletImpl::importEnotesFromStr(const std::string &enotes_str) } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to import outputs from string. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to import enotes to string: ")) + e.what()); } return 0; } @@ -3470,7 +3475,7 @@ std::uint64_t WalletImpl::getBlockchainHeightByDate(std::uint16_t year, std::uin } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to get blockchain height by date. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to get blockchain height by date: ")) + e.what()); } return 0; } @@ -3485,7 +3490,7 @@ std::vector> WalletImpl::estimateBacklog } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to estimate backlog. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to estimate backlog: ")) + e.what()); } return { std::make_pair(0, 0) }; } @@ -3538,7 +3543,7 @@ std::uint64_t WalletImpl::hashTransfers(std::uint64_t transfer_height, std::stri } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to hash transfers. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to hash transfers: ")) + e.what()); } return 0; } @@ -3553,7 +3558,7 @@ void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t transfer_height, cons } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to finish rescan blockchain. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to finish rescan blockchain: ")) + e.what()); } } //------------------------------------------------------------------------------------------------------------------- @@ -3569,7 +3574,7 @@ std::vector> WalletImpl::g } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to get public nodes. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to get public nodes: ")) + e.what()); return std::vector>{}; } @@ -3589,7 +3594,7 @@ std::pair WalletImpl::estimateTxSizeAndWeight(bool u } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to estimate transaction size and weight. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to estimate transaction size and weight: ")) + e.what()); } return std::make_pair(0, 0); } @@ -3609,17 +3614,17 @@ std::uint64_t importKeyImages(const std::vector key_images, std::size_ { if (!epee::string_tools::hex_to_pod(key_image, tmp_key_image_pod)) { - setStatusError((boost::format(tr("Failed to parse key_image: %s")) % key_image).str()); + setStatusError(string(tr("Failed to parse key image: ")) + key_image); return false; } key_images_pod.push_back(tmp_key_image_pod); @@ -3660,7 +3665,7 @@ bool WalletImpl::importKeyImages(std::vector key_images, std::size_ } catch (const std::exception &e) { - setStatusError((boost::format(tr("Failed to import key images. Error: %s")) % e.what()).str()); + setStatusError(string(tr("Failed to import key images: ")) + e.what()); } return false; } diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index fa14d5f892..5b044accb1 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1336,6 +1336,7 @@ struct Wallet * brief: convertTxToStr - get the encrypted data from a vector of pending transactions as hex string * param: ptxs - * return: unsigned tx data as encrypted hex string if succeeded, else empty string + * note: sets status error on fail */ virtual std::string convertTxToStr(const PendingTransaction &ptxs) const = 0; /** @@ -1343,6 +1344,7 @@ struct Wallet * param: unsigned_tx_str - encrypted hex string * outparam: exported_txs - * return: true if succeeded + * note: sets status error on fail */ virtual bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const = 0; /** @@ -1400,6 +1402,7 @@ struct Wallet * param: priority - * param: fee_algorithm - * return: fee multiplier + * note: sets status error on fail */ virtual std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const = 0; /** @@ -1411,7 +1414,7 @@ struct Wallet * brief: adjustPriority - adjust priority depending on how "full" last N blocks are * param: priority - * return: adjusted priority - * note: sets status error on fail + * warning: doesn't tell if it failed */ virtual std::uint32_t adjustPriority(std::uint32_t priority) = 0; // QUESTION : Any suggestion for the function description below? From 9c6301774eea714d51b219b0879f13cdf4af2042 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 30 Sep 2024 22:23:17 +0200 Subject: [PATCH 17/25] some bugs fixed --- src/wallet/api/wallet.cpp | 103 +++++++++++++++++------------------ src/wallet/api/wallet.h | 2 +- src/wallet/api/wallet2_api.h | 4 +- 3 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 45a7892ba2..9e59402289 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -403,8 +403,8 @@ uint64_t Wallet::maximumAllowedAmount() bool Wallet::walletExists(const std::string &path, bool &key_file_exists, bool &wallet_file_exists) { - tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); - return (keys_file_exists || wallet_file_exists) + tools::wallet2::wallet_exists(path, key_file_exists, wallet_file_exists); + return (key_file_exists || wallet_file_exists); } void Wallet::init(const char *argv0, const char *default_log_base_name, const std::string &log_path, bool console) { @@ -790,7 +790,7 @@ bool WalletImpl::close(bool do_store) // Do not store wallet with invalid status // Status Critical refers to errors on opening or creating wallets. if (status() != Status_Critical) - store(); + store(""); else LOG_ERROR("Status_Critical - not saving wallet"); LOG_PRINT_L1("wallet::store done"); @@ -1154,7 +1154,7 @@ bool WalletImpl::submitTransaction(const string &fileName) { return false; std::unique_ptr transaction(new PendingTransactionImpl(*this)); - bool r = m_wallet->loadTx(fileName, transaction); + bool r = loadTx(fileName, transaction); if (!r) { setStatus(Status_Ok, tr("Failed to load transaction from file")); return false; @@ -1712,7 +1712,7 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector 0 ? mixin_count : defaultMixin(); - fake_outs_count = adjustMixin(mixin_count); + fake_outs_count = adjust_mixin(mixin_count); if (amount) { transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, @@ -1913,7 +1913,7 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vectorget_base_fee(priority), m_wallet->get_fee_quantization_mask()); } @@ -2886,7 +2886,7 @@ std::pair WalletImpl::getSubaddressIndex(const std if (!index) setStatusError(string(tr("Address doesn't belong to the wallet: ") + address)); else - indices = std::make_pair(index.major, index.minor); + indices = std::make_pair((*index).major, (*index).minor); return indices; } @@ -3041,17 +3041,9 @@ void WalletImpl::updatePoolState(std::vector(tx), tx_id)) - { - setStatusError(string(tr("Failed to parse tx_id: ")) + std::get<1>(tx)); - return; - } - process_txs.push_back(std::make_tuple(std::get<0>(tx), tx_id, std::get<2>(tx))); - } + process_txs.push_back(std::make_tuple(std::get<0>(tx), epee::string_tools::pod_to_hex(std::get<1>(tx)), std::get<2>(tx))); } //------------------------------------------------------------------------------------------------------------------- void WalletImpl::processPoolState(const std::vector> &txs) @@ -3081,9 +3073,9 @@ void WalletImpl::processPoolState(const std::vector enote_details) const +void WalletImpl::getEnoteDetails(std::vector &enote_details) const { - wallet2::transfer_container tc; + tools::wallet2::transfer_container tc; m_wallet->get_transfers(tc); enote_details.reserve(tc.size()); @@ -3092,7 +3084,6 @@ void WalletImpl::getEnoteDetails(std::vector enote_details) const EnoteDetails ed{}; cryptonote::txout_target_v txout_v = td.m_tx.vout[tx.m_internal_output_index]; - crypto::public_key pub_key_pod; if (txout_v.type() == typeid(cryptonote::txout_to_key)) ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); else if (txout_v.type() == typeid(cryptonote::txout_to_tagged_key)) @@ -3101,9 +3092,10 @@ void WalletImpl::getEnoteDetails(std::vector enote_details) const ed.m_view_tag = epee::string_tools::pod_to_hex(boost::get(txout_v).view_tag); } - ed.m_tx_id = td.m_txid; - ed.m_internal_output_index = td.m_internal_output_index; - ed.m_global_output_index = td.m_global_output_index; + ed.m_block_height = td.m_block_height; + ed.m_tx_id = epee::string_tools::pod_to_hex(td.m_txid); + ed.m_internal_enote_index = td.m_internal_output_index; + ed.m_global_enote_index = td.m_global_output_index; ed.m_spent = td.m_spent; ed.m_frozen = td.m_frozen; ed.m_spent_height = td.m_spent_height; @@ -3129,8 +3121,8 @@ std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisi checkMultisigWalletReady(m_wallet); tools::wallet2::multisig_tx_set multisig_tx_set; - multisig_tx_set.m_ptx = multisig_ptxs.m_pending_tx; - multisig_tx_set.m_signers = multisig_ptxs.m_signers; + multisig_tx_set.m_ptx = multisig_ptx.m_pending_tx; + multisig_tx_set.m_signers = multisig_ptx.m_signers; return m_wallet->save_multisig_tx(multisig_tx_set); } @@ -3142,7 +3134,7 @@ std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisi return ""; } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptxs, const std::string &filename) const +bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const { clearStatus(); @@ -3151,8 +3143,8 @@ bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptxs, const s checkMultisigWalletReady(m_wallet); tools::wallet2::multisig_tx_set multisig_tx_set; - multisig_tx_set.m_ptx = multisig_ptxs.m_pending_tx; - multisig_tx_set.m_signers = multisig_ptxs.m_signers; + multisig_tx_set.m_ptx = multisig_ptx.m_pending_tx; + multisig_tx_set.m_signers = multisig_ptx.m_signers; return m_wallet->save_multisig_tx(multisig_tx_set, filename); } @@ -3190,10 +3182,10 @@ std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, Pen clearStatus(); std::string signed_tx_data; + tools::wallet2::signed_tx_set signed_txes; try { - tools::wallet2::signed_tx_set signed_txes; signed_tx_data = m_wallet->sign_tx_dump_to_str(exported_txs.m_unsigned_tx_set, ptx.m_pending_tx, signed_txes); } catch (const exception &e) @@ -3279,7 +3271,7 @@ std::uint64_t WalletImpl::getFeeMultiplier(std::uint32_t priority, int fee_algor { return m_wallet->get_fee_multiplier(priority, fee_algorithm); } - catch + catch (const exception &e) { setStatusError((boost::format(tr("Failed to get fee multiplier for priority `%u` and fee algorithm `%d`: %s")) % priority % fee_algorithm % e.what()).str()); } @@ -3288,11 +3280,7 @@ std::uint64_t WalletImpl::getFeeMultiplier(std::uint32_t priority, int fee_algor //------------------------------------------------------------------------------------------------------------------- std::uint64_t WalletImpl::getBaseFee() const { - bool use_dyn_fee = useForkRules(HF_VERSION_DYNAMIC_FEE, -30 * 1); - if (!use_dyn_fee) - return FEE_PER_KB; - - return m_wallet->get_dynamic_base_fee_estimate(); + return m_wallet->get_base_fee(); } //------------------------------------------------------------------------------------------------------------------- std::uint32_t WalletImpl::adjustPriority(std::uint32_t priority) @@ -3306,7 +3294,7 @@ void WalletImpl::coldTxAuxImport(const PendingTransaction &ptx, const std::vecto try { - m_wallet->cold_tx_aux_import(ptx->m_pending_tx, tx_device_aux); + m_wallet->cold_tx_aux_import(ptx.m_pending_tx, tx_device_aux); } catch (const std::exception &e) { @@ -3322,9 +3310,9 @@ void WalletImpl::coldSignTx(const PendingTransaction &ptx_in, PendingTransaction { tools::wallet2::signed_tx_set signed_txs; - m_wallet->cold_sign_tx(ptx_in->m_pending_tx, signed_txs, dsts_info, exported_txs_out->m_tx_device_aux); - exported_txs_out->m_key_images = signed_txs.key_images; - exported_txs_out->m_pending_tx = signed_txs.ptx; + m_wallet->cold_sign_tx(ptx_in.m_pending_tx, signed_txs, dsts_info, exported_txs_out.m_tx_device_aux); + exported_txs_out.m_key_images = signed_txs.key_images; + exported_txs_out.m_pending_tx = signed_txs.ptx; // TODO : figure out if we need signed_txs.tx_key_images here, afaik they're used for selfsend/change enotes // if needed we can probably add a member like `m_selfsend_key_images` to `PendingTransaction` // guess then `PendingTransaction` would be a proper replacement for `wallet2::signed_tx_set` @@ -3374,7 +3362,7 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co { if (!epee::string_tools::hex_to_pod(additional_tx_key, tmp_additional_tx_key_pod)) { - setStatusError(string(tr("Failed to parse additional tx key: ")) + additionaL_tx_key); + setStatusError(string(tr("Failed to parse additional tx key: ")) + additional_tx_key); return; } additional_tx_keys_pod.push_back(tmp_additional_tx_key_pod); @@ -3522,12 +3510,12 @@ std::vector> WalletImpl::estimateBacklog return estimateBacklog(fee_levels); } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const +bool WalletImpl::saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable /* = false */) const { return m_wallet->save_to_file(path_to_file, binary, is_printable); } //------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const +bool WalletImpl::loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size /* = 1000000000 */) const { return m_wallet->load_from_file(path_to_file, target_str, max_size); } @@ -3538,8 +3526,11 @@ std::uint64_t WalletImpl::hashTransfers(std::uint64_t transfer_height, std::stri try { - boost::optional _transfer_height = transfer_height == 0 ? boost::none : transfer_height; - return m_wallet->hash_m_transfers(_transfer_height, hash); + crypto::hash m_transfers_hash; + boost::optional _transfer_height = transfer_height == 0 ? boost::none : boost::optional(transfer_height); + std::uint64_t current_height = m_wallet->hash_m_transfers(_transfer_height, m_transfers_hash); + hash = epee::string_tools::pod_to_hex(m_transfers_hash); + return current_height; } catch (const std::exception &e) { @@ -3554,7 +3545,11 @@ void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t transfer_height, cons try { - m_wallet->finish_rescan_bc_keep_key_images(transfer_height, hash); + crypto::hash hash_pod; + if (!epee::string_tools::hex_to_pod(hash, hash_pod)) + setStatusError(tr("Failed to parse hash")); + else + m_wallet->finish_rescan_bc_keep_key_images(transfer_height, hash_pod); } catch (const std::exception &e) { @@ -3562,12 +3557,12 @@ void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t transfer_height, cons } } //------------------------------------------------------------------------------------------------------------------- -std::vector> WalletImpl::getPublicNodes(bool white_only = true) const +std::vector> WalletImpl::getPublicNodes(bool white_only /* = true */) const { clearStatus(); std::vector public_nodes; - std::vector> public_nodes_out; + std::vector> public_nodes_out; try { public_nodes m_wallet->get_public_nodes(white_only); @@ -3575,11 +3570,11 @@ std::vector> WalletImpl::g catch (const std::exception &e) { setStatusError(string(tr("Failed to get public nodes: ")) + e.what()); - return std::vector>{}; + return std::vector>{}; } for (auto pub_node : public_nodes) - public_nodes_out.push_back(std::tuple{pub_note.host, pub_note.rpc_port, pub_note.last_seen}); + public_nodes_out.push_back(std::tuple{pub_node.host, pub_node.rpc_port, pub_node.last_seen}); return public_nodes_out; } @@ -3599,7 +3594,7 @@ std::pair WalletImpl::estimateTxSizeAndWeight(bool u return std::make_pair(0, 0); } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t importKeyImages(const std::vector> &signed_key_images, std::size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent) +std::uint64_t WalletImpl::importKeyImages(const std::vector> &signed_key_images, std::size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent) { clearStatus(); @@ -3617,17 +3612,17 @@ std::uint64_t importKeyImages(const std::vector key_images, std::size_ try { - boost::optional> _selected_transfers = selected_transfers.empty() ? boost::none : selected_transfers; + boost::optional> _selected_transfers = selected_transfers.empty() ? boost::none : boost::optional>(selected_transfers); return m_wallet->import_key_images(key_images_pod, offset, _selected_transfers); } catch (const std::exception &e) @@ -3674,7 +3669,7 @@ bool WalletImpl::importKeyImages(std::vector key_images, std::size_ //------------------------------------------------------------------------------------------------------------------- // PRIVATE //------------------------------------------------------------------------------------------------------------------- -std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) +std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) const { crypto::key_image ki; if (!epee::string_tools::hex_to_pod(key_image, ki)) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c0c38828b5..0314528347 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -248,7 +248,7 @@ class WalletImpl : public Wallet void writeWatchOnlyWallet(const std::string &password, std::string &new_keys_file_name) override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; void processPoolState(const std::vector> &txs) override; - void getEnoteDetails(std::vector enote_details) const override; + void getEnoteDetails(std::vector &enote_details) const override; std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 5b044accb1..2f853de886 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -82,6 +82,8 @@ struct EnoteDetails std::string m_view_tag; // this enote was received at block height std::uint64_t m_block_height; + // tx id in which tx enote was received + std::string m_tx_id; // relative index in tx std::uint64_t m_internal_enote_index; // absolute index from `cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry.output_indices` @@ -1316,7 +1318,7 @@ struct Wallet * brief: getEnoteDetails - get information about all enotes * outparam: enote_details - */ - virtual void getEnoteDetails(std::vector enote_details) const = 0; + virtual void getEnoteDetails(std::vector &enote_details) const = 0; /** * brief: convertMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction * param: multisig_ptx - multisig pending transaction From 2e842ea8da6904acdbf4a4ba1087ca582cce4c1f Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Tue, 1 Oct 2024 19:57:38 +0200 Subject: [PATCH 18/25] fix bugs --- src/wallet/api/transaction_history.cpp | 6 +- src/wallet/api/wallet.cpp | 93 +++++++++++++++++--------- src/wallet/api/wallet.h | 2 +- src/wallet/api/wallet2_api.h | 6 +- 4 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index d6818ff545..501d5302e0 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -199,7 +199,7 @@ void TransactionHistoryImpl::refresh() ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0; ti->m_unlock_time = pd.m_unlock_time; - ti->m_change = pd->m_change; + ti->m_change = pd.m_change; ti->m_tx_state = TransactionInfo::confirmed; // not used for confirmed_transfer_details ti->m_double_spend_seen = false; @@ -240,8 +240,8 @@ void TransactionHistoryImpl::refresh() ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; ti->m_unlock_time = pd.m_tx.unlock_time; - ti->m_change = pd->m_change; - ti->m_tx_state = pd->m_state; + ti->m_change = pd.m_change; + ti->m_tx_state = pd.m_state; // not used for unconfirmed_transfer_details ti->m_double_spend_seen = false; for (const auto &d : pd.m_dests) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 9e59402289..60854dedce 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1154,7 +1154,8 @@ bool WalletImpl::submitTransaction(const string &fileName) { return false; std::unique_ptr transaction(new PendingTransactionImpl(*this)); - bool r = loadTx(fileName, transaction); + PendingTransaction *ptx_interface = dynamic_cast(transaction.get()); + bool r = loadTx(fileName, *ptx_interface); if (!r) { setStatus(Status_Ok, tr("Failed to load transaction from file")); return false; @@ -1712,7 +1713,7 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector 0 ? mixin_count : defaultMixin(); - fake_outs_count = adjust_mixin(mixin_count); + fake_outs_count = m_wallet->adjust_mixin(mixin_count); if (amount) { transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, @@ -2984,7 +2985,7 @@ void WalletImpl::createOneOffSubaddress(std::uint32_t account_index, std::uint32 m_wallet->create_one_off_subaddress({account_index, address_index}); } //------------------------------------------------------------------------------------------------------------------- -WalletState WalletImpl::getWalletState() const +Wallet::WalletState WalletImpl::getWalletState() const { WalletState wallet_state{}; @@ -3083,7 +3084,7 @@ void WalletImpl::getEnoteDetails(std::vector &enote_details) const { EnoteDetails ed{}; - cryptonote::txout_target_v txout_v = td.m_tx.vout[tx.m_internal_output_index]; + cryptonote::txout_target_v txout_v = td.m_tx.vout[td.m_internal_output_index].target; if (txout_v.type() == typeid(cryptonote::txout_to_key)) ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); else if (txout_v.type() == typeid(cryptonote::txout_to_tagged_key)) @@ -3099,14 +3100,17 @@ void WalletImpl::getEnoteDetails(std::vector &enote_details) const ed.m_spent = td.m_spent; ed.m_frozen = td.m_frozen; ed.m_spent_height = td.m_spent_height; - ed.m_key_image = td.m_key_image; - ed.m_mask = td.m_mask; - ed.m_amount = td.m_mask; + ed.m_key_image = epee::string_tools::pod_to_hex(td.m_key_image); + ed.m_mask = epee::string_tools::pod_to_hex(td.m_mask); + ed.m_amount = td.m_amount; ed.m_protocol_version = td.m_rct ? EnoteDetails::rct : EnoteDetails::cn; ed.m_key_image_known = td.m_key_image_known; ed.m_key_image_request = td.m_key_image_request; ed.m_pk_index = td.m_pk_index; - ed.m_uses = td.m_uses; + ed.m_uses.reserve(td.m_uses.size()); + for (auto &u : td.m_uses) + ed.m_uses.push_back(std::make_pair(u.first, epee::string_tools::pod_to_hex(u.second))); + ed.m_key_image_partial = td.m_key_image_partial; enote_details.push_back(ed); } @@ -3120,9 +3124,11 @@ std::string WalletImpl::convertMultisigTxToStr(const PendingTransaction &multisi { checkMultisigWalletReady(m_wallet); + const PendingTransactionImpl *ptx_impl = dynamic_cast(&multisig_ptx); + tools::wallet2::multisig_tx_set multisig_tx_set; - multisig_tx_set.m_ptx = multisig_ptx.m_pending_tx; - multisig_tx_set.m_signers = multisig_ptx.m_signers; + multisig_tx_set.m_ptx = ptx_impl->m_pending_tx; + multisig_tx_set.m_signers = ptx_impl->m_signers; return m_wallet->save_multisig_tx(multisig_tx_set); } @@ -3142,9 +3148,11 @@ bool WalletImpl::saveMultisigTx(const PendingTransaction &multisig_ptx, const st { checkMultisigWalletReady(m_wallet); + const PendingTransactionImpl *ptx_impl = dynamic_cast(&multisig_ptx); + tools::wallet2::multisig_tx_set multisig_tx_set; - multisig_tx_set.m_ptx = multisig_ptx.m_pending_tx; - multisig_tx_set.m_signers = multisig_ptx.m_signers; + multisig_tx_set.m_ptx = ptx_impl->m_pending_tx; + multisig_tx_set.m_signers = ptx_impl->m_signers; return m_wallet->save_multisig_tx(multisig_tx_set, filename); } @@ -3160,7 +3168,8 @@ std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs) const { clearStatus(); - std::string tx_dump = m_wallet->dump_tx_to_str(ptxs.m_pending_tx); + const PendingTransactionImpl *ptx_impl = dynamic_cast(&ptxs); + std::string tx_dump = m_wallet->dump_tx_to_str(ptx_impl->m_pending_tx); if (tx_dump.empty()) setStatusError(tr("Failed to convert pending tx to string")); @@ -3169,7 +3178,8 @@ std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs) const //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const { - if (!m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, exported_txs.m_unsigned_tx_set)) + UnsignedTransactionImpl *utx_impl = dynamic_cast(&exported_txs); + if (!m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, utx_impl->m_unsigned_tx_set)) { setStatusError(tr("Failed to parse unsigned tx from string. For more info see log file")); return false; @@ -3177,16 +3187,19 @@ bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, Unsi return true; } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const +std::string WalletImpl::signTxToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx) const { clearStatus(); + tools::wallet2::unsigned_tx_set &utx_set = dynamic_cast(&exported_txs)->m_unsigned_tx_set; + PendingTransactionImpl *ptx_impl = dynamic_cast(&ptx); + std::string signed_tx_data; - tools::wallet2::signed_tx_set signed_txes; + tools::wallet2::signed_tx_set signed_txs; try { - signed_tx_data = m_wallet->sign_tx_dump_to_str(exported_txs.m_unsigned_tx_set, ptx.m_pending_tx, signed_txes); + signed_tx_data = m_wallet->sign_tx_dump_to_str(utx_set, ptx_impl->m_pending_tx, signed_txs); } catch (const exception &e) { @@ -3194,7 +3207,7 @@ std::string WalletImpl::signTxToStr(const UnsignedTransaction &exported_txs, Pen return ""; } - ptx.m_key_images = signed_txs.key_images; + ptx_impl->m_key_images = signed_txs.key_images; return signed_tx_data; } //------------------------------------------------------------------------------------------------------------------- @@ -3202,7 +3215,9 @@ bool WalletImpl::loadTx(const std::string &signed_filename, PendingTransaction & { clearStatus(); - if (!m_wallet->load_tx(signed_filename, ptx.m_pending_tx)) + PendingTransactionImpl *ptx_impl = dynamic_cast(&ptx); + + if (!m_wallet->load_tx(signed_filename, ptx_impl->m_pending_tx)) { setStatusError((boost::format(tr("Failed to load tx from file with filename `%s`. For more info see log file")) % signed_filename).str()); return false; @@ -3218,13 +3233,14 @@ bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, Pend { checkMultisigWalletReady(m_wallet); + PendingTransactionImpl *ptx_impl = dynamic_cast(&exported_txs); tools::wallet2::multisig_tx_set multisig_tx; if (!m_wallet->parse_multisig_tx_from_str(multisig_tx_str, multisig_tx)) throw runtime_error(tr("Failed to parse multisig transaction from string.")); - exported_txs.m_pending_tx = multisig_tx.m_ptx; - exported_txs.m_signers = multisig_tx.m_signers; + ptx_impl->m_pending_tx = multisig_tx.m_ptx; + ptx_impl->m_signers = multisig_tx.m_signers; return true; } @@ -3292,9 +3308,11 @@ void WalletImpl::coldTxAuxImport(const PendingTransaction &ptx, const std::vecto { clearStatus(); + const PendingTransactionImpl *ptx_impl = dynamic_cast(&ptx); + try { - m_wallet->cold_tx_aux_import(ptx.m_pending_tx, tx_device_aux); + m_wallet->cold_tx_aux_import(ptx_impl->m_pending_tx, tx_device_aux); } catch (const std::exception &e) { @@ -3308,11 +3326,13 @@ void WalletImpl::coldSignTx(const PendingTransaction &ptx_in, PendingTransaction try { + const PendingTransactionImpl *ptx_impl_in = dynamic_cast(&ptx_in); + PendingTransactionImpl *ptx_impl_out = dynamic_cast(&exported_txs_out); tools::wallet2::signed_tx_set signed_txs; - m_wallet->cold_sign_tx(ptx_in.m_pending_tx, signed_txs, dsts_info, exported_txs_out.m_tx_device_aux); - exported_txs_out.m_key_images = signed_txs.key_images; - exported_txs_out.m_pending_tx = signed_txs.ptx; + m_wallet->cold_sign_tx(ptx_impl_in->m_pending_tx, signed_txs, dsts_info, ptx_impl_out->m_tx_device_aux); + ptx_impl_out->m_key_images = signed_txs.key_images; + ptx_impl_out->m_pending_tx = signed_txs.ptx; // TODO : figure out if we need signed_txs.tx_key_images here, afaik they're used for selfsend/change enotes // if needed we can probably add a member like `m_selfsend_key_images` to `PendingTransaction` // guess then `PendingTransaction` would be a proper replacement for `wallet2::signed_tx_set` @@ -3357,7 +3377,7 @@ void WalletImpl::setTxKey(const std::string &txid, const std::string &tx_key, co std::vector additional_tx_keys_pod; crypto::secret_key tmp_additional_tx_key_pod; - additional_tx_key_pod.reserve(additional_tx_keys.size()); + additional_tx_keys_pod.reserve(additional_tx_keys.size()); for (std::string additional_tx_key : additional_tx_keys) { if (!epee::string_tools::hex_to_pod(additional_tx_key, tmp_additional_tx_key_pod)) @@ -3565,7 +3585,7 @@ std::vector> WalletImpl::g std::vector> public_nodes_out; try { - public_nodes m_wallet->get_public_nodes(white_only); + public_nodes = m_wallet->get_public_nodes(white_only); } catch (const std::exception &e) { @@ -3671,11 +3691,22 @@ bool WalletImpl::importKeyImages(std::vector key_images, std::size_ //------------------------------------------------------------------------------------------------------------------- std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) const { - crypto::key_image ki; - if (!epee::string_tools::hex_to_pod(key_image, ki)) - throw runtime_error(tr("Failed to parse key image.")); + std::vector enote_details; + getEnoteDetails(enote_details); + for (size_t idx = 0; idx < enote_details.size(); ++idx) + { + const EnoteDetails &ed = enote_details[idx]; + if (ed.m_key_image == key_image) + { + if (ed.m_key_image_known) + return idx; + else if (ed.m_key_image_partial) + setStatusError("Failed to get enote index by key image: Transfer detail lookups are not allowed for multisig partial key images"); + } + } - return m_wallet->get_transfer_details(ki); + setStatusError("Failed to get enote index by key image: Key image not found"); + return 0; } //------------------------------------------------------------------------------------------------------------------- diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 0314528347..c345e0b219 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -253,7 +253,7 @@ class WalletImpl : public Wallet bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; - std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const override; + std::string signTxToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx) const override; bool loadTx(const std::string &signed_filename, PendingTransaction &ptx) const override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 2f853de886..a7ddfd1ea9 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -112,8 +112,8 @@ struct EnoteDetails std::vector> m_uses; // QUESTION : Any input on these multisig members? I'd ignore them for now. // Multisig - /* bool m_key_image_partial; + /* std::vector m_multisig_k; std::vector m_multisig_info; // one per other participant */ @@ -519,7 +519,7 @@ struct Wallet struct WalletState { // is wallet file format deprecated bool is_deprecated; - std::uint64_t ring_rize; + std::uint64_t ring_size; std::string daemon_address; }; @@ -1356,7 +1356,7 @@ struct Wallet * return: signed tx data as encrypted hex string * note: sets status error on fail */ - virtual std::string signTxToStr(const UnsignedTransaction &exported_txs, PendingTransaction &ptx) const = 0; + virtual std::string signTxToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx) const = 0; // TODO : if it's fine to drop the accept_func, do it for all the functions below (where possible, meaning accept_func is optional in wallet2 params) /** * brief: loadTx - load pending transactions from a file From 9cb69d871676f3f4d1606d8138937aac0ef45f86 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Wed, 2 Oct 2024 19:20:58 +0200 Subject: [PATCH 19/25] replace term transfer --- src/wallet/api/wallet.cpp | 24 ++++++++++++------------ src/wallet/api/wallet.h | 6 +++--- src/wallet/api/wallet2_api.h | 29 +++++++++++++++-------------- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 60854dedce..f599125987 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3540,26 +3540,26 @@ bool WalletImpl::loadFromFile(const std::string &path_to_file, std::string &targ return m_wallet->load_from_file(path_to_file, target_str, max_size); } //------------------------------------------------------------------------------------------------------------------- -std::uint64_t WalletImpl::hashTransfers(std::uint64_t transfer_height, std::string &hash) const +std::uint64_t WalletImpl::hashEnotes(std::uint64_t enote_idx, std::string &hash) const { clearStatus(); try { - crypto::hash m_transfers_hash; - boost::optional _transfer_height = transfer_height == 0 ? boost::none : boost::optional(transfer_height); - std::uint64_t current_height = m_wallet->hash_m_transfers(_transfer_height, m_transfers_hash); - hash = epee::string_tools::pod_to_hex(m_transfers_hash); + crypto::hash hash_pod; + boost::optional idx = enote_idx == 0 ? boost::none : boost::optional(enote_idx); + std::uint64_t current_height = m_wallet->hash_m_transfers(idx, hash_pod); + hash = epee::string_tools::pod_to_hex(hash_pod); return current_height; } catch (const std::exception &e) { - setStatusError(string(tr("Failed to hash transfers: ")) + e.what()); + setStatusError(string(tr("Failed to hash enotes: ")) + e.what()); } return 0; } //------------------------------------------------------------------------------------------------------------------- -void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) +void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t enote_idx, const std::string &hash) { clearStatus(); @@ -3569,7 +3569,7 @@ void WalletImpl::finishRescanBcKeepKeyImages(std::uint64_t transfer_height, cons if (!epee::string_tools::hex_to_pod(hash, hash_pod)) setStatusError(tr("Failed to parse hash")); else - m_wallet->finish_rescan_bc_keep_key_images(transfer_height, hash_pod); + m_wallet->finish_rescan_bc_keep_key_images(enote_idx, hash_pod); } catch (const std::exception &e) { @@ -3656,7 +3656,7 @@ std::uint64_t WalletImpl::importKeyImages(const std::vector key_images, std::size_t offset, std::unordered_set selected_transfers) +bool WalletImpl::importKeyImages(std::vector key_images, std::size_t offset, std::unordered_set selected_enotes_indices) { clearStatus(); @@ -3675,8 +3675,8 @@ bool WalletImpl::importKeyImages(std::vector key_images, std::size_ try { - boost::optional> _selected_transfers = selected_transfers.empty() ? boost::none : boost::optional>(selected_transfers); - return m_wallet->import_key_images(key_images_pod, offset, _selected_transfers); + boost::optional> _selected_enote_indices = selected_enotes_indices.empty() ? boost::none : boost::optional>(selected_enotes_indices); + return m_wallet->import_key_images(key_images_pod, offset, _selected_enote_indices); } catch (const std::exception &e) { @@ -3701,7 +3701,7 @@ std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) const if (ed.m_key_image_known) return idx; else if (ed.m_key_image_partial) - setStatusError("Failed to get enote index by key image: Transfer detail lookups are not allowed for multisig partial key images"); + setStatusError("Failed to get enote index by key image: Enote detail lookups are not allowed for multisig partial key images"); } } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c345e0b219..7bc6b16efd 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -273,12 +273,12 @@ class WalletImpl : public Wallet std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const override; bool saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const override; bool loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const override; - std::uint64_t hashTransfers(std::uint64_t transfer_height, std::string &hash) const override; - void finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) override; + std::uint64_t hashEnotes(std::uint64_t enote_idx, std::string &hash) const override; + void finishRescanBcKeepKeyImages(std::uint64_t enote_idx, const std::string &hash) override; std::vector> getPublicNodes(bool white_only = true) const override; std::pair estimateTxSizeAndWeight(bool use_rct, int n_inputs, int ring_size, int n_outputs, std::size_t extra_size) const override; std::uint64_t importKeyImages(const std::vector> &signed_key_images, std::size_t offset, std::uint64_t &spent, std::uint64_t &unspent, bool check_spent = true) override; - bool importKeyImages(std::vector key_images, std::size_t offset = 0, std::unordered_set selected_transfers = {}) override; + bool importKeyImages(std::vector key_images, std::size_t offset = 0, std::unordered_set selected_enotes_indices = {}) override; private: void clearStatus() const; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index a7ddfd1ea9..5aad155dcf 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1243,7 +1243,7 @@ struct Wallet virtual std::pair getSubaddressIndex(const std::string &address) const = 0; /** * brief: freeze - freeze enote "so they don't appear in balance, nor are considered when creating a transaction, etc." (https://github.com/monero-project/monero/pull/5333) - * param: idx - index of enote in `m_transfers` + * param: idx - index of enote in local enote storage * param: key_image - key image of enote * note: sets status error on fail */ @@ -1251,7 +1251,7 @@ struct Wallet virtual void freeze(const std::string &key_image) = 0; /** * brief: thaw - thaw enote that is frozen, so it appears in balance and can be spent in a transaction - * param: idx - index of enote in `m_transfers` + * param: idx - index of enote in local enote storage * param: key_image - key image of enote * note: sets status error on fail */ @@ -1259,7 +1259,7 @@ struct Wallet virtual void thaw(const std::string &key_image) = 0; /** * brief: isFrozen - check if enote is frozen - * param: idx - index of enote in `m_transfers` + * param: idx - index of enote in local enote storage * param: key_image - key image of enote * return : true if enote is frozen, else false * note: sets status error on fail @@ -1528,20 +1528,21 @@ struct Wallet */ virtual bool loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const = 0; /** - * brief: hashTransfers - - * param: transfer_height - - * outparam: hash - hash of all transfers from wallet transfer storage up until `transfer_height` - * return: amount of hashed transfers + * brief: hashEnotes - get hash of all enotes in local enote store up until `enote_idx` + * (formerly in wallet2: `uint64_t wallet2::hash_m_transfers(boost::optional transfer_height, crypto::hash &hash)`) + * param: enote_idx - include all enotes below this index + * outparam: hash - hash as hex string + * return: number of hashed enotes * note: sets status error on fail */ - virtual std::uint64_t hashTransfers(std::uint64_t transfer_height, std::string &hash) const = 0; + virtual std::uint64_t hashEnotes(std::uint64_t enote_idx, std::string &hash) const = 0; /** * brief: finishRescanBcKeepKeyImages - - * param: transfer_height - + * param: enote_idx - * param: hash - * note: sets status error on fail */ - virtual void finishRescanBcKeepKeyImages(std::uint64_t transfer_height, const std::string &hash) = 0; + virtual void finishRescanBcKeepKeyImages(std::uint64_t enote_idx, const std::string &hash) = 0; /** * brief: getPublicNodes - get a list of public notes with information when they were last seen * param: white_only - include gray nodes if false (default: true) @@ -1563,7 +1564,7 @@ struct Wallet /** * brief: importKeyImages - * param: signed_key_images - [ [key_image, signature c || signature r], ... ] - * param: offset - offset in local transfer storage + * param: offset - offset in local enote storage * outparam: spent - total spent amount of the wallet * outparam: unspent - total unspent amount of the wallet * param: check_spent - @@ -1574,12 +1575,12 @@ struct Wallet /** * brief: importKeyImages - * param: key_images - - * param: offset - offset in local transfer storage - * param: selected_transfers - + * param: offset - offset in local enote storage + * param: selected_enotes_indices - * return: true if succeeded * note: sets status error on fail */ - virtual bool importKeyImages(std::vector key_images, std::size_t offset = 0, std::unordered_set selected_transfers = {}) = 0; + virtual bool importKeyImages(std::vector key_images, std::size_t offset = 0, std::unordered_set selected_enotes_indices = {}) = 0; }; /** From 8c553f60d778c1a36f0ec1da3da4157d12dc49da Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 7 Oct 2024 20:13:47 +0200 Subject: [PATCH 20/25] add enote_details .h/.cpp --- src/wallet/api/CMakeLists.txt | 2 + src/wallet/api/enote_details.cpp | 96 +++++++++++++++++++++++++++ src/wallet/api/enote_details.h | 109 +++++++++++++++++++++++++++++++ src/wallet/api/wallet.cpp | 57 ++++++++-------- src/wallet/api/wallet.h | 3 +- src/wallet/api/wallet2_api.h | 68 ++++++++----------- 6 files changed, 264 insertions(+), 71 deletions(-) create mode 100644 src/wallet/api/enote_details.cpp create mode 100644 src/wallet/api/enote_details.h diff --git a/src/wallet/api/CMakeLists.txt b/src/wallet/api/CMakeLists.txt index 3428de27a3..74b0d5306a 100644 --- a/src/wallet/api/CMakeLists.txt +++ b/src/wallet/api/CMakeLists.txt @@ -33,6 +33,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(wallet_api_sources wallet.cpp wallet_manager.cpp + enote_details.cpp transaction_info.cpp transaction_history.cpp pending_transaction.cpp @@ -48,6 +49,7 @@ set(wallet_api_headers set(wallet_api_private_headers wallet.h wallet_manager.h + enote_details.h transaction_info.h transaction_history.h pending_transaction.h diff --git a/src/wallet/api/enote_details.cpp b/src/wallet/api/enote_details.cpp new file mode 100644 index 0000000000..5b42a4e88e --- /dev/null +++ b/src/wallet/api/enote_details.cpp @@ -0,0 +1,96 @@ +// Copyright (c) 2014-2024, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "enote_details.h" + + +namespace Monero { + +EnoteDetails::~EnoteDetails() {} + + +EnoteDetailsImpl::EnoteDetailsImpl(): + m_block_height(0), + m_internal_enote_index(0), + m_global_enote_index(0), + m_spent(false), + m_frozen(false), + m_spent_height(0), + m_amount(0), + m_protocol_version(Tx_Protocol_CryptoNote), + m_key_image_known(false), + m_key_image_request(false), + m_pk_index(0), + m_key_image_partial(false) +{ +} + +EnoteDetailsImpl::~EnoteDetailsImpl() {} + +std::string EnoteDetailsImpl::onetimeAddress() const +{ return m_onetime_address; } +std::string EnoteDetailsImpl::viewTag() const +{ return m_view_tag; } +std::uint64_t EnoteDetailsImpl::blockHeight() const +{ return m_block_height; } +std::string EnoteDetailsImpl::txId() const +{ return m_tx_id; } +std::uint64_t EnoteDetailsImpl::internalEnoteIndex() const +{ return m_internal_enote_index; } +std::uint64_t EnoteDetailsImpl::globalEnoteIndex() const +{ return m_global_enote_index; } +bool EnoteDetailsImpl::isSpent() const +{ return m_spent; } +bool EnoteDetailsImpl::isFrozen() const +{ return m_frozen; } +std::uint64_t EnoteDetailsImpl::spentHeight() const +{ return m_spent_height; } +std::string EnoteDetailsImpl::keyImage() const +{ return m_key_image; } +std::string EnoteDetailsImpl::mask() const +{ return m_mask; } +std::uint64_t EnoteDetailsImpl::amount() const +{ return m_amount; } +EnoteDetails::TxProtocol EnoteDetailsImpl::protocolVersion() const +{ return m_protocol_version; } +bool EnoteDetailsImpl::isKeyImageKnown() const +{ return m_key_image_known; } +bool EnoteDetailsImpl::isKeyImageRequest() const +{ return m_key_image_request; } +uint64_t EnoteDetailsImpl::pkIndex() const +{ return m_pk_index; } +std::vector> EnoteDetailsImpl::uses() const +{ return m_uses; } + +// Multisig +bool EnoteDetailsImpl::isKeyImagePartial() const +{ return m_key_image_partial; } + +} // namespace diff --git a/src/wallet/api/enote_details.h b/src/wallet/api/enote_details.h new file mode 100644 index 0000000000..4f4b8b0d40 --- /dev/null +++ b/src/wallet/api/enote_details.h @@ -0,0 +1,109 @@ +// Copyright (c) 2014-2024, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "wallet/api/wallet2_api.h" + + +namespace Monero { + +class EnoteDetailsImpl : public EnoteDetails +{ +public: + EnoteDetailsImpl(); + ~EnoteDetailsImpl() override; + std::string onetimeAddress() const override; + std::string viewTag() const override; + std::uint64_t blockHeight() const override; + std::string txId() const override; + std::uint64_t internalEnoteIndex() const override; + std::uint64_t globalEnoteIndex() const override; + bool isSpent() const override; + bool isFrozen() const override; + std::uint64_t spentHeight() const override; + std::string keyImage() const override; + std::string mask() const override; + std::uint64_t amount() const override; + TxProtocol protocolVersion() const override; + bool isKeyImageKnown() const override; + bool isKeyImageRequest() const override; + uint64_t pkIndex() const override; + std::vector> uses() const override; + + // Multisig + bool isKeyImagePartial() const override; + +private: + friend class WalletImpl; + + // Ko + std::string m_onetime_address; + // view_tag + std::string m_view_tag; + // this enote was received at block height + std::uint64_t m_block_height; + // tx id in which tx enote was received + std::string m_tx_id; + // relative index in tx + std::uint64_t m_internal_enote_index; + // absolute index from `cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry.output_indices` + std::uint64_t m_global_enote_index; + // is spent + bool m_spent; + // is frozen + bool m_frozen; + // blockchain height, set if spent + std::uint64_t m_spent_height; + // key image + std::string m_key_image; + // x, blinding factor in amount commitment C = x G + a H + std::string m_mask; + // a + std::uint64_t m_amount; + // protocol version : Tx_Protocol_CryptoNote / Tx_Protocol_RingCT + TxProtocol m_protocol_version; + // is key image known + bool m_key_image_known; + // view wallets: we want to request it; cold wallets: it was requested + bool m_key_image_request; + // public key index in tx_extra + uint64_t m_pk_index; + // track uses of this enote in the blockchain in the format [ [block_height, tx_id], ... ] if `wallet2::m_track_uses` is true (default is false) + std::vector> m_uses; + +// QUESTION : Any input on these multisig members? I'd ignore them for now. + // Multisig + bool m_key_image_partial; +/* + std::vector m_multisig_k; + std::vector m_multisig_info; // one per other participant +*/ +}; + +} // namespace diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index f599125987..a4ce5dfb87 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -30,6 +30,7 @@ #include "wallet.h" +#include "enote_details.h" #include "pending_transaction.h" #include "unsigned_transaction.h" #include "transaction_history.h" @@ -3074,43 +3075,43 @@ void WalletImpl::processPoolState(const std::vector &enote_details) const +void WalletImpl::getEnoteDetails(std::vector> &enote_details) const { tools::wallet2::transfer_container tc; m_wallet->get_transfers(tc); enote_details.reserve(tc.size()); - for (auto &td : tc) + for (const auto &td : tc) { - EnoteDetails ed{}; + auto ed = std::make_shared(); cryptonote::txout_target_v txout_v = td.m_tx.vout[td.m_internal_output_index].target; if (txout_v.type() == typeid(cryptonote::txout_to_key)) - ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); + ed->m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); else if (txout_v.type() == typeid(cryptonote::txout_to_tagged_key)) { - ed.m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); - ed.m_view_tag = epee::string_tools::pod_to_hex(boost::get(txout_v).view_tag); + ed->m_onetime_address = epee::string_tools::pod_to_hex(boost::get(txout_v).key); + ed->m_view_tag = epee::string_tools::pod_to_hex(boost::get(txout_v).view_tag); } - ed.m_block_height = td.m_block_height; - ed.m_tx_id = epee::string_tools::pod_to_hex(td.m_txid); - ed.m_internal_enote_index = td.m_internal_output_index; - ed.m_global_enote_index = td.m_global_output_index; - ed.m_spent = td.m_spent; - ed.m_frozen = td.m_frozen; - ed.m_spent_height = td.m_spent_height; - ed.m_key_image = epee::string_tools::pod_to_hex(td.m_key_image); - ed.m_mask = epee::string_tools::pod_to_hex(td.m_mask); - ed.m_amount = td.m_amount; - ed.m_protocol_version = td.m_rct ? EnoteDetails::rct : EnoteDetails::cn; - ed.m_key_image_known = td.m_key_image_known; - ed.m_key_image_request = td.m_key_image_request; - ed.m_pk_index = td.m_pk_index; - ed.m_uses.reserve(td.m_uses.size()); + ed->m_block_height = td.m_block_height; + ed->m_tx_id = epee::string_tools::pod_to_hex(td.m_txid); + ed->m_internal_enote_index = td.m_internal_output_index; + ed->m_global_enote_index = td.m_global_output_index; + ed->m_spent = td.m_spent; + ed->m_frozen = td.m_frozen; + ed->m_spent_height = td.m_spent_height; + ed->m_key_image = epee::string_tools::pod_to_hex(td.m_key_image); + ed->m_mask = epee::string_tools::pod_to_hex(td.m_mask); + ed->m_amount = td.m_amount; + ed->m_protocol_version = td.m_rct ? EnoteDetails::Tx_Protocol_RingCT : EnoteDetails::Tx_Protocol_CryptoNote; + ed->m_key_image_known = td.m_key_image_known; + ed->m_key_image_request = td.m_key_image_request; + ed->m_pk_index = td.m_pk_index; + ed->m_uses.reserve(td.m_uses.size()); for (auto &u : td.m_uses) - ed.m_uses.push_back(std::make_pair(u.first, epee::string_tools::pod_to_hex(u.second))); - ed.m_key_image_partial = td.m_key_image_partial; + ed->m_uses.push_back(std::make_pair(u.first, epee::string_tools::pod_to_hex(u.second))); + ed->m_key_image_partial = td.m_key_image_partial; enote_details.push_back(ed); } @@ -3691,16 +3692,16 @@ bool WalletImpl::importKeyImages(std::vector key_images, std::size_ //------------------------------------------------------------------------------------------------------------------- std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) const { - std::vector enote_details; + std::vector> enote_details; getEnoteDetails(enote_details); for (size_t idx = 0; idx < enote_details.size(); ++idx) { - const EnoteDetails &ed = enote_details[idx]; - if (ed.m_key_image == key_image) + const auto &ed = std::dynamic_pointer_cast(enote_details[idx]); + if (ed->m_key_image == key_image) { - if (ed.m_key_image_known) + if (ed->m_key_image_known) return idx; - else if (ed.m_key_image_partial) + else if (ed->m_key_image_partial) setStatusError("Failed to get enote index by key image: Enote detail lookups are not allowed for multisig partial key images"); } } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 7bc6b16efd..196ce38a89 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -42,6 +42,7 @@ class WalletApiAccessorTest; namespace Monero { +class EnoteDetailsImpl; class TransactionHistoryImpl; class PendingTransactionImpl; class UnsignedTransactionImpl; @@ -248,7 +249,7 @@ class WalletImpl : public Wallet void writeWatchOnlyWallet(const std::string &password, std::string &new_keys_file_name) override; void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; void processPoolState(const std::vector> &txs) override; - void getEnoteDetails(std::vector &enote_details) const override; + void getEnoteDetails(std::vector> &enote_details) const override; std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 5aad155dcf..d53c01922f 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -75,48 +75,32 @@ enum NetworkType : uint8_t { */ struct EnoteDetails { - // QUESTION : If this struct is done, should I create the files "src/wallet/api/enote_details.[h/cpp]", put all the member variables inside the header and only set virtual getter functions in here, like it's done for other structs below? - // Ko - std::string m_onetime_address; - // view_tag - std::string m_view_tag; - // this enote was received at block height - std::uint64_t m_block_height; - // tx id in which tx enote was received - std::string m_tx_id; - // relative index in tx - std::uint64_t m_internal_enote_index; - // absolute index from `cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry.output_indices` - std::uint64_t m_global_enote_index; - // is spent - bool m_spent; - // is frozen - bool m_frozen; - // blockchain height, set if spent - std::uint64_t m_spent_height; - // key image - std::string m_key_image; - // x, blinding factor in amount commitment C = x G + a H - std::string m_mask; - // a - std::uint64_t m_amount; - // protocol version : cn = CryptoNote, rct = RingCT - enum { cn, rct } m_protocol_version; - // is key image known - bool m_key_image_known; - // view wallets: we want to request it; cold wallets: it was requested - bool m_key_image_request; - // public key index in tx_extra - uint64_t m_pk_index; - // track uses of this enote in the blockchain in the format [ [block_height, tx_id], ... ] if `wallet2::m_track_uses` is true (default is false) - std::vector> m_uses; -// QUESTION : Any input on these multisig members? I'd ignore them for now. + enum TxProtocol { + Tx_Protocol_CryptoNote, + Tx_Protocol_RingCT + }; + + virtual ~EnoteDetails() = 0; + virtual std::string onetimeAddress() const = 0; + virtual std::string viewTag() const = 0; + virtual std::uint64_t blockHeight() const = 0; + virtual std::string txId() const = 0; + virtual std::uint64_t internalEnoteIndex() const = 0; + virtual std::uint64_t globalEnoteIndex() const = 0; + virtual bool isSpent() const = 0; + virtual bool isFrozen() const = 0; + virtual std::uint64_t spentHeight() const = 0; + virtual std::string keyImage() const = 0; + virtual std::string mask() const = 0; + virtual std::uint64_t amount() const = 0; + virtual TxProtocol protocolVersion() const = 0; + virtual bool isKeyImageKnown() const = 0; + virtual bool isKeyImageRequest() const = 0; + virtual uint64_t pkIndex() const = 0; + virtual std::vector> uses() const = 0; + // Multisig - bool m_key_image_partial; - /* - std::vector m_multisig_k; - std::vector m_multisig_info; // one per other participant - */ + virtual bool isKeyImagePartial() const = 0; }; /** @@ -1318,7 +1302,7 @@ struct Wallet * brief: getEnoteDetails - get information about all enotes * outparam: enote_details - */ - virtual void getEnoteDetails(std::vector &enote_details) const = 0; + virtual void getEnoteDetails(std::vector> &enote_details) const = 0; /** * brief: convertMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction * param: multisig_ptx - multisig pending transaction From 4f393f84bda6b17cf377a8a460700b023f9863b9 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 21 Oct 2024 11:53:02 +0200 Subject: [PATCH 21/25] Clean up, remove: (Method name: reason) signTxToStr: gets added in #9492 as `signAsString()` loadTx: not needed, all it does is `loadFromFile()` and `parseTxFromStr()` estimateBacklog(min_tx_weight, max_tx_weight, fees): not needed, calls `estimateBacklog(fee_levels)` --- src/wallet/api/enote_details.cpp | 2 +- src/wallet/api/enote_details.h | 4 +- src/wallet/api/transaction_history.cpp | 2 +- src/wallet/api/transaction_info.cpp | 2 +- src/wallet/api/transaction_info.h | 6 +- src/wallet/api/wallet.cpp | 98 ++++++-------------------- src/wallet/api/wallet.h | 8 ++- src/wallet/api/wallet2_api.h | 24 +------ 8 files changed, 37 insertions(+), 109 deletions(-) diff --git a/src/wallet/api/enote_details.cpp b/src/wallet/api/enote_details.cpp index 5b42a4e88e..55576f6e11 100644 --- a/src/wallet/api/enote_details.cpp +++ b/src/wallet/api/enote_details.cpp @@ -84,7 +84,7 @@ bool EnoteDetailsImpl::isKeyImageKnown() const { return m_key_image_known; } bool EnoteDetailsImpl::isKeyImageRequest() const { return m_key_image_request; } -uint64_t EnoteDetailsImpl::pkIndex() const +std::uint64_t EnoteDetailsImpl::pkIndex() const { return m_pk_index; } std::vector> EnoteDetailsImpl::uses() const { return m_uses; } diff --git a/src/wallet/api/enote_details.h b/src/wallet/api/enote_details.h index 4f4b8b0d40..8c22c1fc17 100644 --- a/src/wallet/api/enote_details.h +++ b/src/wallet/api/enote_details.h @@ -53,7 +53,7 @@ class EnoteDetailsImpl : public EnoteDetails TxProtocol protocolVersion() const override; bool isKeyImageKnown() const override; bool isKeyImageRequest() const override; - uint64_t pkIndex() const override; + std::uint64_t pkIndex() const override; std::vector> uses() const override; // Multisig @@ -93,7 +93,7 @@ class EnoteDetailsImpl : public EnoteDetails // view wallets: we want to request it; cold wallets: it was requested bool m_key_image_request; // public key index in tx_extra - uint64_t m_pk_index; + std::uint64_t m_pk_index; // track uses of this enote in the blockchain in the format [ [block_height, tx_id], ... ] if `wallet2::m_track_uses` is true (default is false) std::vector> m_uses; diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 501d5302e0..16ab43d4e3 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -241,7 +241,7 @@ void TransactionHistoryImpl::refresh() ti->m_confirmations = 0; ti->m_unlock_time = pd.m_tx.unlock_time; ti->m_change = pd.m_change; - ti->m_tx_state = pd.m_state; + ti->m_tx_state = (TransactionInfo::TxState) pd.m_state; // not used for unconfirmed_transfer_details ti->m_double_spend_seen = false; for (const auto &d : pd.m_dests) diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 9b6d20d656..4e09f6ec8b 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -154,7 +154,7 @@ std::uint64_t TransactionInfoImpl::receivedChangeAmount() const return m_change; } -int TransactionInfoImpl::txState() const +TransactionInfo::TxState TransactionInfoImpl::txState() const { return m_tx_state; } diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 7a26dec2fc..7daf10592a 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -64,7 +64,7 @@ class TransactionInfoImpl : public TransactionInfo virtual uint64_t unlockTime() const override; std::uint64_t receivedChangeAmount() const override; - int txState() const override; + TxState txState() const override; bool isDoubleSpendSeen() const override; private: @@ -87,8 +87,8 @@ class TransactionInfoImpl : public TransactionInfo uint64_t m_unlock_time; // received change amount from outgoing transaction std::uint64_t m_change; - // enum TxState - int m_tx_state; + // tx state : pending / pending_in_pool / failed / confirmed + TxState m_tx_state; // is double spend seen bool m_double_spend_seen; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index a4ce5dfb87..a1dd8566ff 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -506,6 +506,8 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co return false; } setSeedLanguage(language); + if (!statusOk()) + return false; crypto::secret_key recovery_val, secret_key; try { recovery_val = m_wallet->generate(path, password, secret_key, false, false); @@ -681,6 +683,8 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path, if(has_spendkey && !has_viewkey) { m_wallet->generate(path, password, spendkey, true, false); setSeedLanguage(language); + if (!statusOk()) + return false; LOG_PRINT_L1("Generated deterministic wallet from spend key with seed language: " + language); } @@ -737,7 +741,7 @@ bool WalletImpl::open(const std::string &path, const std::string &password) LOG_ERROR("Error opening wallet: " << e.what()); setStatusCritical(e.what()); } - return status() == Status_Ok; + return statusOk(); } bool WalletImpl::recover(const std::string &path, const std::string &seed) @@ -773,12 +777,14 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c try { setSeedLanguage(old_language); + if (!statusOk()) + return false; m_wallet->generate(path, password, recovery_key, true, false); } catch (const std::exception &e) { setStatusCritical(e.what()); } - return status() == Status_Ok; + return statusOk(); } bool WalletImpl::close(bool do_store) @@ -864,7 +870,7 @@ bool WalletImpl::setPassword(const std::string &password) } catch (const std::exception &e) { setStatusError(e.what()); } - return status() == Status_Ok; + return statusOk(); } const std::string& WalletImpl::getPassword() const @@ -880,7 +886,7 @@ bool WalletImpl::setDevicePin(const std::string &pin) } catch (const std::exception &e) { setStatusError(e.what()); } - return status() == Status_Ok; + return statusOk(); } bool WalletImpl::setDevicePassphrase(const std::string &passphrase) @@ -891,7 +897,7 @@ bool WalletImpl::setDevicePassphrase(const std::string &passphrase) } catch (const std::exception &e) { setStatusError(e.what()); } - return status() == Status_Ok; + return statusOk(); } std::string WalletImpl::address(uint32_t accountIndex, uint32_t addressIndex) const @@ -1084,7 +1090,7 @@ bool WalletImpl::refresh() //TODO: make doRefresh return bool to know whether the error occured during refresh or not //otherwise one may try, say, to send transaction, transfer fails and this method returns false doRefresh(); - return status() == Status_Ok; + return statusOk(); } void WalletImpl::refreshAsync() @@ -1101,7 +1107,7 @@ bool WalletImpl::rescanBlockchain() clearStatus(); m_refreshShouldRescan = true; doRefresh(); - return status() == Status_Ok; + return statusOk(); } void WalletImpl::rescanBlockchainAsync() @@ -1276,7 +1282,7 @@ bool WalletImpl::importOutputs(const string &filename) try { size_t n_outputs = importEnotesFromStr(data); - if (status() != Status_Ok) + if (!statusOk()) throw runtime_error(errorString()); LOG_PRINT_L2(std::to_string(n_outputs) << " outputs imported"); } @@ -1644,10 +1650,8 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector(priority)); - if (status() != Status_Ok) - { + if (!statusOk()) return transaction; - } do { if (checkBackgroundSync("cannot create transactions")) @@ -3188,44 +3192,6 @@ bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, Unsi return true; } //------------------------------------------------------------------------------------------------------------------- -std::string WalletImpl::signTxToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx) const -{ - clearStatus(); - - tools::wallet2::unsigned_tx_set &utx_set = dynamic_cast(&exported_txs)->m_unsigned_tx_set; - PendingTransactionImpl *ptx_impl = dynamic_cast(&ptx); - - std::string signed_tx_data; - tools::wallet2::signed_tx_set signed_txs; - - try - { - signed_tx_data = m_wallet->sign_tx_dump_to_str(utx_set, ptx_impl->m_pending_tx, signed_txs); - } - catch (const exception &e) - { - setStatusError(string(tr("Failed to sign tx: ")) + e.what()); - return ""; - } - - ptx_impl->m_key_images = signed_txs.key_images; - return signed_tx_data; -} -//------------------------------------------------------------------------------------------------------------------- -bool WalletImpl::loadTx(const std::string &signed_filename, PendingTransaction &ptx) const -{ - clearStatus(); - - PendingTransactionImpl *ptx_impl = dynamic_cast(&ptx); - - if (!m_wallet->load_tx(signed_filename, ptx_impl->m_pending_tx)) - { - setStatusError((boost::format(tr("Failed to load tx from file with filename `%s`. For more info see log file")) % signed_filename).str()); - return false; - } - return true; -} -//------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const { clearStatus(); @@ -3504,33 +3470,6 @@ std::vector> WalletImpl::estimateBacklog return { std::make_pair(0, 0) }; } //------------------------------------------------------------------------------------------------------------------- -std::vector> WalletImpl::estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const -{ - clearStatus(); - - if (min_tx_weight == 0 || max_tx_weight == 0) - { - setStatusError("Invalid 0 weight"); - return { std::make_pair(0, 0) }; - } - for (std::uint64_t fee: fees) - { - if (fee == 0) - { - setStatusError("Invalid 0 fee"); - return { std::make_pair(0, 0) }; - } - } - - std::vector> fee_levels; - for (uint64_t fee: fees) - { - double our_fee_byte_min = fee / (double)min_tx_weight, our_fee_byte_max = fee / (double)max_tx_weight; - fee_levels.emplace_back(our_fee_byte_min, our_fee_byte_max); - } - return estimateBacklog(fee_levels); -} -//------------------------------------------------------------------------------------------------------------------- bool WalletImpl::saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable /* = false */) const { return m_wallet->save_to_file(path_to_file, binary, is_printable); @@ -3710,5 +3649,12 @@ std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) const return 0; } //------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::statusOk() const +{ + boost::lock_guard l(m_statusMutex); + return m_status == Status_Ok; +} +//------------------------------------------------------------------------------------------------------------------- + } // namespace diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 196ce38a89..f44a841b9b 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -254,8 +254,6 @@ class WalletImpl : public Wallet bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; - std::string signTxToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx) const override; - bool loadTx(const std::string &signed_filename, PendingTransaction &ptx) const override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; std::uint64_t getBaseFee() const override; @@ -271,7 +269,6 @@ class WalletImpl : public Wallet std::size_t importEnotesFromStr(const std::string &enotes_str) override; std::uint64_t getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const override; std::vector> estimateBacklog(const std::vector> &fee_levels) const override; - std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const override; bool saveToFile(const std::string &path_to_file, const std::string &binary, bool is_printable = false) const override; bool loadFromFile(const std::string &path_to_file, std::string &target_str, std::size_t max_size = 1000000000) const override; std::uint64_t hashEnotes(std::uint64_t enote_idx, std::string &hash) const override; @@ -301,6 +298,11 @@ class WalletImpl : public Wallet * return: enote index */ std::size_t getEnoteIndex(const std::string &key_image) const; + /** + * brief: statusOk - + * return: true if status is ok, else false + */ + bool statusOk() const; private: friend class PendingTransactionImpl; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index d53c01922f..dbbdf22fae 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -96,7 +96,7 @@ struct EnoteDetails virtual TxProtocol protocolVersion() const = 0; virtual bool isKeyImageKnown() const = 0; virtual bool isKeyImageRequest() const = 0; - virtual uint64_t pkIndex() const = 0; + virtual std::uint64_t pkIndex() const = 0; virtual std::vector> uses() const = 0; // Multisig @@ -246,7 +246,7 @@ struct TransactionInfo virtual const std::vector & transfers() const = 0; virtual std::uint64_t receivedChangeAmount() const = 0; - virtual int txState() const = 0; + virtual TxState txState() const = 0; virtual bool isDoubleSpendSeen() const = 0; }; /** @@ -1333,22 +1333,7 @@ struct Wallet * note: sets status error on fail */ virtual bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const = 0; - /** - * brief: signTxToStr - get a signed pending transaction from an unsigned transaction - * param: exported_txs - unsigned transaction - * outparam: ptx - signed pending transaction - * return: signed tx data as encrypted hex string - * note: sets status error on fail - */ - virtual std::string signTxToStr(UnsignedTransaction &exported_txs, PendingTransaction &ptx) const = 0; // TODO : if it's fine to drop the accept_func, do it for all the functions below (where possible, meaning accept_func is optional in wallet2 params) - /** - * brief: loadTx - load pending transactions from a file - * param: signed_filename - - * outparam: ptx - - * return: true if succeeded - */ - virtual bool loadTx(const std::string &signed_filename, PendingTransaction &ptx) const = 0; // TODO : accept_func with wallet2::signed_tx_set /** * brief: parseTxFromStr - get transactions from encrypted signed transaction as hex string @@ -1477,18 +1462,13 @@ struct Wallet * note: sets status error on fail */ virtual std::uint64_t getBlockchainHeightByDate(std::uint16_t year, std::uint8_t month, std::uint8_t day) const = 0; - // QUESTION : Can anyone help with these comments? /** * brief: estimateBacklog - * param: fee_levels - [ [fee per byte min, fee per byte max], ... ] - * param: min_tx_weight - - * param: max_tx_weight - - * param: fees - * return: [ [number of blocks min, number of blocks max], ... ] * note: sets status error on fail */ virtual std::vector> estimateBacklog(const std::vector> &fee_levels) const = 0; - virtual std::vector> estimateBacklog(std::uint64_t min_tx_weight, std::uint64_t max_tx_weight, const std::vector &fees) const = 0; // TODO : mms::multisig_wallet_state - from a quick search for get_multisig_wallet_state in simplewallet.cpp this will be complicated to replace /** * brief: getMultisigWalletState - From 19ad41fbc9d322044fe70af503e023855c713f0d Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 21 Oct 2024 21:16:55 +0200 Subject: [PATCH 22/25] accept_func almost complete --- src/wallet/api/wallet.cpp | 43 +++++++----------------------------- src/wallet/api/wallet.h | 1 + src/wallet/api/wallet2_api.h | 23 +------------------ 3 files changed, 10 insertions(+), 57 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index a1dd8566ff..e98c5e6021 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1161,8 +1161,7 @@ bool WalletImpl::submitTransaction(const string &fileName) { return false; std::unique_ptr transaction(new PendingTransactionImpl(*this)); - PendingTransaction *ptx_interface = dynamic_cast(transaction.get()); - bool r = loadTx(fileName, *ptx_interface); + bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx); if (!r) { setStatus(Status_Ok, tr("Failed to load transaction from file")); return false; @@ -3184,12 +3183,13 @@ std::string WalletImpl::convertTxToStr(const PendingTransaction &ptxs) const bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const { UnsignedTransactionImpl *utx_impl = dynamic_cast(&exported_txs); - if (!m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, utx_impl->m_unsigned_tx_set)) - { - setStatusError(tr("Failed to parse unsigned tx from string. For more info see log file")); - return false; - } - return true; + return m_wallet->parse_unsigned_tx_from_str(unsigned_tx_str, utx_impl->m_unsigned_tx_set); +} +//------------------------------------------------------------------------------------------------------------------- +bool WalletImpl::parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx) const +{ + PendingTransactionImpl *ptx_impl = dynamic_cast(&ptx); + return m_wallet->parse_tx_from_str(signed_tx_str, ptx_impl->m_pending_tx, NULL); } //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const @@ -3219,33 +3219,6 @@ bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, Pend return false; } //------------------------------------------------------------------------------------------------------------------- -//bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) -//{ -// clearStatus(); -// -// try -// { -// checkMultisigWalletReady(m_wallet); -// -// tools::wallet2::multisig_tx_set multisig_tx; -// -// // QUESTION / TODO : How to translate the accept_func? -// if (!m_wallet->load_multisig_tx_from_file(filename, multisig_tx, accept_func)) -// throw runtime_error(tr("Failed to load multisig transaction from file.")); -// -// exported_txs.m_pending_tx = multisig_tx.m_ptx; -// exported_txs.m_signers = multisig_tx.m_signers; -// -// return true; -// } -// catch (const exception &e) -// { -// setStatusError(e.what()); -// } -// -// return false; -//} -//------------------------------------------------------------------------------------------------------------------- std::uint64_t WalletImpl::getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index f44a841b9b..c82fb1c42f 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -254,6 +254,7 @@ class WalletImpl : public Wallet bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; + bool parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx) const override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; std::uint64_t getBaseFee() const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index dbbdf22fae..7f9e3feb17 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1330,19 +1330,15 @@ struct Wallet * param: unsigned_tx_str - encrypted hex string * outparam: exported_txs - * return: true if succeeded - * note: sets status error on fail */ virtual bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const = 0; - // TODO : if it's fine to drop the accept_func, do it for all the functions below (where possible, meaning accept_func is optional in wallet2 params) -// TODO : accept_func with wallet2::signed_tx_set /** * brief: parseTxFromStr - get transactions from encrypted signed transaction as hex string * param: signed_tx_str - * outparam: ptx - - * param: accept_func - callback function to verify the transaction * return: true if succeeded */ -// virtual bool parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx, std::function accept_func) const = 0; + virtual bool parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx) const = 0; /** * brief: parseMultisigTxFromStr - get pending multisig transaction from encrypted unsigned multisig transaction as hex string * param: multisig_tx_str - @@ -1351,23 +1347,6 @@ struct Wallet * note: sets status error on fail */ virtual bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const = 0; -// TODO : accept_func with wallet2::multisig_tx_set - /** - * brief: loadMultisigTxFromFile - load a multisig transaction set from a file - * param: multisig_tx_str - - * outparam: exported_txs - - * return: true if succeeded - */ -// virtual bool loadMultisigTxFromFile(const std::string &filename, PendingTransaction &exported_txs, std::function accept_func) const = 0; -// TODO : accept_func with wallet2::multisig_tx_set - /** - * brief: signMultisigTxFromFile - load a multisig transaction set from a file, sign it and store to a file - * param: filename - load from and store to file with this filename - * outparam: txids - transaction ids of signed transactions - * param: accept_func - callback function to verify the transaction - * return: true if succeeded - */ -// virutal bool signMultisigTxFromFile(const std::string &filename, std::vector &txids, std::function accept_func) const = 0; /** * brief: getFeeMultiplier - * param: priority - From 9ab6da338fcd19a06ec4ec3bac4dab21e62f8840 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Fri, 25 Oct 2024 15:06:23 +0200 Subject: [PATCH 23/25] mini clean up --- src/wallet/api/wallet.cpp | 1 - src/wallet/api/wallet2_api.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index e98c5e6021..328ed2664c 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -573,7 +573,6 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas // Export/Import key images // We already know the spent status from the outputs we exported, thus no need to check them again - // TODO : `exportKeyImages()` is only implemented to export to file, consider adding `exportKeyImagesToStr()` or something. auto key_images = m_wallet->export_key_images(true/*all*/); uint64_t spent = 0; uint64_t unspent = 0; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 7f9e3feb17..6f308a4ced 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1407,7 +1407,7 @@ struct Wallet * param: tag - * note: sets status error on fail */ - virtual void setAccountTag(const std::set &account_indices, const std::string &tag) = 0; + virtual void setAccountTag(const std::set &account_indices, const std::string &tag) = 0; /** * brief: setAccountTagDescription - set a description for a tag, tag must already exist * param: tag - From 450bdccad29e99d6ba6419d004bb08c066a01289 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Mon, 28 Oct 2024 17:18:39 +0100 Subject: [PATCH 24/25] split up parse_tx_from_str() so accept_func() can be applied outside the Wallet API --- src/wallet/api/pending_transaction.h | 2 ++ src/wallet/api/wallet.cpp | 15 +++++++++++---- src/wallet/api/wallet.h | 1 + src/wallet/api/wallet2_api.h | 10 ++++++++++ src/wallet/wallet2.cpp | 26 +++++++++++++++++++------- src/wallet/wallet2.h | 3 ++- 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h index 9d8d754c0c..f6eac46577 100644 --- a/src/wallet/api/pending_transaction.h +++ b/src/wallet/api/pending_transaction.h @@ -69,6 +69,8 @@ class PendingTransactionImpl : public PendingTransaction std::unordered_set m_signers; std::vector m_tx_device_aux; std::vector m_key_images; + // wallet2 m_cold_key_images + std::unordered_map m_tx_key_images; }; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 328ed2664c..fe697b1255 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3188,7 +3188,16 @@ bool WalletImpl::parseUnsignedTxFromStr(const std::string &unsigned_tx_str, Unsi bool WalletImpl::parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx) const { PendingTransactionImpl *ptx_impl = dynamic_cast(&ptx); - return m_wallet->parse_tx_from_str(signed_tx_str, ptx_impl->m_pending_tx, NULL); + std::shared_ptr signed_tx_set_out = std::make_shared(); + bool r = m_wallet->parse_tx_from_str(signed_tx_str, ptx_impl->m_pending_tx, /* accept_func = */ NULL, signed_tx_set_out.get(), /* do_handle_key_images = */ false); + if (r) + ptx_impl->m_tx_key_images = signed_tx_set_out->tx_key_images; + return r; +} +//------------------------------------------------------------------------------------------------------------------- +void WalletImpl::insertColdKeyImages(PendingTransaction &ptx) +{ + m_wallet->insert_cold_key_images(dynamic_cast(&ptx)->m_tx_key_images); } //------------------------------------------------------------------------------------------------------------------- bool WalletImpl::parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const @@ -3272,9 +3281,7 @@ void WalletImpl::coldSignTx(const PendingTransaction &ptx_in, PendingTransaction m_wallet->cold_sign_tx(ptx_impl_in->m_pending_tx, signed_txs, dsts_info, ptx_impl_out->m_tx_device_aux); ptx_impl_out->m_key_images = signed_txs.key_images; ptx_impl_out->m_pending_tx = signed_txs.ptx; - // TODO : figure out if we need signed_txs.tx_key_images here, afaik they're used for selfsend/change enotes - // if needed we can probably add a member like `m_selfsend_key_images` to `PendingTransaction` - // guess then `PendingTransaction` would be a proper replacement for `wallet2::signed_tx_set` + ptx_impl_out->m_tx_key_images = signed_txs.tx_key_images; } catch (const std::exception &e) { diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c82fb1c42f..91416ff083 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -255,6 +255,7 @@ class WalletImpl : public Wallet std::string convertTxToStr(const PendingTransaction &ptxs) const override; bool parseUnsignedTxFromStr(const std::string &unsigned_tx_str, UnsignedTransaction &exported_txs) const override; bool parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx) const override; + void insertColdKeyImages(PendingTransaction &ptx) override; bool parseMultisigTxFromStr(const std::string &multisig_tx_str, PendingTransaction &exported_txs) const override; std::uint64_t getFeeMultiplier(std::uint32_t priority, int fee_algorithm) const override; std::uint64_t getBaseFee() const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 6f308a4ced..171c30c036 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1340,6 +1340,16 @@ struct Wallet */ virtual bool parseTxFromStr(const std::string &signed_tx_str, PendingTransaction &ptx) const = 0; /** + * brief: insertColdKeyImages - remember cold key images for parsed tx, for when we get those txes from the blockchain + * Call: + * - parseTxFromStr() + * - accept_func() (optional) + * - importKeyImages() + * - insertColdKeyImages() + * param: ptx - PendingTransaction obtained from parseTxFromStr() outparam ptx + */ + virtual void insertColdKeyImages(PendingTransaction &ptx) = 0; + /** * brief: parseMultisigTxFromStr - get pending multisig transaction from encrypted unsigned multisig transaction as hex string * param: multisig_tx_str - * outparam: exported_txs - diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3874ce8504..d1674abcf2 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -7979,7 +7979,7 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector &ptx, std::function accept_func) +bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector &ptx, std::function accept_func, tools::wallet2::signed_tx_set *signed_txs_out /* = nullptr */, bool do_handle_key_images /* = true */) { std::string s = signed_tx_st; signed_tx_set signed_txs; @@ -8073,19 +8073,31 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector &cold_key_images) +{ + for (const auto &ki: cold_key_images) + m_cold_key_images.insert(ki); +} +//---------------------------------------------------------------------------------------------------- std::string wallet2::save_multisig_tx(multisig_tx_set txs) { LOG_PRINT_L0("saving " << txs.m_ptx.size() << " multisig transactions"); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 7228f19077..3d99359935 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1198,7 +1198,8 @@ namespace tools bool load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs) const; bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const; bool load_tx(const std::string &signed_filename, std::vector &ptx, std::function accept_func = NULL); - bool parse_tx_from_str(const std::string &signed_tx_st, std::vector &ptx, std::function accept_func); + bool parse_tx_from_str(const std::string &signed_tx_st, std::vector &ptx, std::function accept_func, signed_tx_set *signed_tx_set_out = nullptr, bool do_handle_key_images = true); + void insert_cold_key_images(std::unordered_map &cold_key_images); std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose std::vector create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices); std::vector create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector& extra); From 6704d5539696b86f420614cf0c0a562fbff1ea94 Mon Sep 17 00:00:00 2001 From: SNeedlewoods Date: Thu, 31 Oct 2024 19:20:15 +0100 Subject: [PATCH 25/25] jeffro256 review - add `refreshPoolOnly()` which handles `upadte_pool_state()` and `process_pool_state` - remove `cryptonote_basic.h` from interface - change `shared_ptr` to `unique_ptr` --- src/wallet/api/wallet.cpp | 47 +++++++++++++----------------------- src/wallet/api/wallet.h | 5 ++-- src/wallet/api/wallet2_api.h | 24 +++--------------- 3 files changed, 23 insertions(+), 53 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index fe697b1255..fea8368586 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -3029,10 +3029,11 @@ void WalletImpl::writeWatchOnlyWallet(const std::string &password, std::string & } } //------------------------------------------------------------------------------------------------------------------- -void WalletImpl::updatePoolState(std::vector> &process_txs, bool refreshed, bool try_incremental) +void WalletImpl::refreshPoolOnly(bool refreshed /*false*/, bool try_incremental /*false*/) { clearStatus(); + // Update pool state std::vector> process_txs_pod; try { @@ -3045,30 +3046,13 @@ void WalletImpl::updatePoolState(std::vector(tx), epee::string_tools::pod_to_hex(std::get<1>(tx)), std::get<2>(tx))); -} -//------------------------------------------------------------------------------------------------------------------- -void WalletImpl::processPoolState(const std::vector> &txs) -{ - clearStatus(); - - std::vector> txs_pod; - crypto::hash tx_id; - for (auto &tx : txs) - { - if (!epee::string_tools::hex_to_pod(std::get<1>(tx), tx_id)) - { - setStatusError(string(tr("Failed to parse tx_id: ")) + std::get<1>(tx)); - return; - } - txs_pod.push_back(std::make_tuple(std::get<0>(tx), tx_id, std::get<2>(tx))); - } + if (process_txs_pod.empty()) + return; + // Process pool state try { - m_wallet->process_pool_state(txs_pod); + m_wallet->process_pool_state(process_txs_pod); } catch (const std::exception &e) { @@ -3077,7 +3061,7 @@ void WalletImpl::processPoolState(const std::vector> &enote_details) const +void WalletImpl::getEnoteDetails(std::vector> &enote_details) const { tools::wallet2::transfer_container tc; m_wallet->get_transfers(tc); @@ -3085,7 +3069,7 @@ void WalletImpl::getEnoteDetails(std::vector> &eno for (const auto &td : tc) { - auto ed = std::make_shared(); + auto ed = std::make_unique(); cryptonote::txout_target_v txout_v = td.m_tx.vout[td.m_internal_output_index].target; if (txout_v.type() == typeid(cryptonote::txout_to_key)) @@ -3115,7 +3099,7 @@ void WalletImpl::getEnoteDetails(std::vector> &eno ed->m_uses.push_back(std::make_pair(u.first, epee::string_tools::pod_to_hex(u.second))); ed->m_key_image_partial = td.m_key_image_partial; - enote_details.push_back(ed); + enote_details.push_back(std::move(ed)); } } //------------------------------------------------------------------------------------------------------------------- @@ -3610,17 +3594,20 @@ bool WalletImpl::importKeyImages(std::vector key_images, std::size_ //------------------------------------------------------------------------------------------------------------------- std::size_t WalletImpl::getEnoteIndex(const std::string &key_image) const { - std::vector> enote_details; + std::vector> enote_details; getEnoteDetails(enote_details); for (size_t idx = 0; idx < enote_details.size(); ++idx) { - const auto &ed = std::dynamic_pointer_cast(enote_details[idx]); - if (ed->m_key_image == key_image) + const auto &ed = dynamic_cast(*enote_details[idx].get()); + if (ed.m_key_image == key_image) { - if (ed->m_key_image_known) + if (ed.m_key_image_known) return idx; - else if (ed->m_key_image_partial) + else if (ed.m_key_image_partial) + { setStatusError("Failed to get enote index by key image: Enote detail lookups are not allowed for multisig partial key images"); + return 0; + } } } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 91416ff083..30ef6ba8de 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -247,9 +247,8 @@ class WalletImpl : public Wallet WalletState getWalletState() const override; void rewriteWalletFile(const std::string &wallet_name, const std::string &password) override; void writeWatchOnlyWallet(const std::string &password, std::string &new_keys_file_name) override; - void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) override; - void processPoolState(const std::vector> &txs) override; - void getEnoteDetails(std::vector> &enote_details) const override; + void refreshPoolOnly(bool refreshed = false, bool try_incremental = false) override; + void getEnoteDetails(std::vector> &enote_details) const override; std::string convertMultisigTxToStr(const PendingTransaction &multisig_ptx) const override; bool saveMultisigTx(const PendingTransaction &multisig_ptx, const std::string &filename) const override; std::string convertTxToStr(const PendingTransaction &ptxs) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 171c30c036..999a051c58 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -38,9 +38,9 @@ #include #include #include +#include #include -#include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/cryptonote_basic_impl.h" // Public interface for libwallet library @@ -1276,33 +1276,17 @@ struct Wallet */ virtual void writeWatchOnlyWallet(const std::string &password, std::string &new_keys_file_name) = 0; /** - * brief: updatePoolState - - * outparam: process_txs - [ [tx, tx_id, double_spend_seen], ... ] + * brief: refreshPoolOnly - calls wallet2 update_pool_state and process_pool_state * param: refreshed - (default: false) * param: try_incremental - (default: false) * note: sets status error on fail - * This public method is typically called to make sure that the wallet's pool state is up-to-date by - * clients like simplewallet and the RPC daemon. Before incremental update this was the same method - * that 'refresh' also used, but now it's more complicated because for the time being we support - * the "old" and the "new" way of updating the pool and because only the 'getblocks' call supports - * incremental update but we don't want any blocks here. - * - * simplewallet does NOT update the pool info during automatic refresh to avoid disturbing interactive - * messages and prompts. When it finally calls this method here "to catch up" so to say we can't use - * incremental update anymore, because with that we might miss some txs altogether. - */ - virtual void updatePoolState(std::vector> &process_txs, bool refreshed = false, bool try_incremental = false) = 0; - /** - * brief: processPoolState - - * param: txs - [ [tx, tx_id, double_spend_seen], ... ] - * note: sets status error on fail */ - virtual void processPoolState(const std::vector> &txs) = 0; + virtual void refreshPoolOnly(bool refreshed = false, bool try_incremental = false) = 0; /** * brief: getEnoteDetails - get information about all enotes * outparam: enote_details - */ - virtual void getEnoteDetails(std::vector> &enote_details) const = 0; + virtual void getEnoteDetails(std::vector> &enote_details) const = 0; /** * brief: convertMultisigTxToString - get the encrypted unsigned multisig transaction as hex string from a multisig pending transaction * param: multisig_ptx - multisig pending transaction