Electroneum
Loading...
Searching...
No Matches
tools::wallet2 Class Reference

#include <wallet2.h>

Classes

struct  multisig_info
struct  tx_scan_info_t
struct  transfer_details
struct  payment_details
struct  address_tx
struct  pool_payment_details
struct  unconfirmed_transfer_details
struct  confirmed_transfer_details
struct  tx_construction_data
struct  multisig_sig
struct  pending_tx
struct  unsigned_tx_set
struct  signed_tx_set
struct  multisig_tx_set
struct  keys_file_data
struct  cache_file_data
struct  address_book_row
struct  reserve_proof_entry
struct  parsed_block
struct  is_out_data
struct  tx_cache_data

Public Types

enum  RefreshType { RefreshFull , RefreshOptimizeCoinbase , RefreshNoCoinbase , RefreshDefault = RefreshOptimizeCoinbase }
enum  AskPasswordType { AskPasswordNever = 0 , AskPasswordOnAction = 1 , AskPasswordToDecrypt = 2 }
enum  BackgroundMiningSetupType { BackgroundMiningMaybe = 0 , BackgroundMiningYes = 1 , BackgroundMiningNo = 2 }
typedef std::vector< transfer_detailstransfer_container
typedef std::unordered_multimap< crypto::hash, payment_detailspayment_container
typedef std::tuple< uint64_t, crypto::public_key, rct::keyget_outs_entry

Public Member Functions

 wallet2 (cryptonote::network_type nettype=cryptonote::MAINNET, uint64_t kdf_rounds=1, bool unattended=false)
 ~wallet2 ()
void generate (const std::string &wallet_, const epee::wipeable_string &password, const epee::wipeable_string &multisig_data, bool create_address_file=false)
 Generates a wallet or restores one.
crypto::secret_key generate (const std::string &wallet, const epee::wipeable_string &password, const crypto::secret_key &recovery_param=crypto::secret_key(), bool recover=false, bool two_random=false, bool create_address_file=false)
 Generates a wallet or restores one.
void generate (const std::string &wallet, const epee::wipeable_string &password, const cryptonote::account_public_address &account_public_address, const crypto::secret_key &spendkey, const crypto::secret_key &viewkey, bool create_address_file=false)
 Creates a wallet from a public address and a spend/view secret key pair.
void generate (const std::string &wallet, const epee::wipeable_string &password, const cryptonote::account_public_address &account_public_address, const crypto::secret_key &viewkey=crypto::secret_key(), bool create_address_file=false)
 Creates a watch only wallet from a public address and a view secret key.
void restore (const std::string &wallet_, const epee::wipeable_string &password, const std::string &device_name, bool create_address_file=false)
 Restore a wallet hold by an HW.
std::string make_multisig (const epee::wipeable_string &password, const std::vector< std::string > &info, uint32_t threshold)
 Creates a multisig wallet.
std::string make_multisig (const epee::wipeable_string &password, const std::vector< crypto::secret_key > &view_keys, const std::vector< crypto::public_key > &spend_keys, uint32_t threshold)
 Creates a multisig wallet.
std::string exchange_multisig_keys (const epee::wipeable_string &password, const std::vector< std::string > &info)
std::string exchange_multisig_keys (const epee::wipeable_string &password, std::unordered_set< crypto::public_key > pkeys, std::vector< crypto::public_key > signers)
 Any but first round of keys exchange.
bool finalize_multisig (const epee::wipeable_string &password, const std::vector< std::string > &info)
 Finalizes creation of a multisig wallet.
bool finalize_multisig (const epee::wipeable_string &password, const std::unordered_set< crypto::public_key > &pkeys, std::vector< crypto::public_key > signers)
 Finalizes creation of a multisig wallet.
std::string get_multisig_info () const
cryptonote::blobdata export_multisig ()
size_t import_multisig (std::vector< cryptonote::blobdata > info)
void rewrite (const std::string &wallet_name, const epee::wipeable_string &password)
 Rewrites to the wallet file for wallet upgrade (doesn't generate key, assumes it's already there).
void write_watch_only_wallet (const std::string &wallet_name, const epee::wipeable_string &password, std::string &new_keys_filename)
 Writes to a file named based on the normal wallet (doesn't generate key, assumes it's already there).
void load (const std::string &wallet, const epee::wipeable_string &password)
void store ()
void store_to (const std::string &path, const epee::wipeable_string &password)
 store_to Stores wallet to another file(s), deleting old ones
std::string path () const
bool verify_password (const epee::wipeable_string &password)
 verifies given password is correct for default wallet keys file
cryptonote::account_baseget_account ()
const cryptonote::account_baseget_account () const
void encrypt_keys (const crypto::chacha_key &key)
void encrypt_keys (const epee::wipeable_string &password)
void decrypt_keys (const crypto::chacha_key &key)
void decrypt_keys (const epee::wipeable_string &password)
void set_refresh_from_block_height (uint64_t height)
uint64_t get_refresh_from_block_height () const
void explicit_refresh_from_block_height (bool expl)
bool explicit_refresh_from_block_height () const
bool deinit ()
bool init (std::string daemon_address="http://localhost:8080", boost::optional< epee::net_utils::http::login > daemon_login=boost::none, boost::asio::ip::tcp::endpoint proxy={}, uint64_t upper_transaction_weight_limit=0, bool trusted_daemon=true, epee::net_utils::ssl_options_t ssl_options=epee::net_utils::ssl_support_t::e_ssl_support_autodetect, std::string blockchain_db_path="")
bool set_daemon (std::string daemon_address="http://localhost:8080", boost::optional< epee::net_utils::http::login > daemon_login=boost::none, bool trusted_daemon=true, epee::net_utils::ssl_options_t ssl_options=epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
void stop ()
i_wallet2_callbackcallback () const
void callback (i_wallet2_callback *callback)
bool is_trusted_daemon () const
void set_trusted_daemon (bool trusted)
bool is_deterministic () const
 Checks if deterministic wallet.
bool get_seed (epee::wipeable_string &electrum_words, const epee::wipeable_string &passphrase=epee::wipeable_string()) const
bool light_wallet () const
 Checks if light wallet. A light wallet sends view key to a server where the blockchain is scanned.
void set_light_wallet (bool light_wallet)
uint64_t get_light_wallet_scanned_block_height () const
uint64_t get_light_wallet_blockchain_height () const
const std::string & get_seed_language () const
 Gets the seed language.
void set_seed_language (const std::string &language)
 Sets the seed language.
cryptonote::account_public_address get_subaddress (const cryptonote::subaddress_index &index) const
cryptonote::account_public_address get_address () const
boost::optional< cryptonote::subaddress_indexget_subaddress_index (const cryptonote::account_public_address &address) const
crypto::public_key get_subaddress_spend_public_key (const cryptonote::subaddress_index &index) const
std::vector< crypto::public_keyget_subaddress_spend_public_keys (uint32_t account, uint32_t begin, uint32_t end) const
std::string get_subaddress_as_str (const cryptonote::subaddress_index &index) const
std::string get_address_as_str () const
std::string get_integrated_address_as_str (const crypto::hash8 &payment_id) const
void add_subaddress_account (const std::string &label, const bool update_account_tags=true)
size_t get_num_subaddress_accounts () const
size_t get_num_subaddresses (uint32_t index_major) const
void add_subaddress (uint32_t index_major, const std::string &label)
void expand_subaddresses (const cryptonote::subaddress_index &index, const bool udpate_account_tags=true)
std::string get_subaddress_label (const cryptonote::subaddress_index &index) const
void set_subaddress_label (const cryptonote::subaddress_index &index, const std::string &label)
void set_subaddress_lookahead (size_t major, size_t minor)
std::pair< size_t, size_t > get_subaddress_lookahead () const
void account_major_offset (uint32_t offset)
uint32_t account_major_offset () const
bool is_deprecated () const
 Tells if the wallet file is deprecated.
void refresh (bool trusted_daemon)
void refresh (bool trusted_daemon, uint64_t start_height, uint64_t &blocks_fetched)
void refresh (bool trusted_daemon, uint64_t start_height, uint64_t &blocks_fetched, bool &received_etn, bool check_pool=true)
bool refresh (bool trusted_daemon, uint64_t &blocks_fetched, bool &received_etn, bool &ok)
void set_refresh_type (RefreshType refresh_type)
RefreshType get_refresh_type () const
cryptonote::network_type nettype () const
bool watch_only () const
bool multisig (bool *ready=NULL, uint32_t *threshold=NULL, uint32_t *total=NULL) const
bool has_multisig_partial_key_images () const
bool has_unknown_key_images () const
bool get_multisig_seed (epee::wipeable_string &seed, const epee::wipeable_string &passphrase=std::string(), bool raw=true) const
bool key_on_device () const
hw::device::device_type get_device_type () const
bool reconnect_device ()
uint64_t balance (uint32_t subaddr_index_major, bool public_blockchain) const
uint64_t unlocked_balance (uint32_t subaddr_index_major, bool public_blockchain, uint64_t *blocks_to_unlock=NULL) const
std::map< uint32_t, uint64_tbalance_per_subaddress (uint32_t subaddr_index_major, bool public_blockchain=false) const
std::map< uint32_t, std::pair< uint64_t, uint64_t > > unlocked_balance_per_subaddress (uint32_t subaddr_index_major, bool public_blockchain=false) const
uint64_t balance_all (bool public_blockchain) const
uint64_t unlocked_balance_all (bool public_blockchain, uint64_t *blocks_to_unlock=NULL) const
template<typename T>
void transfer_selected (const std::vector< cryptonote::tx_destination_entry > &dsts, const std::vector< size_t > &selected_transfers, size_t fake_outputs_count, std::vector< std::vector< tools::wallet2::get_outs_entry > > &outs, uint64_t unlock_time, uint64_t fee, const std::vector< uint8_t > &extra, T destination_split_strategy, const tx_dust_policy &dust_policy, cryptonote::transaction &tx, pending_tx &ptx)
void commit_tx (pending_tx &ptx_vector)
void commit_tx (std::vector< pending_tx > &ptx_vector)
bool save_tx (const std::vector< pending_tx > &ptx_vector, const std::string &filename) const
std::string dump_tx_to_str (const std::vector< pending_tx > &ptx_vector) const
std::string save_multisig_tx (multisig_tx_set txs)
bool save_multisig_tx (const multisig_tx_set &txs, const std::string &filename)
std::string save_multisig_tx (const std::vector< pending_tx > &ptx_vector)
bool save_multisig_tx (const std::vector< pending_tx > &ptx_vector, const std::string &filename)
multisig_tx_set make_multisig_tx_set (const std::vector< pending_tx > &ptx_vector) const
bool sign_tx (const std::string &unsigned_filename, const std::string &signed_filename, std::vector< wallet2::pending_tx > &ptx, std::function< bool(const unsigned_tx_set &)> accept_func=NULL, bool export_raw=false)
bool sign_tx (unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector< wallet2::pending_tx > &ptx, bool export_raw=false)
bool sign_tx (unsigned_tx_set &exported_txs, std::vector< wallet2::pending_tx > &ptx, signed_tx_set &signed_txs)
std::string sign_tx_dump_to_str (unsigned_tx_set &exported_txs, std::vector< wallet2::pending_tx > &ptx, signed_tx_set &signed_txes)
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< tools::wallet2::pending_tx > &ptx, std::function< bool(const signed_tx_set &)> accept_func=NULL)
bool parse_tx_from_str (const std::string &signed_tx_st, std::vector< tools::wallet2::pending_tx > &ptx, std::function< bool(const signed_tx_set &)> accept_func)
std::vector< wallet2::pending_txcreate_transactions_2 (std::vector< cryptonote::tx_destination_entry > dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector< uint8_t > &extra, uint32_t subaddr_account, std::set< uint32_t > subaddr_indices)
std::vector< wallet2::pending_txcreate_transactions_all (uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector< uint8_t > &extra, uint32_t subaddr_account, std::set< uint32_t > subaddr_indices, const bool migrate=false)
std::vector< wallet2::pending_txcreate_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, const uint64_t unlock_time, uint32_t priority, const std::vector< uint8_t > &extra)
std::vector< wallet2::pending_txcreate_transactions_from (const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector< size_t > unused_transfers_indices, std::vector< size_t > unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector< uint8_t > &extra, const uint8_t tx_version)
bool sanity_check (const std::vector< wallet2::pending_tx > &ptx_vector, std::vector< cryptonote::tx_destination_entry > dsts) const
void cold_tx_aux_import (const std::vector< pending_tx > &ptx, const std::vector< std::string > &tx_device_aux)
void cold_sign_tx (const std::vector< pending_tx > &ptx_vector, signed_tx_set &exported_txs, std::vector< cryptonote::address_parse_info > &dsts_info, std::vector< std::string > &tx_device_aux)
uint64_t cold_key_image_sync (uint64_t &spent, uint64_t &unspent)
bool parse_multisig_tx_from_str (std::string multisig_tx_st, multisig_tx_set &exported_txs) const
bool load_multisig_tx (cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function< bool(const multisig_tx_set &)> accept_func=NULL)
bool load_multisig_tx_from_file (const std::string &filename, multisig_tx_set &exported_txs, std::function< bool(const multisig_tx_set &)> accept_func=NULL)
bool sign_multisig_tx_from_file (const std::string &filename, std::vector< crypto::hash > &txids, std::function< bool(const multisig_tx_set &)> accept_func)
bool sign_multisig_tx (multisig_tx_set &exported_txs, std::vector< crypto::hash > &txids)
bool sign_multisig_tx_to_file (multisig_tx_set &exported_txs, const std::string &filename, std::vector< crypto::hash > &txids)
std::vector< pending_txcreate_unmixable_sweep_transactions ()
void discard_unmixable_outputs ()
bool check_connection (uint32_t *version=NULL, bool *ssl=NULL, uint32_t timeout=200000)
void get_transfers (wallet2::transfer_container &incoming_transfers) const
void get_payments (const crypto::hash &payment_id, std::list< wallet2::payment_details > &payments, uint64_t min_height=0, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
void get_payments (std::list< std::pair< crypto::hash, wallet2::payment_details > > &payments, uint64_t min_height, uint64_t max_height=(uint64_t) -1, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
void get_payments_out (std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > &confirmed_payments, uint64_t min_height, uint64_t max_height=(uint64_t) -1, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
void get_payments_out_migration (std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > &confirmed_payments, uint64_t min_height, uint64_t max_height=(uint64_t) -1, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
void get_payments_out_sc_migration (std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > &confirmed_payments, uint64_t min_height, uint64_t max_height=(uint64_t) -1, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
void get_unconfirmed_payments_out (std::list< std::pair< crypto::hash, wallet2::unconfirmed_transfer_details > > &unconfirmed_payments, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
void get_unconfirmed_payments (std::list< std::pair< crypto::hash, wallet2::pool_payment_details > > &unconfirmed_payments, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
uint64_t get_blockchain_current_height () const
bool synced_to_v10 () const
bool public_transactions_required () const
void rescan_spent ()
void rescan_blockchain (bool hard, bool refresh=true, bool keep_key_images=false)
bool is_transfer_unlocked (const transfer_details &td) const
bool is_transfer_unlocked (uint64_t unlock_time, uint64_t block_height) const
uint64_t get_last_block_reward () const
uint64_t get_device_last_key_image_sync () const
template<class t_archive>
void serialize (t_archive &a, const unsigned int ver)
bool always_confirm_transfers () const
void always_confirm_transfers (bool always)
bool print_ring_members () const
void print_ring_members (bool value)
bool store_tx_info () const
void store_tx_info (bool store)
uint32_t default_mixin () const
void default_mixin (uint32_t m)
uint32_t get_default_priority () const
void set_default_priority (uint32_t p)
bool auto_refresh () const
void auto_refresh (bool r)
bool confirm_missing_payment_id () const
void confirm_missing_payment_id (bool always)
AskPasswordType ask_password () const
void ask_password (AskPasswordType ask)
void set_min_output_count (uint32_t count)
uint32_t get_min_output_count () const
void set_min_output_value (uint64_t value)
uint64_t get_min_output_value () const
void merge_destinations (bool merge)
bool merge_destinations () const
bool confirm_backlog () const
void confirm_backlog (bool always)
void set_confirm_backlog_threshold (uint32_t threshold)
uint32_t get_confirm_backlog_threshold () const
bool confirm_export_overwrite () const
void confirm_export_overwrite (bool always)
bool auto_low_priority () const
void auto_low_priority (bool value)
bool segregate_pre_fork_outputs () const
void segregate_pre_fork_outputs (bool value)
bool key_reuse_mitigation2 () const
void key_reuse_mitigation2 (bool value)
uint64_t segregation_height () const
void segregation_height (uint64_t height)
bool ignore_fractional_outputs () const
void ignore_fractional_outputs (bool value)
bool confirm_non_default_ring_size () const
void confirm_non_default_ring_size (bool always)
bool track_uses () const
void track_uses (bool value)
BackgroundMiningSetupType setup_background_mining () const
void setup_background_mining (BackgroundMiningSetupType value)
const std::string & device_name () const
void device_name (const std::string &device_name)
const std::string & device_derivation_path () const
void device_derivation_path (const std::string &device_derivation_path)
bool get_tx_key_cached (const crypto::hash &txid, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys) const
void set_tx_key (const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector< crypto::secret_key > &additional_tx_keys)
bool get_tx_key (const crypto::hash &txid, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys)
void check_tx_key (const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector< crypto::secret_key > &additional_tx_keys, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations)
void check_tx_key_helper (const crypto::hash &txid, const crypto::key_derivation &derivation, const std::vector< crypto::key_derivation > &additional_derivations, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations)
void check_tx_key_helper (const cryptonote::transaction &tx, const crypto::key_derivation &derivation, const std::vector< crypto::key_derivation > &additional_derivations, const cryptonote::account_public_address &address, uint64_t &received) const
std::string get_tx_proof (const crypto::hash &txid, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message)
std::string get_tx_proof (const cryptonote::transaction &tx, const crypto::secret_key &tx_key, const std::vector< crypto::secret_key > &additional_tx_keys, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message) const
bool check_tx_proof (const crypto::hash &txid, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received, bool &in_pool, uint64_t &confirmations)
bool check_tx_proof (const cryptonote::transaction &tx, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received) const
std::string get_spend_proof (const crypto::hash &txid, const std::string &message)
bool check_spend_proof (const crypto::hash &txid, const std::string &message, const std::string &sig_str)
std::string get_reserve_proof (const boost::optional< std::pair< uint32_t, uint64_t > > &account_minreserve, const std::string &message)
 Generates a proof that proves the reserve of unspent funds.
bool check_reserve_proof (const cryptonote::account_public_address &address, const std::string &message, const std::string &sig_str, uint64_t &total, uint64_t &spent)
 Verifies a proof of reserve.
std::vector< address_book_rowget_address_book () const
 GUI Address book get/store.
bool add_address_book_row (const cryptonote::account_public_address &address, const crypto::hash &payment_id, const std::string &description, bool is_subaddress)
bool delete_address_book_row (std::size_t row_id)
uint64_t get_num_rct_outputs ()
size_t get_num_transfer_details () const
const transfer_detailsget_transfer_details (size_t idx) const
void get_hard_fork_info (uint8_t version, uint64_t &earliest_height) const
bool use_fork_rules (uint8_t version, int64_t early_blocks=0) const
int get_fee_algorithm () const
std::string get_wallet_file () const
std::string get_keys_file () const
std::string get_daemon_address () const
const boost::optional< epee::net_utils::http::login > & get_daemon_login () const
uint64_t get_daemon_blockchain_height (std::string &err) const
uint64_t get_daemon_blockchain_target_height (std::string &err)
uint64_t get_approximate_blockchain_height () const
 Calculates the approximate blockchain height from current date/time.
uint64_t estimate_blockchain_height ()
std::vector< size_t > select_available_outputs_from_histogram (uint64_t count, bool atleast, bool unlocked, bool allow_rct)
std::vector< size_t > select_available_outputs (const std::function< bool(const transfer_details &td)> &f) const
std::vector< size_t > select_available_unmixable_outputs ()
std::vector< size_t > select_available_mixable_outputs ()
size_t pop_best_value_from (const transfer_container &transfers, std::vector< size_t > &unused_dust_indices, const std::vector< size_t > &selected_transfers, bool smallest=false) const
size_t pop_best_value (std::vector< size_t > &unused_dust_indices, const std::vector< size_t > &selected_transfers, bool smallest=false) const
void set_tx_note (const crypto::hash &txid, const std::string &note)
std::string get_tx_note (const crypto::hash &txid) const
void set_tx_device_aux (const crypto::hash &txid, const std::string &aux)
std::string get_tx_device_aux (const crypto::hash &txid) const
void set_description (const std::string &description)
std::string get_description () const
const std::pair< std::map< std::string, std::string >, std::vector< std::string > > & get_account_tags ()
 Get the list of registered account tags.
void set_account_tag (const std::set< uint32_t > &account_indices, const std::string &tag)
 Set a tag to the given accounts.
void set_account_tag_description (const std::string &tag, const std::string &description)
 Set the label of the given tag.
std::string sign (const std::string &data) const
bool verify (const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const
std::string sign_multisig_participant (const std::string &data) const
 sign_multisig_participant signs given message with the multisig public signer key
bool verify_with_public_key (const std::string &data, const crypto::public_key &public_key, const std::string &signature) const
 verify_with_public_key verifies message was signed with given public key
std::pair< size_t, std::vector< tools::wallet2::transfer_details > > export_outputs (bool all=false) const
std::string export_outputs_to_str (bool all=false) const
size_t import_outputs (const std::pair< size_t, std::vector< tools::wallet2::transfer_details > > &outputs)
size_t import_outputs_from_str (const std::string &outputs_st)
payment_container export_payments () const
void import_payments (const payment_container &payments)
void import_payments_out (const std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > &confirmed_payments)
std::tuple< size_t, crypto::hash, std::vector< crypto::hash > > export_blockchain () const
void import_blockchain (const std::tuple< size_t, crypto::hash, std::vector< crypto::hash > > &bc)
bool export_key_images (const std::string &filename) const
std::pair< size_t, std::vector< std::pair< crypto::key_image, crypto::signature > > > export_key_images (bool all=false) const
uint64_t import_key_images (const std::vector< std::pair< crypto::key_image, crypto::signature > > &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent=true)
uint64_t import_key_images (const std::string &filename, uint64_t &spent, uint64_t &unspent)
bool import_key_images (std::vector< crypto::key_image > key_images, size_t offset=0, boost::optional< std::unordered_set< size_t > > selected_transfers=boost::none)
bool import_key_images (signed_tx_set &signed_tx, size_t offset=0, bool only_selected_transfers=false)
crypto::public_key get_tx_pub_key_from_received_outs (const tools::wallet2::transfer_details &td) const
void update_pool_state (bool refreshed=false)
void remove_obsolete_pool_txs (const std::vector< crypto::hash > &tx_hashes)
std::string encrypt (const char *plaintext, size_t len, const crypto::secret_key &skey, bool authenticated=true) const
std::string encrypt (const epee::span< char > &span, const crypto::secret_key &skey, bool authenticated=true) const
std::string encrypt (const std::string &plaintext, const crypto::secret_key &skey, bool authenticated=true) const
std::string encrypt (const epee::wipeable_string &plaintext, const crypto::secret_key &skey, bool authenticated=true) const
std::string encrypt_with_view_secret_key (const std::string &plaintext, bool authenticated=true) const
template<typename T = std::string>
T decrypt (const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated=true) const
std::string decrypt_with_view_secret_key (const std::string &ciphertext, bool authenticated=true) const
std::string make_uri (const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const
bool parse_uri (const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector< std::string > &unknown_parameters, std::string &error)
uint64_t get_blockchain_height_by_date (uint16_t year, uint8_t month, uint8_t day)
bool is_synced () const
std::vector< std::pair< uint64_t, uint64_t > > estimate_backlog (const std::vector< std::pair< double, double > > &fee_levels)
std::vector< std::pair< uint64_t, uint64_t > > estimate_backlog (uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector< uint64_t > &fees)
uint64_t get_fee_multiplier (uint32_t priority, int fee_algorithm=-1) const
uint64_t get_base_fee () const
uint64_t get_fee_quantization_mask () const
uint64_t get_min_ring_size () const
uint64_t get_max_ring_size () const
uint64_t adjust_mixin (uint64_t mixin) const
uint32_t adjust_priority (uint32_t priority)
bool is_unattended () const
void light_wallet_get_unspent_outs ()
void light_wallet_get_address_txs ()
bool light_wallet_get_address_info (tools::COMMAND_RPC_GET_ADDRESS_INFO::response &response)
bool light_wallet_login (bool &new_address)
bool light_wallet_import_wallet_request (tools::COMMAND_RPC_IMPORT_WALLET_REQUEST::response &response)
void light_wallet_get_outs (std::vector< std::vector< get_outs_entry > > &outs, const std::vector< size_t > &selected_transfers, size_t fake_outputs_count)
bool light_wallet_parse_rct_str (const std::string &rct_string, const crypto::public_key &tx_pub_key, uint64_t internal_output_index, rct::key &decrypted_mask, rct::key &rct_commit, bool decrypt) const
bool light_wallet_key_image_is_ours (const crypto::key_image &key_image, const crypto::public_key &tx_public_key, uint64_t out_index)
void set_attribute (const std::string &key, const std::string &value)
std::string get_attribute (const std::string &key) const
crypto::public_key get_multisig_signer_public_key (const crypto::secret_key &spend_skey) const
crypto::public_key get_multisig_signer_public_key () const
crypto::public_key get_multisig_signing_public_key (size_t idx) const
crypto::public_key get_multisig_signing_public_key (const crypto::secret_key &skey) const
template<class t_request, class t_response>
bool invoke_http_json (const boost::string_ref uri, const t_request &req, t_response &res, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET")
template<class t_request, class t_response>
bool invoke_http_bin (const boost::string_ref uri, const t_request &req, t_response &res, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET")
template<class t_request, class t_response>
bool invoke_http_json_rpc (const boost::string_ref uri, const std::string &method_name, const t_request &req, t_response &res, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET", const std::string &req_id="0")
bool set_ring_database (const std::string &filename)
const std::string get_ring_database () const
bool get_ring (const crypto::key_image &key_image, std::vector< uint64_t > &outs)
bool get_rings (const crypto::hash &txid, std::vector< std::pair< crypto::key_image, std::vector< uint64_t > > > &outs)
bool set_ring (const crypto::key_image &key_image, const std::vector< uint64_t > &outs, bool relative)
bool unset_ring (const std::vector< crypto::key_image > &key_images)
bool unset_ring (const crypto::hash &txid)
bool find_and_save_rings (bool force=true)
bool blackball_output (const std::pair< uint64_t, uint64_t > &output)
bool set_blackballed_outputs (const std::vector< std::pair< uint64_t, uint64_t > > &outputs, bool add=false)
bool unblackball_output (const std::pair< uint64_t, uint64_t > &output)
bool is_output_blackballed (const std::pair< uint64_t, uint64_t > &output) const
void freeze (size_t idx)
void thaw (size_t idx)
bool frozen (size_t idx) const
void freeze (const crypto::key_image &ki)
void thaw (const crypto::key_image &ki)
bool frozen (const crypto::key_image &ki) const
bool frozen (const transfer_details &td) const
uint64_t get_bytes_sent () const
uint64_t get_bytes_received () const
void add_checkpoint (uint64_t height, std::string hash)
mms::message_storeget_message_store ()
const mms::message_storeget_message_store () const
mms::multisig_wallet_state get_multisig_wallet_state () const
bool lock_keys_file ()
bool unlock_keys_file ()
bool is_keys_file_locked () const
void change_password (const std::string &filename, const epee::wipeable_string &original_password, const epee::wipeable_string &new_password)
void set_tx_notify (const std::shared_ptr< tools::Notify > &notify)
bool is_tx_spendtime_unlocked (uint64_t unlock_time, uint64_t block_height) const
void hash_m_transfer (const transfer_details &transfer, crypto::hash &hash) const
uint64_t hash_m_transfers (int64_t transfer_height, crypto::hash &hash) const
void finish_rescan_bc_keep_key_images (uint64_t transfer_height, const crypto::hash &hash)
void enable_dns (bool enable)
void set_offline (bool offline=true)
template<typename T>
T decrypt (const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated) const

Static Public Member Functions

static const char * tr (const char *str)
static bool has_testnet_option (const boost::program_options::variables_map &vm)
static bool has_stagenet_option (const boost::program_options::variables_map &vm)
static std::string device_name_option (const boost::program_options::variables_map &vm)
static std::string device_derivation_path_option (const boost::program_options::variables_map &vm)
static void init_options (boost::program_options::options_description &desc_params)
static std::pair< std::unique_ptr< wallet2 >, password_containermake_from_json (const boost::program_options::variables_map &vm, bool unattended, const std::string &json_file, const std::function< boost::optional< password_container >(const char *, bool)> &password_prompter)
 Uses stdin and stdout. Returns a wallet2 if no errors.
static std::pair< std::unique_ptr< wallet2 >, password_containermake_from_file (const boost::program_options::variables_map &vm, bool unattended, const std::string &wallet_file, const std::function< boost::optional< password_container >(const char *, bool)> &password_prompter)
 Uses stdin and stdout. Returns a wallet2 and password for wallet_file if no errors.
static std::pair< std::unique_ptr< wallet2 >, password_containermake_new (const boost::program_options::variables_map &vm, bool unattended, const std::function< boost::optional< password_container >(const char *, bool)> &password_prompter)
 Uses stdin and stdout. Returns a wallet2 and password for wallet with no file if no errors.
static std::unique_ptr< wallet2make_dummy (const boost::program_options::variables_map &vm, bool unattended, const std::function< boost::optional< password_container >(const char *, bool)> &password_prompter)
 Just parses variables.
static bool verify_password (const std::string &keys_file_name, const epee::wipeable_string &password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds)
 verify password for specified wallet keys file.
static bool query_device (hw::device::device_type &device_type, const std::string &keys_file_name, const epee::wipeable_string &password, uint64_t kdf_rounds=1)
 determine the key storage for the specified wallet file
static bool verify_multisig_info (const std::string &data, crypto::secret_key &skey, crypto::public_key &pkey)
static bool verify_extra_multisig_info (const std::string &data, std::unordered_set< crypto::public_key > &pkeys, crypto::public_key &signer)
static void wallet_exists (const std::string &file_path, bool &keys_file_exists, bool &wallet_file_exists)
 Check if wallet keys and bin files exist.
static std::string get_human_readable_timestamp (uint64_t ts)
 Check if wallet file path is valid format.
static bool wallet_valid_path_format (const std::string &file_path)
static bool parse_long_payment_id (const std::string &payment_id_str, crypto::hash &payment_id)
static bool parse_short_payment_id (const std::string &payment_id_str, crypto::hash8 &payment_id)
static bool parse_payment_id (const std::string &payment_id_str, crypto::hash &payment_id)

Public Attributes

const char *const ATTRIBUTE_DESCRIPTION = "wallet2.description"

Static Public Attributes

static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30)

Friends

class ::Serialization_portability_wallet_Test
class ::wallet_accessor_test
class wallet_keys_unlocker
class wallet_device_callback

Detailed Description

Definition at line 209 of file wallet2.h.

Member Typedef Documentation

◆ get_outs_entry

Definition at line 562 of file wallet2.h.

◆ payment_container

Definition at line 450 of file wallet2.h.

◆ transfer_container

Definition at line 449 of file wallet2.h.

Member Enumeration Documentation

◆ AskPasswordType

Enumerator
AskPasswordNever 
AskPasswordOnAction 
AskPasswordToDecrypt 

Definition at line 225 of file wallet2.h.

225 {
229 };
@ AskPasswordToDecrypt
Definition wallet2.h:228
@ AskPasswordOnAction
Definition wallet2.h:227

◆ BackgroundMiningSetupType

Enumerator
BackgroundMiningMaybe 
BackgroundMiningYes 
BackgroundMiningNo 

Definition at line 231 of file wallet2.h.

231 {
235 };
@ BackgroundMiningMaybe
Definition wallet2.h:232
@ BackgroundMiningYes
Definition wallet2.h:233

◆ RefreshType

Enumerator
RefreshFull 
RefreshOptimizeCoinbase 
RefreshNoCoinbase 
RefreshDefault 

Definition at line 218 of file wallet2.h.

Constructor & Destructor Documentation

◆ wallet2()

tools::wallet2::wallet2 ( cryptonote::network_type nettype = cryptonote::MAINNET,
uint64_t kdf_rounds = 1,
bool unattended = false )

Definition at line 1102 of file wallet2.cpp.

1102 :
1103 m_multisig_rescan_info(NULL),
1104 m_multisig_rescan_k(NULL),
1105 m_upper_transaction_weight_limit(0),
1106 m_run(true),
1107 m_callback(0),
1108 m_trusted_daemon(false),
1109 m_nettype(nettype),
1110 m_multisig_rounds_passed(0),
1111 m_always_confirm_transfers(true),
1112 m_print_ring_members(false),
1113 m_store_tx_info(true),
1114 m_default_mixin(0),
1115 m_default_priority(0),
1116 m_refresh_type(RefreshOptimizeCoinbase),
1117 m_auto_refresh(true),
1118 m_first_refresh_done(false),
1119 m_refresh_from_block_height(0),
1120 m_explicit_refresh_from_block_height(true),
1121 m_confirm_missing_payment_id(true),
1122 m_confirm_non_default_ring_size(true),
1123 m_ask_password(AskPasswordOnAction),
1124 m_min_output_count(0),
1125 m_min_output_value(0),
1126 m_merge_destinations(false),
1127 m_confirm_backlog(true),
1128 m_confirm_backlog_threshold(0),
1129 m_confirm_export_overwrite(true),
1130 m_auto_low_priority(true),
1131 m_segregate_pre_fork_outputs(true),
1132 m_key_reuse_mitigation2(true),
1133 m_segregation_height(0),
1134 m_ignore_fractional_outputs(true),
1135 m_track_uses(false),
1136 m_setup_background_mining(BackgroundMiningMaybe),
1137 m_is_initialized(false),
1138 m_kdf_rounds(kdf_rounds),
1139 is_old_file_format(false),
1140 m_watch_only(false),
1141 m_multisig(false),
1142 m_multisig_threshold(0),
1143 m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex),
1144 m_account_public_address{crypto::null_pkey, crypto::null_pkey},
1145 m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR),
1146 m_subaddress_lookahead_minor(SUBADDRESS_LOOKAHEAD_MINOR),
1147 m_light_wallet(false),
1148 m_light_wallet_scanned_block_height(0),
1149 m_light_wallet_blockchain_height(0),
1150 m_light_wallet_connected(false),
1151 m_light_wallet_balance(0),
1152 m_light_wallet_unlocked_balance(0),
1153 m_original_keys_available(false),
1154 m_message_store(),
1155 m_key_device_type(hw::device::device_type::SOFTWARE),
1156 m_ring_history_saved(false),
1157 m_ringdb(),
1158 m_last_block_reward(0),
1159 m_encrypt_keys_after_refresh(boost::none),
1160 m_unattended(unattended),
1161 m_devices_registered(false),
1162 m_device_last_key_image_sync(0),
1163 m_use_dns(true),
1164 m_offline(false),
1165 m_account_major_offset(0)
1166{
1167}
cryptonote::network_type nettype() const
Definition wallet2.h:824
const crypto::public_key null_pkey
Definition crypto.cpp:72
#define SUBADDRESS_LOOKAHEAD_MAJOR
Definition wallet2.cpp:120
#define SUBADDRESS_LOOKAHEAD_MINOR
Definition wallet2.cpp:121
Here is the call graph for this function:

◆ ~wallet2()

tools::wallet2::~wallet2 ( )

Definition at line 1169 of file wallet2.cpp.

1170{
1171}

Member Function Documentation

◆ account_major_offset() [1/2]

uint32_t tools::wallet2::account_major_offset ( ) const
inline

Definition at line 811 of file wallet2.h.

811{return m_account_major_offset;}

◆ account_major_offset() [2/2]

void tools::wallet2::account_major_offset ( uint32_t offset)
inline

Definition at line 810 of file wallet2.h.

810{m_account_major_offset = offset;}

◆ add_address_book_row()

bool tools::wallet2::add_address_book_row ( const cryptonote::account_public_address & address,
const crypto::hash & payment_id,
const std::string & description,
bool is_subaddress )

Definition at line 3451 of file wallet2.cpp.

3452{
3453 wallet2::address_book_row a;
3454 a.m_address = address;
3455 a.m_payment_id = payment_id;
3456 a.m_description = description;
3457 a.m_is_subaddress = is_subaddress;
3458
3459 auto old_size = m_address_book.size();
3460 m_address_book.push_back(a);
3461 if(m_address_book.size() == old_size+1)
3462 return true;
3463 return false;
3464}
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1124
const char * address
Definition multisig.cpp:37
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_checkpoint()

void tools::wallet2::add_checkpoint ( uint64_t height,
std::string hash )

Definition at line 13766 of file wallet2.cpp.

13766 {
13767 m_checkpoints.add_checkpoint(height, hash);
13768}
uint64_t height
POD_CLASS hash
Definition hash.h:50
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_subaddress()

void tools::wallet2::add_subaddress ( uint32_t index_major,
const std::string & label )

Definition at line 1470 of file wallet2.cpp.

1471{
1472 THROW_WALLET_EXCEPTION_IF(index_major >= m_subaddress_labels.size(), error::account_index_outofbound);
1473 uint32_t index_minor = (uint32_t)get_num_subaddresses(index_major);
1474 expand_subaddresses({index_major, index_minor});
1475 m_subaddress_labels[index_major][index_minor] = label;
1476}
void expand_subaddresses(const cryptonote::subaddress_index &index, const bool udpate_account_tags=true)
Definition wallet2.cpp:1478
size_t get_num_subaddresses(uint32_t index_major) const
Definition wallet2.h:802
unsigned int uint32_t
Definition stdint.h:126
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
Here is the call graph for this function:

◆ add_subaddress_account()

void tools::wallet2::add_subaddress_account ( const std::string & label,
const bool update_account_tags = true )

Definition at line 1463 of file wallet2.cpp.

1464{
1466 expand_subaddresses({index_major, 0}, update_account_tags);
1467 m_subaddress_labels[index_major][0] = label;
1468}
size_t get_num_subaddress_accounts() const
Definition wallet2.h:801
Here is the call graph for this function:
Here is the caller graph for this function:

◆ adjust_mixin()

uint64_t tools::wallet2::adjust_mixin ( uint64_t mixin) const

Definition at line 7860 of file wallet2.cpp.

7861{
7862 const uint64_t min_ring_size = get_min_ring_size();
7863 if (mixin + 1 < min_ring_size)
7864 {
7865 MWARNING("Requested ring size " << (mixin + 1) << " too low, using " << min_ring_size);
7866 mixin = min_ring_size-1;
7867 }
7868 const uint64_t max_ring_size = get_max_ring_size();
7869 if (max_ring_size && mixin + 1 > max_ring_size)
7870 {
7871 MWARNING("Requested ring size " << (mixin + 1) << " too high, using " << max_ring_size);
7872 mixin = max_ring_size-1;
7873 }
7874 return mixin;
7875}
uint64_t get_max_ring_size() const
Definition wallet2.cpp:7851
uint64_t get_min_ring_size() const
Definition wallet2.cpp:7836
#define MWARNING(x)
Definition misc_log_ex.h:74
unsigned __int64 uint64_t
Definition stdint.h:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ adjust_priority()

uint32_t tools::wallet2::adjust_priority ( uint32_t priority)

Definition at line 7877 of file wallet2.cpp.

7878{
7879 // just return 1 for normal priority for aurelius instead of being concerned with backlog and adjusting priority because fees are 0 for everyone
7880 return 1;
7881
7882 if (priority == 0 && m_default_priority == 0 && auto_low_priority())
7883 {
7884 try
7885 {
7886 // check if there's a backlog in the tx pool
7887 const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
7888 const uint64_t base_fee = get_base_fee();
7889 const uint64_t fee_multiplier = get_fee_multiplier(1);
7890 const double fee_level = fee_multiplier * base_fee * (use_per_byte_fee ? 1 : (12/(double)13 / (double)1024));
7891 const std::vector<std::pair<uint64_t, uint64_t>> blocks = estimate_backlog({std::make_pair(fee_level, fee_level)});
7892 if (blocks.size() != 1)
7893 {
7894 MERROR("Bad estimated backlog array size");
7895 return priority;
7896 }
7897 else if (blocks[0].first > 0)
7898 {
7899 MINFO("We don't use the low priority because there's a backlog in the tx pool.");
7900 return priority;
7901 }
7902
7903 // get the current full reward zone
7904 uint64_t block_weight_limit = 0;
7905 const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
7906 throw_on_rpc_response_error(result, "get_info");
7907 const uint64_t full_reward_zone = block_weight_limit / 2;
7908
7909 // get the last N block headers and sum the block sizes
7910 const size_t N = 10;
7911 if (m_blockchain.size() < N)
7912 {
7913 MERROR("The blockchain is too short");
7914 return priority;
7915 }
7918 m_daemon_rpc_mutex.lock();
7919 getbh_req.start_height = m_blockchain.size() - N;
7920 getbh_req.end_height = m_blockchain.size() - 1;
7921 bool r = invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, rpc_timeout);
7922 m_daemon_rpc_mutex.unlock();
7923 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange");
7924 THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange");
7925 THROW_WALLET_EXCEPTION_IF(getbh_res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, get_rpc_status(getbh_res.status));
7926 if (getbh_res.headers.size() != N)
7927 {
7928 MERROR("Bad blockheaders size");
7929 return priority;
7930 }
7931 size_t block_weight_sum = 0;
7932 for (const cryptonote::block_header_response &i : getbh_res.headers)
7933 {
7934 block_weight_sum += i.block_weight;
7935 }
7936
7937 // estimate how 'full' the last N blocks are
7938 const size_t P = 100 * block_weight_sum / (N * full_reward_zone);
7939 MINFO((boost::format("The last %d blocks fill roughly %d%% of the full reward zone.") % N % P).str());
7940 if (P > 80)
7941 {
7942 MINFO("We don't use the low priority because recent blocks are quite full.");
7943 return priority;
7944 }
7945 MINFO("We'll use the low priority because probably it's safe to do so.");
7946 return 1;
7947 }
7948 catch (const std::exception &e)
7949 {
7950 MERROR(e.what());
7951 }
7952 }
7953 return priority;
7954}
uint64_t get_base_fee() const
Definition wallet2.cpp:7785
uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm=-1) const
Definition wallet2.cpp:7732
bool use_fork_rules(uint8_t version, int64_t early_blocks=0) const
std::vector< std::pair< uint64_t, uint64_t > > estimate_backlog(const std::vector< std::pair< double, double > > &fee_levels)
bool auto_low_priority() const
Definition wallet2.h:1093
static constexpr const std::chrono::seconds rpc_timeout
Definition wallet2.h:216
bool invoke_http_json_rpc(const boost::string_ref uri, const std::string &method_name, const t_request &req, t_response &res, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET", const std::string &req_id="0")
Definition wallet2.h:1333
#define CORE_RPC_STATUS_OK
#define CORE_RPC_STATUS_BUSY
#define HF_VERSION_PER_BYTE_FEE
#define AUTO_VAL_INIT(v)
#define MERROR(x)
Definition misc_log_ex.h:73
#define MINFO(x)
Definition misc_log_ex.h:75
failed_rpc_request< refresh_error, get_blocks_error_message_index > get_blocks_error
epee::misc_utils::struct_init< response_t > response
Here is the call graph for this function:
Here is the caller graph for this function:

◆ always_confirm_transfers() [1/2]

bool tools::wallet2::always_confirm_transfers ( ) const
inline

Definition at line 1065 of file wallet2.h.

1065{ return m_always_confirm_transfers; }

◆ always_confirm_transfers() [2/2]

void tools::wallet2::always_confirm_transfers ( bool always)
inline

Definition at line 1066 of file wallet2.h.

1066{ m_always_confirm_transfers = always; }

◆ ask_password() [1/2]

AskPasswordType tools::wallet2::ask_password ( ) const
inline

Definition at line 1079 of file wallet2.h.

1079{ return m_ask_password; }

◆ ask_password() [2/2]

void tools::wallet2::ask_password ( AskPasswordType ask)
inline

Definition at line 1080 of file wallet2.h.

1080{ m_ask_password = ask; }

◆ auto_low_priority() [1/2]

bool tools::wallet2::auto_low_priority ( ) const
inline

Definition at line 1093 of file wallet2.h.

1093{ return m_auto_low_priority; }
Here is the caller graph for this function:

◆ auto_low_priority() [2/2]

void tools::wallet2::auto_low_priority ( bool value)
inline

Definition at line 1094 of file wallet2.h.

1094{ m_auto_low_priority = value; }
const GenericPointer< typename T::ValueType > T2 value
Definition pointer.h:1225

◆ auto_refresh() [1/2]

bool tools::wallet2::auto_refresh ( ) const
inline

Definition at line 1075 of file wallet2.h.

1075{ return m_auto_refresh; }

◆ auto_refresh() [2/2]

void tools::wallet2::auto_refresh ( bool r)
inline

Definition at line 1076 of file wallet2.h.

1076{ m_auto_refresh = r; }

◆ balance()

uint64_t tools::wallet2::balance ( uint32_t subaddr_index_major,
bool public_blockchain ) const

Definition at line 6162 of file wallet2.cpp.

6163{
6164 uint64_t amount = 0;
6165 if(m_light_wallet)
6166 return m_light_wallet_unlocked_balance;
6167 for (const auto& i : balance_per_subaddress(index_major, public_blockchain))
6168 amount += i.second;
6169 return amount;
6170}
std::map< uint32_t, uint64_t > balance_per_subaddress(uint32_t subaddr_index_major, bool public_blockchain=false) const
Definition wallet2.cpp:6188
Here is the call graph for this function:
Here is the caller graph for this function:

◆ balance_all()

uint64_t tools::wallet2::balance_all ( bool public_blockchain) const

Definition at line 6292 of file wallet2.cpp.

6293{
6294 uint64_t r = 0;
6295 for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
6296 r += balance(index_major, public_blockchain);
6297 return r;
6298}
uint64_t balance(uint32_t subaddr_index_major, bool public_blockchain) const
Definition wallet2.cpp:6162
Here is the call graph for this function:
Here is the caller graph for this function:

◆ balance_per_subaddress()

std::map< uint32_t, uint64_t > tools::wallet2::balance_per_subaddress ( uint32_t subaddr_index_major,
bool public_blockchain = false ) const

Definition at line 6188 of file wallet2.cpp.

6189{
6190 std::map<uint32_t, uint64_t> amount_per_subaddr;
6191 for (const auto& td: m_transfers)
6192 {
6193 if((public_blockchain && td.m_tx.version == 1) || (!public_blockchain && td.m_tx.version > 1))
6194 continue;
6195
6196 if (td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
6197 {
6198 auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
6199 if (found == amount_per_subaddr.end())
6200 amount_per_subaddr[td.m_subaddr_index.minor] = td.amount();
6201 else
6202 found->second += td.amount();
6203 }
6204 }
6205 for (const auto& utx: m_unconfirmed_txs) {
6206 if ((public_blockchain && utx.second.m_tx.version == 1) || (!public_blockchain && utx.second.m_tx.version > 1))
6207 continue;
6208
6209 if (utx.second.m_state != wallet2::unconfirmed_transfer_details::failed) {
6210 //HANDLE LOOPBACK OUTS INCLUDING CHANGE
6211 if(utx.second.m_tx.version > 1){
6212 for (const cryptonote::tx_out &out : utx.second.m_tx.vout) {
6213 if (out.target.type() == typeid(txout_to_key_public)) {
6214 // check whether this out is to one of our subaddresses
6215 auto target = boost::get<cryptonote::txout_to_key_public>(out.target);
6216 auto subaddr_found = m_subaddresses.find(target.address.m_spend_public_key);
6217 // if this out is to us
6218 // and the view key part of the destination matches that of our our subaddress,
6219 // and the major index of this subaddress corresponds to the current account we're getting balance for,
6220 // then add amount to balance
6221 if (subaddr_found != m_subaddresses.end() && get_subaddress(subaddr_found->second).m_view_public_key == target.address.m_view_public_key && subaddr_found->second.major == index_major) {
6222 auto found = amount_per_subaddr.find(subaddr_found->second.minor);
6223 if (found == amount_per_subaddr.end())
6224 amount_per_subaddr[subaddr_found->second.minor] = out.amount;
6225 else
6226 found->second += out.amount;
6227 } else {
6228 continue;
6229 }
6230 }
6231 }
6232 }
6233 // CHANGE HANDLING FOR V1 TX
6234 // (NB LOOPBACK OUTS APART FROM CHANGE AREN'T FACTORED INTO BAL WHILST TX IS UNCONFIRMED
6235 // and there is no need to fix this (monero) issue as we've migrated to a transparent chain)
6236 if (utx.second.m_tx.version == 1 && utx.second.m_subaddr_account == index_major) {
6237 // all changes go to 0-th subaddress (in the current subaddress account)
6238 auto found = amount_per_subaddr.find(0);
6239 if (found == amount_per_subaddr.end())
6240 amount_per_subaddr[0] = utx.second.m_change;
6241 else
6242 found->second += utx.second.m_change;
6243 }
6244 }
6245 }
6246 return amount_per_subaddr;
6247}
cryptonote::account_public_address get_subaddress(const cryptonote::subaddress_index &index) const
Definition wallet2.cpp:1430
Here is the call graph for this function:
Here is the caller graph for this function:

◆ blackball_output()

bool tools::wallet2::blackball_output ( const std::pair< uint64_t, uint64_t > & output)

Definition at line 8175 of file wallet2.cpp.

8176{
8177 if (!m_ringdb)
8178 return false;
8179 try { return m_ringdb->blackball(output); }
8180 catch (const std::exception &e) { return false; }
8181}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ callback() [1/2]

i_wallet2_callback * tools::wallet2::callback ( ) const
inline

Definition at line 762 of file wallet2.h.

762{ return m_callback; }
Here is the caller graph for this function:

◆ callback() [2/2]

void tools::wallet2::callback ( i_wallet2_callback * callback)
inline

Definition at line 763 of file wallet2.h.

763{ m_callback = callback; }
i_wallet2_callback * callback() const
Definition wallet2.h:762
Here is the call graph for this function:

◆ change_password()

void tools::wallet2::change_password ( const std::string & filename,
const epee::wipeable_string & original_password,
const epee::wipeable_string & new_password )

Definition at line 4320 of file wallet2.cpp.

4321{
4322 if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
4323 decrypt_keys(original_password);
4324 setup_keys(new_password);
4325 rewrite(filename, new_password);
4326 if (!filename.empty())
4327 store();
4328}
void decrypt_keys(const crypto::chacha_key &key)
Definition wallet2.cpp:4752
void rewrite(const std::string &wallet_name, const epee::wipeable_string &password)
Rewrites to the wallet file for wallet upgrade (doesn't generate key, assumes it's already there).
Definition wallet2.cpp:5670
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_connection()

bool tools::wallet2::check_connection ( uint32_t * version = NULL,
bool * ssl = NULL,
uint32_t timeout = 200000 )

Definition at line 5758 of file wallet2.cpp.

5759{
5760 THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
5761
5762 if (m_offline)
5763 {
5764 if (version)
5765 *version = 0;
5766 if (ssl)
5767 *ssl = false;
5768 return false;
5769 }
5770
5771 // TODO: Add light wallet version check.
5772 if(m_light_wallet) {
5773 if (version)
5774 *version = 0;
5775 if (ssl)
5776 *ssl = m_light_wallet_connected; // light wallet is always SSL
5777 return m_light_wallet_connected;
5778 }
5779
5780 {
5781 boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
5782 if(!m_http_client.is_connected(ssl))
5783 {
5784 m_node_rpc_proxy.invalidate();
5785 if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
5786 return false;
5787 if(!m_http_client.is_connected(ssl))
5788 return false;
5789 }
5790 }
5791
5792 if (version)
5793 {
5796 bool r = invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t);
5797 if(!r) {
5798 *version = 0;
5799 return false;
5800 }
5801 if (resp_t.status != CORE_RPC_STATUS_OK)
5802 *version = 0;
5803 else
5804 *version = resp_t.version;
5805 }
5806
5807 return true;
5808}
uint8_t version
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_reserve_proof()

bool tools::wallet2::check_reserve_proof ( const cryptonote::account_public_address & address,
const std::string & message,
const std::string & sig_str,
uint64_t & total,
uint64_t & spent )

Verifies a proof of reserve.

Parameters
addressThe signer's address
messageChallenge message used for signing
sig_strSignature string
total[OUT] the sum of funds included in the signature
spent[OUT] the sum of spent funds included in the signature
Returns
true if the signature verifies correctly

Definition at line 11790 of file wallet2.cpp.

11791{
11792 uint32_t rpc_version;
11793 THROW_WALLET_EXCEPTION_IF(!check_connection(&rpc_version), error::wallet_internal_error, "Failed to connect to daemon: " + get_daemon_address());
11794 THROW_WALLET_EXCEPTION_IF(rpc_version < MAKE_CORE_RPC_VERSION(1, 0), error::wallet_internal_error, "Daemon RPC version is too old");
11795
11796 static constexpr char header[] = "ReserveProofV1";
11797 THROW_WALLET_EXCEPTION_IF(!boost::string_ref{sig_str}.starts_with(header), error::wallet_internal_error,
11798 "Signature header check error");
11799
11800 std::string sig_decoded;
11801 THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(std::strlen(header)), sig_decoded), error::wallet_internal_error,
11802 "Signature decoding error");
11803
11804 std::istringstream iss(sig_decoded);
11805 boost::archive::portable_binary_iarchive ar(iss);
11806 std::vector<reserve_proof_entry> proofs;
11807 std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
11808 ar >> proofs >> subaddr_spendkeys;
11809
11810 THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(address.m_spend_public_key) == 0, error::wallet_internal_error,
11811 "The given address isn't found in the proof");
11812
11813 // compute signature prefix hash
11814 std::string prefix_data = message;
11815 prefix_data.append((const char*)&address, sizeof(cryptonote::account_public_address));
11816 for (size_t i = 0; i < proofs.size(); ++i)
11817 {
11818 prefix_data.append((const char*)&proofs[i].key_image, sizeof(crypto::key_image));
11819 }
11820 crypto::hash prefix_hash;
11821 crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11822
11823 // fetch txes from daemon
11826 for (size_t i = 0; i < proofs.size(); ++i)
11827 gettx_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(proofs[i].txid));
11828 gettx_req.decode_as_json = false;
11829 gettx_req.prune = true;
11830 m_daemon_rpc_mutex.lock();
11831 bool ok = invoke_http_json("/gettransactions", gettx_req, gettx_res, rpc_timeout);
11832 m_daemon_rpc_mutex.unlock();
11833 THROW_WALLET_EXCEPTION_IF(!ok || gettx_res.txs.size() != proofs.size(),
11834 error::wallet_internal_error, "Failed to get transaction from daemon");
11835
11836 // check spent status
11839 for (size_t i = 0; i < proofs.size(); ++i)
11840 kispent_req.key_images.push_back(epee::string_tools::pod_to_hex(proofs[i].key_image));
11841 m_daemon_rpc_mutex.lock();
11842 ok = invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, rpc_timeout);
11843 m_daemon_rpc_mutex.unlock();
11844 THROW_WALLET_EXCEPTION_IF(!ok || kispent_res.spent_status.size() != proofs.size(),
11845 error::wallet_internal_error, "Failed to get key image spent status from daemon");
11846
11847 total = spent = 0;
11848 for (size_t i = 0; i < proofs.size(); ++i)
11849 {
11850 const reserve_proof_entry& proof = proofs[i];
11851 THROW_WALLET_EXCEPTION_IF(gettx_res.txs[i].in_pool, error::wallet_internal_error, "Tx is unconfirmed");
11852
11853 cryptonote::transaction tx;
11854 crypto::hash tx_hash;
11855 ok = get_pruned_tx(gettx_res.txs[i], tx, tx_hash);
11856 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11857
11858 THROW_WALLET_EXCEPTION_IF(tx_hash != proof.txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
11859
11860 THROW_WALLET_EXCEPTION_IF(proof.index_in_tx >= tx.vout.size(), error::wallet_internal_error, "index_in_tx is out of bound");
11861
11862 const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[proof.index_in_tx].target));
11863 THROW_WALLET_EXCEPTION_IF(!out_key, error::wallet_internal_error, "Output key wasn't found")
11864
11865 // get tx pub key
11866 const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
11867 THROW_WALLET_EXCEPTION_IF(tx_pub_key == crypto::null_pkey, error::wallet_internal_error, "The tx public key isn't found");
11868 const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
11869
11870 // check singature for shared secret
11871 ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, proof.shared_secret, proof.shared_secret_sig);
11872 if (!ok && additional_tx_pub_keys.size() == tx.vout.size())
11873 ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[proof.index_in_tx], boost::none, proof.shared_secret, proof.shared_secret_sig);
11874 if (!ok)
11875 return false;
11876
11877 // check signature for key image
11878 const std::vector<const crypto::public_key*> pubs = { &out_key->key };
11879 ok = crypto::check_ring_signature(prefix_hash, proof.key_image, &pubs[0], 1, &proof.key_image_sig);
11880 if (!ok)
11881 return false;
11882
11883 // check if the address really received the fund
11884 crypto::key_derivation derivation;
11885 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(proof.shared_secret, rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
11886 crypto::public_key subaddr_spendkey;
11887 crypto::derive_subaddress_public_key(out_key->key, derivation, proof.index_in_tx, subaddr_spendkey);
11888 THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(subaddr_spendkey) == 0, error::wallet_internal_error,
11889 "The address doesn't seem to have received the fund");
11890
11891 // check amount
11892 uint64_t amount = tx.vout[proof.index_in_tx].amount;
11893 if (amount == 0)
11894 {
11895 // decode rct
11896 crypto::secret_key shared_secret;
11897 crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
11898 rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
11899 rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2);
11900 amount = rct::h2d(ecdh_info.amount);
11901 }
11902 total += amount;
11903 if (kispent_res.spent_status[i])
11904 spent += amount;
11905 }
11906
11907 // check signatures for all subaddress spend keys
11908 for (const auto &i : subaddr_spendkeys)
11909 {
11910 if (!crypto::check_signature(prefix_hash, i.first, i.second))
11911 return false;
11912 }
11913 return true;
11914}
else if(0==res)
bool invoke_http_json(const boost::string_ref uri, const t_request &req, t_response &res, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET")
Definition wallet2.h:1319
bool check_connection(uint32_t *version=NULL, bool *ssl=NULL, uint32_t timeout=200000)
Definition wallet2.cpp:5758
std::string get_daemon_address() const
bool check_tx_proof(const crypto::hash &txid, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received, bool &in_pool, uint64_t &confirmations)
#define MAKE_CORE_RPC_VERSION(major, minor)
std::string message("Message requiring signing")
epee::mlocked< tools::scrubbed< ec_scalar > > secret_key
Definition crypto.h:82
void cn_fast_hash(const void *data, size_t length, char *hash)
bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &result)
Definition crypto.h:286
POD_CLASS key_derivation
Definition crypto.h:101
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
Definition crypto.h:272
POD_CLASS public_key
Definition crypto.h:79
POD_CLASS key_image
Definition crypto.h:105
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig)
Definition crypto.h:295
void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res)
Definition crypto.h:279
bool check_ring_signature(const hash &prefix_hash, const key_image &image, const public_key *const *pubs, std::size_t pubs_count, const signature *sig)
Definition crypto.h:333
std::vector< crypto::public_key > get_additional_tx_pub_keys_from_extra(const std::vector< uint8_t > &tx_extra)
crypto::public_key get_tx_pub_key_from_extra(const std::vector< uint8_t > &tx_extra, size_t pk_index)
std::string pod_to_hex(const t_pod_type &s)
etn_amount h2d(const key &test)
Definition rctTypes.cpp:161
@ RCTTypeBulletproof2
Definition rctTypes.h:233
void ecdhDecode(ecdhTuple &masked, const key &sharedSec, bool v2)
Definition rctOps.cpp:712
bool decode(const std::string &enc, std::string &data)
Definition base58.cpp:196
#define false
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
std::vector< ecdhTuple > ecdhInfo
Definition rctTypes.h:246
Definition wallet2.h:553
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_spend_proof()

bool tools::wallet2::check_spend_proof ( const crypto::hash & txid,
const std::string & message,
const std::string & sig_str )

Definition at line 11163 of file wallet2.cpp.

11164{
11165 const std::string header = "SpendProofV1";
11166 const size_t header_len = header.size();
11167 THROW_WALLET_EXCEPTION_IF(sig_str.size() < header_len || sig_str.substr(0, header_len) != header, error::wallet_internal_error,
11168 "Signature header check error");
11169
11170 // fetch tx from daemon
11172 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11173 req.decode_as_json = false;
11174 req.prune = true;
11176 bool r;
11177 {
11178 const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
11179 r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11180 }
11181 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
11182 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
11183 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
11184 THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
11185 "daemon returned wrong response for gettransactions, wrong txs count = " +
11186 std::to_string(res.txs.size()) + ", expected 1");
11187
11188 cryptonote::transaction tx;
11189 crypto::hash tx_hash;
11190 THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(res.txs[0], tx, tx_hash), error::wallet_internal_error, "failed to get tx from daemon");
11191
11192 // check signature size
11193 size_t num_sigs = 0;
11194 for(size_t i = 0; i < tx.vin.size(); ++i)
11195 {
11196 const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
11197 if (in_key != nullptr)
11198 num_sigs += in_key->key_offsets.size();
11199 }
11200 std::vector<std::vector<crypto::signature>> signatures = { std::vector<crypto::signature>(1) };
11201 const size_t sig_len = tools::base58::encode(std::string((const char *)&signatures[0][0], sizeof(crypto::signature))).size();
11202 if( sig_str.size() != header_len + num_sigs * sig_len ) {
11203 return false;
11204 }
11205
11206 // decode base58
11207 signatures.clear();
11208 size_t offset = header_len;
11209 for(size_t i = 0; i < tx.vin.size(); ++i)
11210 {
11211 const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
11212 if (in_key == nullptr)
11213 continue;
11214 signatures.resize(signatures.size() + 1);
11215 signatures.back().resize(in_key->key_offsets.size());
11216 for (size_t j = 0; j < in_key->key_offsets.size(); ++j)
11217 {
11218 std::string sig_decoded;
11219 THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(offset, sig_len), sig_decoded), error::wallet_internal_error, "Signature decoding error");
11220 THROW_WALLET_EXCEPTION_IF(sizeof(crypto::signature) != sig_decoded.size(), error::wallet_internal_error, "Signature decoding error");
11221 memcpy(&signatures.back()[j], sig_decoded.data(), sizeof(crypto::signature));
11222 offset += sig_len;
11223 }
11224 }
11225
11226 // get signature prefix hash
11227 std::string sig_prefix_data((const char*)&txid, sizeof(crypto::hash));
11228 sig_prefix_data += message;
11229 crypto::hash sig_prefix_hash;
11230 crypto::cn_fast_hash(sig_prefix_data.data(), sig_prefix_data.size(), sig_prefix_hash);
11231
11232 std::vector<std::vector<crypto::signature>>::const_iterator sig_iter = signatures.cbegin();
11233 for(size_t i = 0; i < tx.vin.size(); ++i)
11234 {
11235 const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
11236 if (in_key == nullptr)
11237 continue;
11238
11239 // get output pubkeys in the ring
11241 const std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key->key_offsets);
11242 req.outputs.resize(absolute_offsets.size());
11243 for (size_t j = 0; j < absolute_offsets.size(); ++j)
11244 {
11245 req.outputs[j].amount = in_key->amount;
11246 req.outputs[j].index = absolute_offsets[j];
11247 }
11249 bool r;
11250 {
11251 const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
11252 r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
11253 }
11254 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
11255 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
11256 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "get_outs.bin");
11257 THROW_WALLET_EXCEPTION_IF(res.outs.size() != req.outputs.size(), error::wallet_internal_error,
11258 "daemon returned wrong response for get_outs.bin, wrong amounts count = " +
11259 std::to_string(res.outs.size()) + ", expected " + std::to_string(req.outputs.size()));
11260
11261 // copy pointers
11262 std::vector<const crypto::public_key *> p_output_keys;
11263 for (const COMMAND_RPC_GET_OUTPUTS_BIN::outkey &out : res.outs)
11264 p_output_keys.push_back(&out.key);
11265
11266 // check this ring
11267 if (!crypto::check_ring_signature(sig_prefix_hash, in_key->k_image, p_output_keys, sig_iter->data()))
11268 return false;
11269 ++sig_iter;
11270 }
11271 THROW_WALLET_EXCEPTION_IF(sig_iter != signatures.cend(), error::wallet_internal_error, "Signature iterator didn't reach the end");
11272 return true;
11273}
bool invoke_http_bin(const boost::string_ref uri, const t_request &req, t_response &res, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET")
Definition wallet2.h:1326
void * memcpy(void *a, const void *b, size_t c)
const char * res
POD_CLASS signature
Definition crypto.h:108
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
std::string encode(const std::string &data)
Definition base58.cpp:173
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
crypto::key_image k_image
std::vector< uint64_t > key_offsets
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_tx_key()

void tools::wallet2::check_tx_key ( const crypto::hash & txid,
const crypto::secret_key & tx_key,
const std::vector< crypto::secret_key > & additional_tx_keys,
const cryptonote::account_public_address & address,
uint64_t & received,
bool & in_pool,
uint64_t & confirmations )

Definition at line 11276 of file wallet2.cpp.

11277{
11278 crypto::key_derivation derivation;
11279 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation), error::wallet_internal_error,
11280 "Failed to generate key derivation from supplied parameters");
11281
11282 std::vector<crypto::key_derivation> additional_derivations;
11283 additional_derivations.resize(additional_tx_keys.size());
11284 for (size_t i = 0; i < additional_tx_keys.size(); ++i)
11285 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i]), error::wallet_internal_error,
11286 "Failed to generate key derivation from supplied parameters");
11287
11288 check_tx_key_helper(txid, derivation, additional_derivations, address, received, in_pool, confirmations);
11289}
void check_tx_key_helper(const crypto::hash &txid, const crypto::key_derivation &derivation, const std::vector< crypto::key_derivation > &additional_derivations, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_tx_key_helper() [1/2]

void tools::wallet2::check_tx_key_helper ( const crypto::hash & txid,
const crypto::key_derivation & derivation,
const std::vector< crypto::key_derivation > & additional_derivations,
const cryptonote::account_public_address & address,
uint64_t & received,
bool & in_pool,
uint64_t & confirmations )

Definition at line 11323 of file wallet2.cpp.

11324{
11327 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11328 req.decode_as_json = false;
11329 req.prune = true;
11330 m_daemon_rpc_mutex.lock();
11331 bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11332 m_daemon_rpc_mutex.unlock();
11333 THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
11334 error::wallet_internal_error, "Failed to get transaction from daemon");
11335
11336 cryptonote::transaction tx;
11337 crypto::hash tx_hash;
11338 if (res.txs.size() == 1)
11339 {
11340 ok = get_pruned_tx(res.txs.front(), tx, tx_hash);
11341 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11342 }
11343 else
11344 {
11345 cryptonote::blobdata tx_data;
11346 ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
11347 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11349 error::wallet_internal_error, "Failed to validate transaction from daemon");
11351 }
11352
11353 THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error,
11354 "Failed to get the right transaction from daemon");
11355 THROW_WALLET_EXCEPTION_IF(!additional_derivations.empty() && additional_derivations.size() != tx.vout.size(), error::wallet_internal_error,
11356 "The size of additional derivations is wrong");
11357
11358 check_tx_key_helper(tx, derivation, additional_derivations, address, received);
11359
11360 in_pool = res.txs.front().in_pool;
11361 confirmations = 0;
11362 if (!in_pool)
11363 {
11364 std::string err;
11365 uint64_t bc_height = get_daemon_blockchain_height(err);
11366 if (err.empty())
11367 confirmations = bc_height - res.txs.front().block_height;
11368 }
11369}
uint64_t get_daemon_blockchain_height(std::string &err) const
crypto::hash get_transaction_hash(const transaction &t)
std::string blobdata
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_tx_key_helper() [2/2]

void tools::wallet2::check_tx_key_helper ( const cryptonote::transaction & tx,
const crypto::key_derivation & derivation,
const std::vector< crypto::key_derivation > & additional_derivations,
const cryptonote::account_public_address & address,
uint64_t & received ) const

Definition at line 11291 of file wallet2.cpp.

11292{
11293 received = 0;
11294
11295 for (size_t n = 0; n < tx.vout.size(); ++n)
11296 {
11297 const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[n].target));
11298 if (!out_key)
11299 continue;
11300
11301 crypto::public_key derived_out_key;
11302 bool r = crypto::derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key);
11303 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
11304 bool found = out_key->key == derived_out_key;
11305 crypto::key_derivation found_derivation = derivation;
11306 if (!found && !additional_derivations.empty())
11307 {
11308 r = crypto::derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key);
11309 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
11310 found = out_key->key == derived_out_key;
11311 found_derivation = additional_derivations[n];
11312 }
11313
11314 if (found)
11315 {
11316 uint64_t amount;
11317 amount = tx.vout[n].amount;
11318 received += amount;
11319 }
11320 }
11321}
bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key)
Definition crypto.h:275
Here is the call graph for this function:

◆ check_tx_proof() [1/2]

bool tools::wallet2::check_tx_proof ( const crypto::hash & txid,
const cryptonote::account_public_address & address,
bool is_subaddress,
const std::string & message,
const std::string & sig_str,
uint64_t & received,
bool & in_pool,
uint64_t & confirmations )

Definition at line 11527 of file wallet2.cpp.

11528{
11529 // fetch tx pubkey from the daemon
11532 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11533 req.decode_as_json = false;
11534 req.prune = true;
11535 m_daemon_rpc_mutex.lock();
11536 bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11537 m_daemon_rpc_mutex.unlock();
11538 THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
11539 error::wallet_internal_error, "Failed to get transaction from daemon");
11540
11541 cryptonote::transaction tx;
11542 crypto::hash tx_hash;
11543 if (res.txs.size() == 1)
11544 {
11545 ok = get_pruned_tx(res.txs.front(), tx, tx_hash);
11546 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11547 }
11548 else
11549 {
11550 cryptonote::blobdata tx_data;
11551 ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
11552 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11554 error::wallet_internal_error, "Failed to validate transaction from daemon");
11556 }
11557
11558 THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
11559
11560 if (!check_tx_proof(tx, address, is_subaddress, message, sig_str, received))
11561 return false;
11562
11563 in_pool = res.txs.front().in_pool;
11564 confirmations = 0;
11565 if (!in_pool)
11566 {
11567 std::string err;
11568 uint64_t bc_height = get_daemon_blockchain_height(err);
11569 if (err.empty())
11570 confirmations = bc_height - res.txs.front().block_height;
11571 }
11572
11573 return true;
11574}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_tx_proof() [2/2]

bool tools::wallet2::check_tx_proof ( const cryptonote::transaction & tx,
const cryptonote::account_public_address & address,
bool is_subaddress,
const std::string & message,
const std::string & sig_str,
uint64_t & received ) const

Definition at line 11576 of file wallet2.cpp.

11577{
11578 CHECK_AND_ASSERT_THROW_MES(tx.version == 1, "Tx proofs are for v1 transactions only");
11579 const bool is_out = sig_str.substr(0, 3) == "Out";
11580 const std::string header = is_out ? "OutProofV1" : "InProofV1";
11581 const size_t header_len = header.size();
11582 THROW_WALLET_EXCEPTION_IF(sig_str.size() < header_len || sig_str.substr(0, header_len) != header, error::wallet_internal_error,
11583 "Signature header check error");
11584
11585 // decode base58
11586 std::vector<crypto::public_key> shared_secret(1);
11587 std::vector<crypto::signature> sig(1);
11588 const size_t pk_len = tools::base58::encode(std::string((const char *)&shared_secret[0], sizeof(crypto::public_key))).size();
11589 const size_t sig_len = tools::base58::encode(std::string((const char *)&sig[0], sizeof(crypto::signature))).size();
11590 const size_t num_sigs = (sig_str.size() - header_len) / (pk_len + sig_len);
11591 THROW_WALLET_EXCEPTION_IF(sig_str.size() != header_len + num_sigs * (pk_len + sig_len), error::wallet_internal_error,
11592 "Wrong signature size");
11593 shared_secret.resize(num_sigs);
11594 sig.resize(num_sigs);
11595 for (size_t i = 0; i < num_sigs; ++i)
11596 {
11597 std::string pk_decoded;
11598 std::string sig_decoded;
11599 const size_t offset = header_len + i * (pk_len + sig_len);
11600 THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(offset, pk_len), pk_decoded), error::wallet_internal_error,
11601 "Signature decoding error");
11602 THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(offset + pk_len, sig_len), sig_decoded), error::wallet_internal_error,
11603 "Signature decoding error");
11604 THROW_WALLET_EXCEPTION_IF(sizeof(crypto::public_key) != pk_decoded.size() || sizeof(crypto::signature) != sig_decoded.size(), error::wallet_internal_error,
11605 "Signature decoding error");
11606 memcpy(&shared_secret[i], pk_decoded.data(), sizeof(crypto::public_key));
11607 memcpy(&sig[i], sig_decoded.data(), sizeof(crypto::signature));
11608 }
11609
11611 THROW_WALLET_EXCEPTION_IF(tx_pub_key == null_pkey, error::wallet_internal_error, "Tx pubkey was not found");
11612
11613 std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
11614 THROW_WALLET_EXCEPTION_IF(additional_tx_pub_keys.size() + 1 != num_sigs, error::wallet_internal_error, "Signature size mismatch with additional tx pubkeys");
11615
11617 std::string prefix_data((const char*)&txid, sizeof(crypto::hash));
11618 prefix_data += message;
11619 crypto::hash prefix_hash;
11620 crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11621
11622 // check signature
11623 std::vector<int> good_signature(num_sigs, 0);
11624 if (is_out)
11625 {
11626 good_signature[0] = is_subaddress ?
11627 crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], sig[0]) :
11628 crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], sig[0]);
11629
11630 for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
11631 {
11632 good_signature[i + 1] = is_subaddress ?
11633 crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, address.m_spend_public_key, shared_secret[i + 1], sig[i + 1]) :
11634 crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, boost::none, shared_secret[i + 1], sig[i + 1]);
11635 }
11636 }
11637 else
11638 {
11639 good_signature[0] = is_subaddress ?
11640 crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], sig[0]) :
11641 crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], sig[0]);
11642
11643 for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
11644 {
11645 good_signature[i + 1] = is_subaddress ?
11646 crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], address.m_spend_public_key, shared_secret[i + 1], sig[i + 1]) :
11647 crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], boost::none, shared_secret[i + 1], sig[i + 1]);
11648 }
11649 }
11650
11651 if (std::any_of(good_signature.begin(), good_signature.end(), [](int i) { return i > 0; }))
11652 {
11653 // obtain key derivation by multiplying scalar 1 to the shared secret
11654 crypto::key_derivation derivation;
11655 if (good_signature[0])
11656 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[0], rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
11657
11658 std::vector<crypto::key_derivation> additional_derivations(num_sigs - 1);
11659 for (size_t i = 1; i < num_sigs; ++i)
11660 if (good_signature[i])
11661 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
11662
11663 check_tx_key_helper(tx, derivation, additional_derivations, address, received);
11664 return true;
11665 }
11666 return false;
11667}
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional< public_key > &B, const public_key &D, const signature &sig)
Definition crypto.h:314
@ none
Do not verify peer.
Definition net_ssl.h:54
Here is the call graph for this function:

◆ cold_key_image_sync()

uint64_t tools::wallet2::cold_key_image_sync ( uint64_t & spent,
uint64_t & unspent )

Definition at line 10694 of file wallet2.cpp.

10694 {
10695 auto & hwdev = get_account().get_device();
10696 CHECK_AND_ASSERT_THROW_MES(hwdev.has_ki_cold_sync(), "Device does not support cold ki sync protocol");
10697
10698 auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
10699 CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
10700
10701 std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
10703 setup_shim(&wallet_shim, this);
10704
10705 dev_cold->ki_sync(&wallet_shim, m_transfers, ski);
10706
10707 // Call COMMAND_RPC_IS_KEY_IMAGE_SPENT only if daemon is trusted.
10708 uint64_t import_res = import_key_images(ski, 0, spent, unspent, is_trusted_daemon());
10709 m_device_last_key_image_sync = time(NULL);
10710
10711 return import_res;
10712}
time_t time
hw::device & get_device() const
Definition account.h:91
cryptonote::account_base & get_account()
Definition wallet2.h:734
uint64_t import_key_images(const std::vector< std::pair< crypto::key_image, crypto::signature > > &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent=true)
bool is_trusted_daemon() const
Definition wallet2.h:765
struct hw::wallet_shim wallet_shim
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cold_sign_tx()

void tools::wallet2::cold_sign_tx ( const std::vector< pending_tx > & ptx_vector,
signed_tx_set & exported_txs,
std::vector< cryptonote::address_parse_info > & dsts_info,
std::vector< std::string > & tx_device_aux )

Definition at line 10665 of file wallet2.cpp.

10666{
10667 auto & hwdev = get_account().get_device();
10668 if (!hwdev.has_tx_cold_sign()){
10669 throw std::invalid_argument("Device does not support cold sign protocol");
10670 }
10671
10672 unsigned_tx_set txs;
10673 for (auto &tx: ptx_vector)
10674 {
10675 txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
10676 }
10677 txs.transfers = std::make_pair(0, m_transfers);
10678
10679 auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
10680 CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
10681
10682 hw::tx_aux_data aux_data;
10684 setup_shim(&wallet_shim, this);
10685 aux_data.tx_recipients = dsts_info;
10686 aux_data.bp_version = use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1;
10687 dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data);
10688 tx_device_aux = aux_data.tx_device_aux;
10689
10690 MDEBUG("Signed tx data from hw: " << exported_txs.ptx.size() << " transactions");
10691 for (auto &c_ptx: exported_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(c_ptx.tx));
10692}
std::vector< std::string > tx_device_aux
boost::optional< int > bp_version
std::vector< cryptonote::address_parse_info > tx_recipients
#define HF_VERSION_SMALLER_BP
#define MDEBUG(x)
Definition misc_log_ex.h:76
#define LOG_PRINT_L0(x)
Definition misc_log_ex.h:99
std::string obj_to_json_str(T &obj)
tools::wallet2::transfer_container transfers
std::vector< tools::wallet2::tx_construction_data > txes
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cold_tx_aux_import()

void tools::wallet2::cold_tx_aux_import ( const std::vector< pending_tx > & ptx,
const std::vector< std::string > & tx_device_aux )

Definition at line 10655 of file wallet2.cpp.

10656{
10657 CHECK_AND_ASSERT_THROW_MES(ptx.size() == tx_device_aux.size(), "TX aux has invalid size");
10658 for (size_t i = 0; i < ptx.size(); ++i){
10659 crypto::hash txid;
10660 txid = get_transaction_hash(ptx[i].tx);
10661 set_tx_device_aux(txid, tx_device_aux[i]);
10662 }
10663}
void set_tx_device_aux(const crypto::hash &txid, const std::string &aux)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ commit_tx() [1/2]

void tools::wallet2::commit_tx ( pending_tx & ptx_vector)

Definition at line 6887 of file wallet2.cpp.

6888{
6889 using namespace cryptonote;
6890
6891 if(m_light_wallet)
6892 {
6895 oreq.address = get_account().get_public_address_str(m_nettype);
6896 oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
6898 m_daemon_rpc_mutex.lock();
6899 bool r = invoke_http_json("/submit_raw_tx", oreq, ores, rpc_timeout, "POST");
6900 m_daemon_rpc_mutex.unlock();
6901 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "submit_raw_tx");
6902 // MyMonero and OpenMonero use different status strings
6903 THROW_WALLET_EXCEPTION_IF(ores.status != "OK" && ores.status != "success" , error::tx_rejected, ptx.tx, get_rpc_status(ores.status), ores.error);
6904 }
6905 else
6906 {
6907 // Normal submit
6910 req.do_not_relay = false;
6911 req.do_sanity_checks = true;
6912 COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
6913 m_daemon_rpc_mutex.lock();
6914 bool r = invoke_http_json("/sendrawtransaction", req, daemon_send_resp, rpc_timeout);
6915 m_daemon_rpc_mutex.unlock();
6916 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
6917 THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
6918 THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, get_rpc_status(daemon_send_resp.status), get_text_reason(daemon_send_resp));
6919 // sanity checks
6920 for (size_t idx: ptx.selected_transfers)
6921 {
6922 THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error,
6923 "Bad output index in selected transfers: " + boost::lexical_cast<std::string>(idx));
6924 }
6925 }
6926 crypto::hash txid;
6927
6928 txid = get_transaction_hash(ptx.tx);
6929 crypto::hash payment_id = crypto::null_hash;
6930 std::vector<cryptonote::tx_destination_entry> dests;
6931 uint64_t amount_in = 0;
6932 if (store_tx_info())
6933 {
6934 payment_id = get_payment_id(ptx);
6935 dests = ptx.dests;
6936 for(size_t idx: ptx.selected_transfers)
6937 amount_in += m_transfers[idx].amount();
6938 }
6939 add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
6940 if (store_tx_info())
6941 {
6942 m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
6943 m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
6944 }
6945
6946 LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]");
6947
6948 for(size_t idx: ptx.selected_transfers)
6949 {
6950 set_spent(idx, 0);
6951 }
6952
6953 // tx generated, get rid of used k values
6954 for (size_t idx: ptx.selected_transfers)
6955 m_transfers[idx].m_multisig_k.clear();
6956
6957 //fee includes dust if dust policy specified it.
6958 LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
6959 << "Commission: " << print_etn(ptx.fee) << " (dust sent to dust addr: " << print_etn((ptx.dust_added_to_fee ? 0 : ptx.dust)) << ")" << ENDL
6960 << "Pre V10 Balance: " << print_etn(balance(ptx.construction_data.subaddr_account, false)) << ENDL
6961 << "Pre V10 Unlocked Balance: " << print_etn(unlocked_balance(ptx.construction_data.subaddr_account, false)) << ENDL
6962 << "Public Chain Balance: " << print_etn(balance(ptx.construction_data.subaddr_account, true)) << ENDL
6963 << "Public Chain Unlocked Balance: " << print_etn(unlocked_balance(ptx.construction_data.subaddr_account, true)) << ENDL
6964 << "Please, wait for confirmation for your balance to be unlocked.");
6965}
std::string get_public_address_str(network_type nettype) const
Definition account.cpp:269
bool store_tx_info() const
Definition wallet2.h:1069
uint64_t unlocked_balance(uint32_t subaddr_index_major, bool public_blockchain, uint64_t *blocks_to_unlock=NULL) const
Definition wallet2.cpp:6172
#define ENDL
#define LOG_PRINT_L1(x)
#define LOG_PRINT_L2(x)
blobdata tx_to_blob(const transaction &tx)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
std::string buff_to_hex_nodelimer(const std::string &src)
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ commit_tx() [2/2]

void tools::wallet2::commit_tx ( std::vector< pending_tx > & ptx_vector)

Definition at line 6967 of file wallet2.cpp.

6968{
6969 for (auto & ptx : ptx_vector)
6970 {
6971 commit_tx(ptx);
6972 }
6973}
void commit_tx(pending_tx &ptx_vector)
Definition wallet2.cpp:6887
Here is the call graph for this function:

◆ confirm_backlog() [1/2]

bool tools::wallet2::confirm_backlog ( ) const
inline

Definition at line 1087 of file wallet2.h.

1087{ return m_confirm_backlog; }

◆ confirm_backlog() [2/2]

void tools::wallet2::confirm_backlog ( bool always)
inline

Definition at line 1088 of file wallet2.h.

1088{ m_confirm_backlog = always; }

◆ confirm_export_overwrite() [1/2]

bool tools::wallet2::confirm_export_overwrite ( ) const
inline

Definition at line 1091 of file wallet2.h.

1091{ return m_confirm_export_overwrite; }

◆ confirm_export_overwrite() [2/2]

void tools::wallet2::confirm_export_overwrite ( bool always)
inline

Definition at line 1092 of file wallet2.h.

1092{ m_confirm_export_overwrite = always; }

◆ confirm_missing_payment_id() [1/2]

bool tools::wallet2::confirm_missing_payment_id ( ) const
inline

Definition at line 1077 of file wallet2.h.

1077{ return m_confirm_missing_payment_id; }

◆ confirm_missing_payment_id() [2/2]

void tools::wallet2::confirm_missing_payment_id ( bool always)
inline

Definition at line 1078 of file wallet2.h.

1078{ m_confirm_missing_payment_id = always; }

◆ confirm_non_default_ring_size() [1/2]

bool tools::wallet2::confirm_non_default_ring_size ( ) const
inline

Definition at line 1103 of file wallet2.h.

1103{ return m_confirm_non_default_ring_size; }

◆ confirm_non_default_ring_size() [2/2]

void tools::wallet2::confirm_non_default_ring_size ( bool always)
inline

Definition at line 1104 of file wallet2.h.

1104{ m_confirm_non_default_ring_size = always; }

◆ create_transactions_2()

std::vector< wallet2::pending_tx > tools::wallet2::create_transactions_2 ( std::vector< cryptonote::tx_destination_entry > dsts,
const size_t fake_outs_count,
const uint64_t unlock_time,
uint32_t priority,
const std::vector< uint8_t > & extra,
uint32_t subaddr_account,
std::set< uint32_t > subaddr_indices )

Definition at line 9725 of file wallet2.cpp.

9726{
9727 //ensure device is let in NONE mode in any case
9728 hw::device &hwdev = m_account.get_device();
9729 boost::unique_lock<hw::device> hwdev_lock (hwdev);
9730 hw::reset_mode rst(hwdev);
9731
9732 //destinations in the full etn-address format
9733 auto original_dsts = dsts;
9734
9735 if(m_light_wallet) {
9736 // Populate m_transfers
9738 }
9739
9740 uint8_t tx_version = this->public_transactions_required() ? 3 : 1;
9741 //vector of pairs of <subaddr minor index : vector<transfer indexes for that subaddr index inside m_transfers>>
9742 std::vector<std::pair<uint32_t, std::vector<size_t>>> unused_transfers_indices_per_subaddr;
9743 std::vector<std::pair<uint32_t, std::vector<size_t>>> unused_dust_indices_per_subaddr;
9744 uint64_t needed_etn;
9745 uint64_t accumulated_fee, accumulated_outputs, accumulated_change;
9746 struct TX {
9747 std::vector<size_t> selected_transfers;
9748 std::vector<cryptonote::tx_destination_entry> dsts;
9749 cryptonote::transaction tx;
9750 pending_tx ptx;
9751 size_t weight;
9752 uint64_t needed_fee;
9753 std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
9754
9755 TX() : weight(0), needed_fee(0) {}
9756
9757 void add(const cryptonote::tx_destination_entry &de, uint64_t amount, unsigned int original_output_index, bool merge_destinations) {
9758 if (merge_destinations)
9759 {
9760 std::vector<cryptonote::tx_destination_entry>::iterator i;
9761 i = std::find_if(dsts.begin(), dsts.end(), [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &de.addr, sizeof(de.addr)); });
9762 if (i == dsts.end())
9763 {
9764 dsts.push_back(de);
9765 i = dsts.end() - 1;
9766 i->amount = 0;
9767 }
9768 i->amount += amount;
9769 }
9770 else
9771 {
9772 THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error,
9773 std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size()));
9774 if (original_output_index == dsts.size())
9775 {
9776 dsts.push_back(de);
9777 dsts.back().amount = 0;
9778 }
9779 THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &de.addr, sizeof(de.addr)), error::wallet_internal_error, "Mismatched destination address");
9780 dsts[original_output_index].amount += amount;
9781 }
9782 }
9783 };
9784 std::vector<TX> txes;
9785 bool adding_fee; // true if new outputs go towards fee, rather than destinations
9786
9787 uint64_t needed_fee, available_for_fee = 0;
9788 uint64_t upper_transaction_weight_limit;
9789 uint64_t extra_bytes = extra.size();
9790 switch(hwdev.get_type()){
9791
9792 // Normal Software Limit
9793 case 0 : upper_transaction_weight_limit = get_upper_transaction_weight_limit(); break;
9794
9795 // Ledger NanoS: ~3.3kB of RAM for app variables. Give a bit of buffer (300) for other variables on device
9796 // and subtract the size of the extra.
9797 // because in the Ledger app this still lives on the stack at the same time the entire prefix does.
9798 // This is a rough rule of thumb estimate... The logic can be updated at a later stage.
9799 // Right now we just need to make we don't fail to build any tx (and split the tx to avoid this happening)
9800 case 1 : upper_transaction_weight_limit = 3000 - extra_bytes; break;
9801
9802 //Trezor limit set at the same as Ledger for the time being.
9803 case 2 : upper_transaction_weight_limit = 3000 - extra_bytes; break;
9804 //Future hw devices
9805 }
9806 const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
9807 const bool use_rct = use_fork_rules(HF_VERSION_ENABLE_RCT, 0);
9808 const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
9809 const rct::RCTConfig rct_config {
9811 bulletproof ? (use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1) : 0
9812 };
9813
9814 const uint64_t base_fee = get_base_fee();
9815 const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
9816 const uint64_t fee_quantization_mask = get_fee_quantization_mask();
9817
9818 // throw if attempting a transaction with no destinations
9819 THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
9820
9821 // calculate total amount being sent to all destinations
9822 // throw if total amount overflows uint64_t
9823 needed_etn = 0;
9824 for(auto& dt: dsts)
9825 {
9826 THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination);
9827 needed_etn += dt.amount;
9828 LOG_PRINT_L2("transfer: adding " << print_etn(dt.amount) << ", for a total of " << print_etn (needed_etn));
9829 THROW_WALLET_EXCEPTION_IF(needed_etn < dt.amount, error::tx_sum_overflow, dsts, 0, m_nettype);
9830 }
9831
9832 // throw if attempting a transaction with no etn
9833 THROW_WALLET_EXCEPTION_IF(needed_etn == 0, error::zero_destination);
9834
9835 std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, tx_version >= 3);
9836 std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, tx_version >= 3);
9837
9838 if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
9839 {
9840 for (const auto& i : balance_per_subaddr)
9841 subaddr_indices.insert(i.first);
9842 }
9843
9844 // early out if we know we can't make it anyway
9845 // we could also check for being within FEE_PER_KB, but if the fee calculation
9846 // ever changes, this might be missed, so let this go through
9847 uint64_t min_fee = (fee_multiplier * base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof));
9848 //Whilst we're still dealing with fee/kb:
9849 if (!use_per_byte_fee){
9850 min_fee /= 1000;
9851 if(min_fee == 0){min_fee += 10;}
9852 }
9853 uint64_t balance_subtotal = 0;
9854 uint64_t unlocked_balance_subtotal = 0;
9855 for (uint32_t index_minor : subaddr_indices)
9856 {
9857 balance_subtotal += balance_per_subaddr[index_minor];
9858 unlocked_balance_subtotal += unlocked_balance_per_subaddr[index_minor].first;
9859 }
9860 THROW_WALLET_EXCEPTION_IF(needed_etn + min_fee > balance_subtotal, error::not_enough_etn,
9861 balance_subtotal, needed_etn, 0);
9862 // first check overall balance is enough, then unlocked one, so we throw distinct exceptions
9863 THROW_WALLET_EXCEPTION_IF(needed_etn + min_fee > unlocked_balance_subtotal, error::not_enough_unlocked_etn,
9864 unlocked_balance_subtotal, needed_etn, 0);
9865
9866 for (uint32_t i : subaddr_indices)
9867 LOG_PRINT_L2("Candidate subaddress index for spending: " << i);
9868
9869 // determine threshold for fractional amount
9870 const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof);
9871 const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof);
9872 THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!");
9873 const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
9874 const uint64_t fractional_threshold = (fee_multiplier * base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
9875
9876 // gather all dust and non-dust outputs belonging to specified subaddresses
9877 size_t num_nondust_outputs = 0;
9878 size_t num_dust_outputs = 0;
9879 for (size_t i = 0; i < m_transfers.size(); ++i)
9880 {
9881 const transfer_details& td = m_transfers[i];
9882 if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
9883 {
9884 MDEBUG("Ignoring output " << i << " of amount " << print_etn(td.amount()) << " which is below threshold " << print_etn(fractional_threshold));
9885 continue;
9886 }
9887 if (!td.m_spent && !td.m_frozen && (!td.m_key_image_partial || td.m_tx.version > 1) && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
9888 {
9889 if((tx_version < 3 && td.m_tx.version > 1) || (tx_version >= 3 && td.m_tx.version == 1))
9890 continue;
9891
9892 const uint32_t index_minor = td.m_subaddr_index.minor;
9893 auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; };
9894 if ((td.is_rct()) || is_valid_decomposed_amount(td.amount()))
9895 {
9896 auto found = std::find_if(unused_transfers_indices_per_subaddr.begin(), unused_transfers_indices_per_subaddr.end(), find_predicate);
9897 if (found == unused_transfers_indices_per_subaddr.end())
9898 {
9899 unused_transfers_indices_per_subaddr.push_back({index_minor, {i}});
9900 }
9901 else
9902 {
9903 found->second.push_back(i);
9904 }
9905 ++num_nondust_outputs;
9906 }
9907 else
9908 {
9909 auto found = std::find_if(unused_dust_indices_per_subaddr.begin(), unused_dust_indices_per_subaddr.end(), find_predicate);
9910 if (found == unused_dust_indices_per_subaddr.end())
9911 {
9912 unused_dust_indices_per_subaddr.push_back({index_minor, {i}});
9913 }
9914 else
9915 {
9916 found->second.push_back(i);
9917 }
9918 ++num_dust_outputs;
9919 }
9920 }
9921 }
9922
9923 // sort output indices
9924 {
9925 auto sort_predicate = [&unlocked_balance_per_subaddr] (const std::pair<uint32_t, std::vector<size_t>>& x, const std::pair<uint32_t, std::vector<size_t>>& y)
9926 {
9927 return unlocked_balance_per_subaddr[x.first].first > unlocked_balance_per_subaddr[y.first].first;
9928 };
9929 std::sort(unused_transfers_indices_per_subaddr.begin(), unused_transfers_indices_per_subaddr.end(), sort_predicate);
9930 std::sort(unused_dust_indices_per_subaddr.begin(), unused_dust_indices_per_subaddr.end(), sort_predicate);
9931 }
9932
9933 LOG_PRINT_L2("Starting with " << num_nondust_outputs << " non-dust outputs and " << num_dust_outputs << " dust outputs");
9934
9935 if (unused_dust_indices_per_subaddr.empty() && unused_transfers_indices_per_subaddr.empty())
9936 return std::vector<wallet2::pending_tx>();
9937
9938 // if empty, put dummy entry so that the front can be referenced later in the loop
9939 if (unused_dust_indices_per_subaddr.empty())
9940 unused_dust_indices_per_subaddr.push_back({});
9941 if (unused_transfers_indices_per_subaddr.empty())
9942 unused_transfers_indices_per_subaddr.push_back({});
9943
9944 // start with an empty tx
9945 txes.push_back(TX());
9946 accumulated_fee = 0;
9947 accumulated_outputs = 0;
9948 accumulated_change = 0;
9949 adding_fee = false;
9950 needed_fee = 0;
9951 std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
9952
9953 // for rct, since we don't see the amounts, we will try to make all transactions
9954 // look the same, with 1 or 2 inputs, and 2 outputs. One input is preferable, as
9955 // this prevents linking to another by provenance analysis, but two is ok if we
9956 // try to pick outputs not from the same block. We will get two outputs, one for
9957 // the destination, and one for change.
9958 LOG_PRINT_L2("checking preferred");
9959 std::vector<size_t> preferred_inputs;
9960 uint64_t rct_outs_needed = 2 * (fake_outs_count + 1);
9961 rct_outs_needed += 100; // some fudge factor since we don't know how many are locked
9962 if (use_rct)
9963 {
9964 // this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
9965 // will get us a known fee.
9966 uint64_t estimated_fee = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, base_fee, fee_multiplier, fee_quantization_mask);
9967 preferred_inputs = pick_preferred_rct_inputs(needed_etn + estimated_fee, subaddr_account, subaddr_indices);
9968 if (!preferred_inputs.empty())
9969 {
9970 string s;
9971 for (auto i: preferred_inputs) s += boost::lexical_cast<std::string>(i) + " (" + print_etn(m_transfers[i].amount()) + ") ";
9972 LOG_PRINT_L1("Found preferred rct inputs for rct tx: " << s);
9973
9974 // bring the list of available outputs stored by the same subaddress index to the front of the list
9975 uint32_t index_minor = m_transfers[preferred_inputs[0]].m_subaddr_index.minor;
9976 for (size_t i = 1; i < unused_transfers_indices_per_subaddr.size(); ++i)
9977 {
9978 if (unused_transfers_indices_per_subaddr[i].first == index_minor)
9979 {
9980 std::swap(unused_transfers_indices_per_subaddr[0], unused_transfers_indices_per_subaddr[i]);
9981 break;
9982 }
9983 }
9984 for (size_t i = 1; i < unused_dust_indices_per_subaddr.size(); ++i)
9985 {
9986 if (unused_dust_indices_per_subaddr[i].first == index_minor)
9987 {
9988 std::swap(unused_dust_indices_per_subaddr[0], unused_dust_indices_per_subaddr[i]);
9989 break;
9990 }
9991 }
9992 }
9993 }
9994 LOG_PRINT_L2("done checking preferred");
9995
9996 // while:
9997 // - we have something to send
9998 // - or we need to gather more fee
9999 // - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2)
10000 unsigned int original_output_index = 0;
10001 std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second;
10002 std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second;
10003
10005 while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) {
10006 TX &tx = txes.back();
10007
10008 LOG_PRINT_L2("Start of loop with " << unused_transfers_indices->size() << " " << unused_dust_indices->size() << ", tx.dsts.size() " << tx.dsts.size());
10009 LOG_PRINT_L2("unused_transfers_indices: " << strjoin(*unused_transfers_indices, " "));
10010 LOG_PRINT_L2("unused_dust_indices: " << strjoin(*unused_dust_indices, " "));
10011 LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? "-" : cryptonote::print_etn(dsts[0].amount)));
10012 LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct);
10013
10014 // if we need to spend etn and don't have any left, we fail
10015 if (unused_dust_indices->empty() && unused_transfers_indices->empty()) {
10016 LOG_PRINT_L2("No more outputs to choose from");
10017 THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, tx_version >= 3), needed_etn, accumulated_fee + needed_fee);
10018 }
10019
10020 // get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
10021 // This could be more clever, but maybe at the cost of making probabilistic inferences easier
10022 size_t idx;
10023 if (!preferred_inputs.empty()) {
10024 idx = pop_back(preferred_inputs);
10025 pop_if_present(*unused_transfers_indices, idx);
10026 pop_if_present(*unused_dust_indices, idx);
10027 } else if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee) {
10028 // the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too
10029 std::vector<size_t> indices = get_only_rct(*unused_dust_indices, *unused_transfers_indices);
10030 idx = pop_best_value(indices, tx.selected_transfers, true);
10031
10032 // we might not want to add it if it's a large output and we don't have many left
10033 uint64_t min_output_value = m_min_output_value;
10034 uint32_t min_output_count = m_min_output_count;
10035 if (min_output_value == 0 && min_output_count == 0)
10036 {
10037 min_output_value = DEFAULT_MIN_OUTPUT_VALUE;
10038 min_output_count = DEFAULT_MIN_OUTPUT_COUNT;
10039 }
10040 if (m_transfers[idx].amount() >= min_output_value) {
10041 if (get_count_above(m_transfers, *unused_transfers_indices, min_output_value) < min_output_count) {
10042 LOG_PRINT_L2("Second output was not strictly needed, and we're running out of outputs above " << print_etn(min_output_value) << ", not adding");
10043 break;
10044 }
10045 }
10046
10047 // since we're trying to add a second output which is not strictly needed,
10048 // we only add it if it's unrelated enough to the first one
10049 float relatedness = get_output_relatedness(m_transfers[idx], m_transfers[tx.selected_transfers.front()]);
10050 if (relatedness > SECOND_OUTPUT_RELATEDNESS_THRESHOLD)
10051 {
10052 LOG_PRINT_L2("Second output was not strictly needed, and relatedness " << relatedness << ", not adding");
10053 break;
10054 }
10055 pop_if_present(*unused_transfers_indices, idx);
10056 pop_if_present(*unused_dust_indices, idx);
10057 } else
10058 idx = pop_best_value(unused_transfers_indices->empty() ? *unused_dust_indices : *unused_transfers_indices, tx.selected_transfers);
10059
10060 const transfer_details &td = m_transfers[idx];
10061 LOG_PRINT_L2("Picking output " << idx << ", amount " << print_etn(td.amount()) << ", ki " << td.m_key_image);
10062
10063 // add this output to the list to spend
10064 tx.selected_transfers.push_back(idx);
10065 uint64_t available_amount = td.amount();
10066 accumulated_outputs += available_amount;
10067
10068 // clear any fake outs we'd already gathered, since we'll need a new set
10069 outs.clear();
10070
10071 if (adding_fee)
10072 {
10073 LOG_PRINT_L2("We need more fee, adding it to fee");
10074 available_for_fee += available_amount;
10075 }
10076 else
10077 {
10078 while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof) < TX_WEIGHT_TARGET(upper_transaction_weight_limit))
10079 {
10080 // we can fully pay that destination
10081 LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) <<
10082 " for " << print_etn(dsts[0].amount));
10083 tx.add(dsts[0], dsts[0].amount, original_output_index, m_merge_destinations);
10084 available_amount -= dsts[0].amount;
10085 dsts[0].amount = 0;
10086 pop_index(dsts, 0);
10087 ++original_output_index;
10088 }
10089
10090 if (available_amount > 0 && !dsts.empty() && estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof) < TX_WEIGHT_TARGET(upper_transaction_weight_limit)) {
10091 // we can partially fill that destination
10092 LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) <<
10093 " for " << print_etn(available_amount) << "/" << print_etn(dsts[0].amount));
10094 tx.add(dsts[0], available_amount, original_output_index, m_merge_destinations);
10095 dsts[0].amount -= available_amount;
10096 available_amount = 0;
10097 }
10098 }
10099
10100 // here, check if we need to sent tx and start a new one
10101 LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
10102 << upper_transaction_weight_limit);
10103 bool try_tx = false;
10104 // if we have preferred picks, but haven't yet used all of them, continue
10105 if (preferred_inputs.empty())
10106 {
10107 if (adding_fee)
10108 {
10109 /* might not actually be enough if adding this output bumps size to next kB, but we need to try */
10110 try_tx = available_for_fee >= needed_fee;
10111 }
10112 else
10113 {
10114 const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof);
10115 try_tx = dsts.empty() || (estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
10116 THROW_WALLET_EXCEPTION_IF(try_tx && tx.dsts.empty(), error::tx_too_big, estimated_rct_tx_weight, upper_transaction_weight_limit);
10117 }
10118 }
10119
10120 if (try_tx) {
10121 cryptonote::transaction test_tx;
10122 test_tx.version = tx_version;
10123 pending_tx test_ptx;
10124
10125 needed_fee = estimate_fee(use_per_byte_fee, use_rct ,tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, base_fee, fee_multiplier, fee_quantization_mask);
10126
10127 uint64_t inputs = 0, outputs = needed_fee;
10128 for (size_t idx: tx.selected_transfers) inputs += m_transfers[idx].amount();
10129 for (const auto &o: tx.dsts) outputs += o.amount;
10130
10131 if (inputs < outputs)
10132 {
10133 LOG_PRINT_L2("We don't have enough for the basic fee, switching to adding_fee");
10134 adding_fee = true;
10135 goto skip_tx;
10136 }
10137
10138 LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
10139 tx.selected_transfers.size() << " inputs");
10140
10141 transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
10142 detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10143 auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
10144 needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
10145 available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0);
10146 LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(available_for_fee) << " available for fee (" <<
10147 print_etn(needed_fee) << " needed)");
10148
10149 if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0)
10150 {
10151 // we don't have enough for the fee, but we've only partially paid the current address,
10152 // so we can take the fee from the paid amount, since we'll have to make another tx anyway
10153 std::vector<cryptonote::tx_destination_entry>::iterator i;
10154 i = std::find_if(tx.dsts.begin(), tx.dsts.end(),
10155 [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &dsts[0].addr, sizeof(dsts[0].addr)); });
10156 THROW_WALLET_EXCEPTION_IF(i == tx.dsts.end(), error::wallet_internal_error, "paid address not found in outputs");
10157 if (i->amount > needed_fee)
10158 {
10159 uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_fee;
10160 LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_nettype, i->is_subaddress, i->addr) << " from " <<
10161 print_etn(i->amount) << " to " << print_etn(new_paid_amount) << " to accommodate " <<
10162 print_etn(needed_fee) << " fee");
10163 dsts[0].amount += i->amount - new_paid_amount;
10164 i->amount = new_paid_amount;
10165 test_ptx.fee = needed_fee;
10166 available_for_fee = needed_fee;
10167 }
10168 }
10169
10170 if (needed_fee > available_for_fee)
10171 {
10172 LOG_PRINT_L2("We could not make a tx, switching to fee accumulation");
10173
10174 adding_fee = true;
10175 }
10176 else
10177 {
10178 LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_etn(needed_fee) << " and we have " << print_etn(test_ptx.fee));
10179 while (needed_fee > test_ptx.fee) {
10180 transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
10181 detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10182 txBlob = t_serializable_object_to_blob(test_ptx.tx);
10183 needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
10184 LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
10185 " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
10186 }
10187
10188 LOG_PRINT_L2("Made a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
10189 " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
10190
10191 tx.tx = test_tx;
10192 tx.ptx = test_ptx;
10193 tx.weight = get_transaction_weight(test_tx, txBlob.size());
10194 tx.outs = outs;
10195 tx.needed_fee = test_ptx.fee;
10196 accumulated_fee += test_ptx.fee;
10197 accumulated_change += test_ptx.change_dts.amount;
10198 adding_fee = false;
10199 if (!dsts.empty())
10200 {
10201 LOG_PRINT_L2("We have more to pay, starting another tx");
10202 txes.push_back(TX());
10203 original_output_index = 0;
10204 }
10205 }
10206 }
10207
10208skip_tx:
10209 // if unused_*_indices is empty while unused_*_indices_per_subaddr has multiple elements, and if we still have something to pay,
10210 // pop front of unused_*_indices_per_subaddr and have unused_*_indices point to the front of unused_*_indices_per_subaddr
10211 if ((!dsts.empty() && dsts[0].amount > 0) || adding_fee)
10212 {
10213 if (unused_transfers_indices->empty() && unused_transfers_indices_per_subaddr.size() > 1)
10214 {
10215 unused_transfers_indices_per_subaddr.erase(unused_transfers_indices_per_subaddr.begin());
10216 unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second;
10217 }
10218 if (unused_dust_indices->empty() && unused_dust_indices_per_subaddr.size() > 1)
10219 {
10220 unused_dust_indices_per_subaddr.erase(unused_dust_indices_per_subaddr.begin());
10221 unused_dust_indices = &unused_dust_indices_per_subaddr[0].second;
10222 }
10223 }
10224 }
10225
10226 if (adding_fee)
10227 {
10228 LOG_PRINT_L1("We ran out of outputs while trying to gather final fee");
10229 THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, tx_version >= 3), needed_etn, accumulated_fee + needed_fee);
10230 }
10231
10232 LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_etn(accumulated_fee) <<
10233 " total fee, " << print_etn(accumulated_change) << " total change");
10234
10236 for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10237 {
10238 TX &tx = *i;
10239 cryptonote::transaction test_tx;
10240 test_tx.version = tx_version;
10241 pending_tx test_ptx;
10242 transfer_selected(tx.dsts,
10243 tx.selected_transfers,
10244 fake_outs_count,
10245 tx.outs,
10246 unlock_time,
10247 tx.needed_fee,
10248 extra,
10250 tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD),
10251 test_tx,
10252 test_ptx);
10253
10254 auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
10255 tx.tx = test_tx;
10256 tx.ptx = test_ptx;
10257 tx.weight = get_transaction_weight(test_tx, txBlob.size());
10258 }
10259
10260 std::vector<wallet2::pending_tx> ptx_vector;
10261 for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10262 {
10263 TX &tx = *i;
10264 uint64_t tx_etn = 0;
10265 for (size_t idx: tx.selected_transfers)
10266 tx_etn += m_transfers[idx].amount();
10267 LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
10268 " " << get_transaction_hash(tx.ptx.tx) << ": " << get_weight_string(tx.weight) << ", sending " << print_etn(tx_etn) << " in " << tx.selected_transfers.size() <<
10269 " outputs to " << tx.dsts.size() << " destination(s), including " <<
10270 print_etn(tx.ptx.fee) << " fee, " << print_etn(tx.ptx.change_dts.amount) << " change");
10271 ptx_vector.push_back(tx.ptx);
10272 }
10273
10274 THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, original_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
10275
10276 // if we made it this far, we're OK to actually send the transactions
10277 return ptx_vector;
10278}
virtual device_type get_type() const =0
@ TRANSACTION_CREATE_FAKE
Definition device.hpp:101
@ TRANSACTION_CREATE_REAL
Definition device.hpp:100
virtual bool set_mode(device_mode mode)
Definition device.hpp:130
bool sanity_check(const std::vector< wallet2::pending_tx > &ptx_vector, std::vector< cryptonote::tx_destination_entry > dsts) const
void light_wallet_get_unspent_outs()
Definition wallet2.cpp:9284
int get_fee_algorithm() const
Definition wallet2.cpp:7824
uint64_t get_fee_quantization_mask() const
Definition wallet2.cpp:7807
void transfer_selected(const std::vector< cryptonote::tx_destination_entry > &dsts, const std::vector< size_t > &selected_transfers, size_t fake_outputs_count, std::vector< std::vector< tools::wallet2::get_outs_entry > > &outs, uint64_t unlock_time, uint64_t fee, const std::vector< uint8_t > &extra, T destination_split_strategy, const tx_dust_policy &dust_policy, cryptonote::transaction &tx, pending_tx &ptx)
Definition wallet2.cpp:8952
std::map< uint32_t, std::pair< uint64_t, uint64_t > > unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool public_blockchain=false) const
Definition wallet2.cpp:6249
bool public_transactions_required() const
Definition wallet2.h:900
bool is_transfer_unlocked(const transfer_details &td) const
Definition wallet2.cpp:6565
size_t pop_best_value(std::vector< size_t > &unused_dust_indices, const std::vector< size_t > &selected_transfers, bool smallest=false) const
Definition wallet2.cpp:6740
#define HF_VERSION_ENABLE_RCT
uint64_t const DEFAULT_DUST_THRESHOLD
bool is_valid_decomposed_amount(uint64_t amount)
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
@ RangeProofBorromean
Definition rctTypes.h:235
@ RangeProofPaddedBulletproof
Definition rctTypes.h:235
void digit_split_strategy(const std::vector< cryptonote::tx_destination_entry > &dsts, const cryptonote::tx_destination_entry &change_dst, uint64_t dust_threshold, std::vector< cryptonote::tx_destination_entry > &splitted_dsts, std::vector< cryptonote::tx_destination_entry > &dust_dsts)
Definition wallet2.h:2098
unsigned char uint8_t
Definition stdint.h:124
account_public_address addr
#define TX_WEIGHT_TARGET(bytes)
Definition wallet2.cpp:100
#define DEFAULT_MIN_OUTPUT_VALUE
Definition wallet2.cpp:138
#define SECOND_OUTPUT_RELATEDNESS_THRESHOLD
Definition wallet2.cpp:118
#define DEFAULT_MIN_OUTPUT_COUNT
Definition wallet2.cpp:137
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_transactions_all()

std::vector< wallet2::pending_tx > tools::wallet2::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,
const uint64_t unlock_time,
uint32_t priority,
const std::vector< uint8_t > & extra,
uint32_t subaddr_account,
std::set< uint32_t > subaddr_indices,
const bool migrate = false )

Definition at line 10359 of file wallet2.cpp.

10360{
10361 std::vector<size_t> unused_transfers_indices;
10362 std::vector<size_t> unused_dust_indices;
10363 const bool use_rct = use_fork_rules(4, 0);
10364 uint8_t tx_version = public_transactions_required() ? (migrate ? 2 : 3) : 1; //public migration **NOT** SC migration. SC migration tx are just vanilla v3 tx.
10365 THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, tx_version >=3) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet");
10366 std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr;
10367
10368 // gather all dust ***and*** non-dust outputs of specified subaddress (if any) and below specified threshold (if any)
10369 bool fund_found = false;
10370 for (size_t i = 0; i < m_transfers.size(); ++i)
10371 {
10372 const transfer_details& td = m_transfers[i];
10373
10374 if((tx_version < 3 && td.m_tx.version > 1) || (tx_version >= 3 && td.m_tx.version == 1))
10375 continue;
10376
10377 if (!td.m_spent && !td.m_frozen && (!td.m_key_image_partial || tx_version >= 3) && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
10378 {
10379 fund_found = true;
10380 if (below == 0 || td.amount() < below)
10381 {
10382 if ((td.is_rct()) || is_valid_decomposed_amount(td.amount()))
10383 unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].first.push_back(i);
10384 else
10385 unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].second.push_back(i);
10386 }
10387 }
10388 }
10389 THROW_WALLET_EXCEPTION_IF(!fund_found, error::wallet_internal_error, "No unlocked balance in the specified subaddress(es)");
10390 THROW_WALLET_EXCEPTION_IF(unused_transfer_dust_indices_per_subaddr.empty(), error::wallet_internal_error, "The smallest amount found is not below the specified threshold");
10391
10392 if (subaddr_indices.empty())
10393 {
10394 // in case subaddress index wasn't specified, choose non-empty subaddress randomly (with index=0 being chosen last)
10395 if (unused_transfer_dust_indices_per_subaddr.count(0) == 1 && unused_transfer_dust_indices_per_subaddr.size() > 1)
10396 unused_transfer_dust_indices_per_subaddr.erase(0);
10397 auto i = unused_transfer_dust_indices_per_subaddr.begin();
10398 std::advance(i, crypto::rand_idx(unused_transfer_dust_indices_per_subaddr.size()));
10399 unused_transfers_indices = i->second.first;
10400 unused_dust_indices = i->second.second;
10401 LOG_PRINT_L2("Spending from subaddress index " << i->first);
10402 }
10403 else
10404 {
10405 for (const auto& p : unused_transfer_dust_indices_per_subaddr)
10406 {
10407 unused_transfers_indices.insert(unused_transfers_indices.end(), p.second.first.begin(), p.second.first.end());
10408 unused_dust_indices.insert(unused_dust_indices.end(), p.second.second.begin(), p.second.second.end());
10409 LOG_PRINT_L2("Spending from subaddress index " << p.first);
10410 }
10411 }
10412
10413 return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, tx_version);
10414}
std::vector< wallet2::pending_tx > create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector< size_t > unused_transfers_indices, std::vector< size_t > unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector< uint8_t > &extra, const uint8_t tx_version)
std::enable_if< std::is_unsigned< T >::value, T >::type rand_idx(T sz)
Definition crypto.h:244
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_transactions_from()

std::vector< wallet2::pending_tx > tools::wallet2::create_transactions_from ( const cryptonote::account_public_address & address,
bool is_subaddress,
const size_t outputs,
std::vector< size_t > unused_transfers_indices,
std::vector< size_t > unused_dust_indices,
const size_t fake_outs_count,
const uint64_t unlock_time,
uint32_t priority,
const std::vector< uint8_t > & extra,
const uint8_t tx_version )

Definition at line 10439 of file wallet2.cpp.

10440{
10441 //ensure device is let in NONE mode in any case
10442 hw::device &hwdev = m_account.get_device();
10443 boost::unique_lock<hw::device> hwdev_lock (hwdev);
10444 hw::reset_mode rst(hwdev);
10445
10446 uint64_t accumulated_fee, accumulated_outputs, accumulated_change;
10447 struct TX {
10448 std::vector<size_t> selected_transfers;
10449 std::vector<cryptonote::tx_destination_entry> dsts;
10450 cryptonote::transaction tx;
10451 pending_tx ptx;
10452 size_t weight;
10453 uint64_t needed_fee;
10454 std::vector<std::vector<get_outs_entry>> outs;
10455
10456 TX() : weight(0), needed_fee(0) {}
10457 };
10458 std::vector<TX> txes;
10459 uint64_t needed_fee, available_for_fee = 0;
10460 uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit(); //max size of a tx - usually ~ half the block size
10461 std::vector<std::vector<get_outs_entry>> outs;
10462
10463 const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE);
10464 const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
10465 const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
10466 const rct::RCTConfig rct_config {
10468 bulletproof ? (use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1) : 0,
10469 };
10470 const uint64_t base_fee = get_base_fee();
10471 const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
10472 const uint64_t fee_quantization_mask = get_fee_quantization_mask();
10473
10474 LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs");
10475
10476 if (unused_dust_indices.empty() && unused_transfers_indices.empty())
10477 return std::vector<wallet2::pending_tx>();
10478
10479 // start with an empty tx
10480 txes.push_back(TX());
10481 accumulated_fee = 0;
10482 accumulated_outputs = 0;
10483 accumulated_change = 0;
10484 needed_fee = 0;
10485
10486 // while we have something to send
10488 while (!unused_dust_indices.empty() || !unused_transfers_indices.empty()) {
10489 TX &tx = txes.back();
10490
10491 // get a random unspent output and use it to pay next chunk. We try to alternate
10492 // dust and non dust to ensure we never get with only dust, from which we might
10493 // get a tx that can't pay for itself
10494 uint64_t fee_dust_threshold;
10496 {
10497 const uint64_t estimated_tx_weight_with_one_extra_output = estimate_tx_weight(use_rct, tx.selected_transfers.size() + 1, fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof);
10498 fee_dust_threshold = calculate_fee_from_weight(base_fee, estimated_tx_weight_with_one_extra_output, fee_multiplier, fee_quantization_mask);
10499 }
10500 else
10501 {
10502 fee_dust_threshold = base_fee * fee_multiplier * (upper_transaction_weight_limit + 1023) / 1024;
10503 }
10504
10505 size_t idx =
10506 unused_transfers_indices.empty()
10507 ? pop_best_value(unused_dust_indices, tx.selected_transfers)
10508 : unused_dust_indices.empty()
10509 ? pop_best_value(unused_transfers_indices, tx.selected_transfers)
10510 : ((tx.selected_transfers.size() & 1) || accumulated_outputs > fee_dust_threshold)
10511 ? pop_best_value(unused_dust_indices, tx.selected_transfers)
10512 : pop_best_value(unused_transfers_indices, tx.selected_transfers);
10513
10514 const transfer_details &td = m_transfers[idx];
10515 LOG_PRINT_L2("Picking output " << idx << ", amount " << print_etn(td.amount()));
10516
10517 // add this output to the list to spend
10518 tx.selected_transfers.push_back(idx);
10519 uint64_t available_amount = td.amount();
10520 accumulated_outputs += available_amount;
10521
10522 // clear any fake outs we'd already gathered, since we'll need a new set
10523 outs.clear();
10524
10525 // here, check if we need to sent tx and start a new one
10526 LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
10527 << upper_transaction_weight_limit);
10528 const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 2, extra.size(), bulletproof);
10529 bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
10530
10531 if (try_tx) {
10532 cryptonote::transaction test_tx;
10533 test_tx.version = tx_version;
10534 pending_tx test_ptx;
10535
10536 needed_fee = tx_version == 2 ? 0 : estimate_fee(use_per_byte_fee, use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, base_fee, fee_multiplier, fee_quantization_mask);
10537
10538 // add N - 1 outputs for correct initial fee estimation
10539 for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i)
10540 tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
10541
10542 LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
10543 tx.selected_transfers.size() << " outputs");
10544
10545 transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
10546 detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10547
10548 auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
10549 needed_fee = tx_version == 2 ? 0 : calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
10550 available_for_fee = test_ptx.fee + test_ptx.change_dts.amount;
10551 for (auto &dt: test_ptx.dests)
10552 available_for_fee += dt.amount;
10553 LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(available_for_fee) << " available for fee (" <<
10554 print_etn(needed_fee) << " needed)");
10555
10556 // add last output, missed for fee estimation
10557 if (outputs > 1)
10558 tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
10559
10560 THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself");
10561
10562 do {
10563 LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
10564 // distribute total transferred amount between outputs
10565 uint64_t amount_transferred = available_for_fee - needed_fee; //shouuld be zero for migration transactions
10566 uint64_t dt_amount = amount_transferred / outputs;
10567 // residue is distributed as one atomic unit per output until it reaches zero
10568 uint64_t residue = amount_transferred % outputs;
10569 for (auto &dt: tx.dsts)
10570 {
10571 uint64_t dt_residue = 0;
10572 if (residue > 0)
10573 {
10574 dt_residue = 1;
10575 residue -= 1;
10576 }
10577 dt.amount = dt_amount + dt_residue;
10578 }
10579 transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
10580 detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10581 txBlob = t_serializable_object_to_blob(test_ptx.tx);
10582 needed_fee = tx_version == 2 ? 0 : calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
10583 LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
10584 " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
10585 } while (needed_fee > test_ptx.fee);
10586
10587 LOG_PRINT_L2("Made a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
10588 " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
10589
10590 tx.tx = test_tx;
10591 tx.ptx = test_ptx;
10592 tx.weight = get_transaction_weight(test_tx, txBlob.size());
10593 tx.outs = outs;
10594 tx.needed_fee = test_ptx.fee;
10595 accumulated_fee += test_ptx.fee;
10596 accumulated_change += test_ptx.change_dts.amount;
10597 if (!unused_transfers_indices.empty() || !unused_dust_indices.empty())
10598 {
10599 LOG_PRINT_L2("We have more to pay, starting another tx");
10600 txes.push_back(TX());
10601 }
10602 }
10603 }
10604
10605 LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_etn(accumulated_fee) <<
10606 " total fee, " << print_etn(accumulated_change) << " total change");
10607
10609 for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10610 {
10611 TX &tx = *i;
10612 cryptonote::transaction test_tx;
10613 test_tx.version = tx_version;
10614 pending_tx test_ptx;
10615 transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra,
10616 detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10617
10618 auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
10619 tx.tx = test_tx;
10620 tx.ptx = test_ptx;
10621 tx.weight = get_transaction_weight(test_tx, txBlob.size());
10622 }
10623
10624 std::vector<wallet2::pending_tx> ptx_vector;
10625 for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10626 {
10627 TX &tx = *i;
10628 uint64_t tx_etn = 0;
10629 for (size_t idx: tx.selected_transfers)
10630 tx_etn += m_transfers[idx].amount();
10631 LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
10632 " " << get_transaction_hash(tx.ptx.tx) << ": " << get_weight_string(tx.weight) << ", sending " << print_etn(tx_etn) << " in " << tx.selected_transfers.size() <<
10633 " outputs to " << tx.dsts.size() << " destination(s), including " <<
10634 print_etn(tx.ptx.fee) << " fee, " << print_etn(tx.ptx.change_dts.amount) << " change");
10635 ptx_vector.push_back(tx.ptx);
10636 }
10637
10638 uint64_t a = 0;
10639 for (const TX &tx: txes)
10640 {
10641 for (size_t idx: tx.selected_transfers)
10642 {
10643 a += m_transfers[idx].amount();
10644 }
10645 a -= tx.ptx.fee;
10646 }
10647 std::vector<cryptonote::tx_destination_entry> synthetic_dsts(1, cryptonote::tx_destination_entry("", a, address, is_subaddress));
10648 THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, synthetic_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
10649
10650 // if we made it this far, we're OK to actually send the transactions
10651 return ptx_vector;
10652}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_transactions_single()

std::vector< wallet2::pending_tx > tools::wallet2::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,
const uint64_t unlock_time,
uint32_t priority,
const std::vector< uint8_t > & extra )

Definition at line 10416 of file wallet2.cpp.

10417{
10418 std::vector<size_t> unused_transfers_indices;
10419 std::vector<size_t> unused_dust_indices;
10420 uint8_t tx_version = 1; //todo: 4.0.0.0 leave it as this for now until we update it for sending by chainstate index
10421 const bool use_rct = use_fork_rules(4, 0);
10422 // find output with the given key image (
10423 for (size_t i = 0; i < m_transfers.size(); ++i)
10424 {
10425 const transfer_details& td = m_transfers[i];
10426
10427 if (td.m_key_image_known && td.m_tx.version == 1 && td.m_key_image == ki && !td.m_spent && !td.m_frozen && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
10428 {
10429 if (td.is_rct() || is_valid_decomposed_amount(td.amount()))
10430 unused_transfers_indices.push_back(i);
10431 else
10432 unused_dust_indices.push_back(i);
10433 break;
10434 }
10435 }
10436 return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, tx_version);
10437}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_unmixable_sweep_transactions()

std::vector< wallet2::pending_tx > tools::wallet2::create_unmixable_sweep_transactions ( )

Definition at line 10870 of file wallet2.cpp.

10871{
10872 // From hard fork 1, we don't consider small amounts to be dust anymore
10873 const bool hf1_rules = use_fork_rules(2, 10); // first hard fork has version 2
10874 tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD);
10875
10876 uint8_t tx_version = this->public_transactions_required() ? 3 : 1;
10877 const uint64_t base_fee = get_base_fee();
10878
10879 // may throw
10880 std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
10881 size_t num_dust_outputs = unmixable_outputs.size();
10882
10883 if (num_dust_outputs == 0)
10884 {
10885 return std::vector<wallet2::pending_tx>();
10886 }
10887
10888 // split in "dust" and "non dust" to make it easier to select outputs
10889 std::vector<size_t> unmixable_transfer_outputs, unmixable_dust_outputs;
10890 for (auto n: unmixable_outputs)
10891 {
10892 if (m_transfers[n].amount() < base_fee)
10893 unmixable_dust_outputs.push_back(n);
10894 else
10895 unmixable_transfer_outputs.push_back(n);
10896 }
10897
10898 return create_transactions_from(m_account_public_address, false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>(), tx_version);
10899}
std::vector< size_t > select_available_unmixable_outputs()
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decrypt() [1/2]

template<typename T>
template epee::wipeable_string tools::wallet2::decrypt ( const std::string & ciphertext,
const crypto::secret_key & skey,
bool authenticated ) const

Definition at line 13223 of file wallet2.cpp.

13224{
13225 const size_t prefix_size = sizeof(chacha_iv) + (authenticated ? sizeof(crypto::signature) : 0);
13226 THROW_WALLET_EXCEPTION_IF(ciphertext.size() < prefix_size,
13227 error::wallet_internal_error, "Unexpected ciphertext size");
13228
13229 crypto::chacha_key key;
13230 crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds);
13231 const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0];
13232 if (authenticated)
13233 {
13235 crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash);
13236 crypto::public_key pkey;
13238 const crypto::signature &signature = *(const crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)];
13240 error::wallet_internal_error, "Failed to authenticate ciphertext");
13241 }
13242 std::unique_ptr<char[]> buffer{new char[ciphertext.size() - prefix_size]};
13243 auto wiper = epee::misc_utils::create_scope_leave_handler([&]() { memwipe(buffer.get(), ciphertext.size() - prefix_size); });
13244 crypto::chacha20(ciphertext.data() + sizeof(iv), ciphertext.size() - prefix_size, key, iv, buffer.get());
13245 return T(buffer.get(), ciphertext.size() - prefix_size);
13246}
const char * key
void * memwipe(void *src, size_t n)
bool secret_key_to_public_key(const secret_key &sec, public_key &pub)
Definition crypto.h:262
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
#define T(x)
Here is the call graph for this function:

◆ decrypt() [2/2]

template<typename T = std::string>
T tools::wallet2::decrypt ( const std::string & ciphertext,
const crypto::secret_key & skey,
bool authenticated = true ) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decrypt_keys() [1/2]

void tools::wallet2::decrypt_keys ( const crypto::chacha_key & key)

Definition at line 4752 of file wallet2.cpp.

4753{
4754 m_account.encrypt_viewkey(key);
4755 m_account.decrypt_keys(key);
4756}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decrypt_keys() [2/2]

void tools::wallet2::decrypt_keys ( const epee::wipeable_string & password)

Definition at line 4765 of file wallet2.cpp.

4766{
4767 crypto::chacha_key key;
4768 crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
4770}
const char * data() const noexcept
size_t size() const noexcept
Here is the call graph for this function:

◆ decrypt_with_view_secret_key()

std::string tools::wallet2::decrypt_with_view_secret_key ( const std::string & ciphertext,
bool authenticated = true ) const

Definition at line 13250 of file wallet2.cpp.

13251{
13252 return decrypt(ciphertext, get_account().get_keys().m_view_secret_key, authenticated);
13253}
T decrypt(const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated=true) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ default_mixin() [1/2]

uint32_t tools::wallet2::default_mixin ( ) const
inline

Definition at line 1071 of file wallet2.h.

1071{ return m_default_mixin; }

◆ default_mixin() [2/2]

void tools::wallet2::default_mixin ( uint32_t m)
inline

Definition at line 1072 of file wallet2.h.

1072{ m_default_mixin = m; }

◆ deinit()

bool tools::wallet2::deinit ( )

Definition at line 4031 of file wallet2.cpp.

4032{
4033 m_is_initialized=false;
4035 m_account.deinit();
4036 return true;
4037}
bool unlock_keys_file()
Definition wallet2.cpp:8225
Here is the call graph for this function:
Here is the caller graph for this function:

◆ delete_address_book_row()

bool tools::wallet2::delete_address_book_row ( std::size_t row_id)

Definition at line 3466 of file wallet2.cpp.

3466 {
3467 if(m_address_book.size() <= row_id)
3468 return false;
3469
3470 m_address_book.erase(m_address_book.begin()+row_id);
3471
3472 return true;
3473}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ device_derivation_path() [1/2]

const std::string & tools::wallet2::device_derivation_path ( ) const
inline

Definition at line 1111 of file wallet2.h.

1111{ return m_device_derivation_path; }
Here is the caller graph for this function:

◆ device_derivation_path() [2/2]

void tools::wallet2::device_derivation_path ( const std::string & device_derivation_path)
inline

Definition at line 1112 of file wallet2.h.

1112{ m_device_derivation_path = device_derivation_path; }
const std::string & device_derivation_path() const
Definition wallet2.h:1111
Here is the call graph for this function:

◆ device_derivation_path_option()

std::string tools::wallet2::device_derivation_path_option ( const boost::program_options::variables_map & vm)
static

Definition at line 1188 of file wallet2.cpp.

1189{
1190 return command_line::get_arg(vm, options().hw_device_derivation_path);
1191}
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
Here is the call graph for this function:

◆ device_name() [1/2]

const std::string & tools::wallet2::device_name ( ) const
inline

Definition at line 1109 of file wallet2.h.

1109{ return m_device_name; }
Here is the caller graph for this function:

◆ device_name() [2/2]

void tools::wallet2::device_name ( const std::string & device_name)
inline

Definition at line 1110 of file wallet2.h.

1110{ m_device_name = device_name; }
const std::string & device_name() const
Definition wallet2.h:1109
Here is the call graph for this function:

◆ device_name_option()

std::string tools::wallet2::device_name_option ( const boost::program_options::variables_map & vm)
static

Definition at line 1183 of file wallet2.cpp.

1184{
1185 return command_line::get_arg(vm, options().hw_device);
1186}
Here is the call graph for this function:

◆ discard_unmixable_outputs()

void tools::wallet2::discard_unmixable_outputs ( )

Definition at line 10901 of file wallet2.cpp.

10902{
10903 // may throw
10904 std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
10905 for (size_t idx : unmixable_outputs)
10906 {
10907 freeze(idx);
10908 }
10909}
void freeze(size_t idx)
Definition wallet2.cpp:1584
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dump_tx_to_str()

std::string tools::wallet2::dump_tx_to_str ( const std::vector< pending_tx > & ptx_vector) const

Definition at line 6984 of file wallet2.cpp.

6985{
6986 LOG_PRINT_L0("saving " << ptx_vector.size() << " transactions");
6987 unsigned_tx_set txs;
6988 for (auto &tx: ptx_vector)
6989 {
6990 // Short payment id is encrypted with tx_key.
6991 // Since sign_tx() generates new tx_keys and encrypts the payment id, we need to save the decrypted payment ID
6992 // Save tx construction_data to unsigned_tx_set
6993 txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
6994 }
6995
6996 txs.transfers = export_outputs();
6997 // save as binary
6998 std::ostringstream oss;
6999 boost::archive::portable_binary_oarchive ar(oss);
7000 try
7001 {
7002 ar << txs;
7003 }
7004 catch (...)
7005 {
7006 return std::string();
7007 }
7008 LOG_PRINT_L2("Saving unsigned tx data: " << oss.str());
7009 std::string ciphertext = encrypt_with_view_secret_key(oss.str());
7010
7011 return std::string(UNSIGNED_TX_PREFIX) + ciphertext;
7012}
std::pair< size_t, std::vector< tools::wallet2::transfer_details > > export_outputs(bool all=false) const
std::string encrypt_with_view_secret_key(const std::string &plaintext, bool authenticated=true) const
#define UNSIGNED_TX_PREFIX
Here is the call graph for this function:
Here is the caller graph for this function:

◆ enable_dns()

void tools::wallet2::enable_dns ( bool enable)
inline

Definition at line 1383 of file wallet2.h.

1383{ m_use_dns = enable; }

◆ encrypt() [1/4]

std::string tools::wallet2::encrypt ( const char * plaintext,
size_t len,
const crypto::secret_key & skey,
bool authenticated = true ) const

Definition at line 13181 of file wallet2.cpp.

13182{
13183 crypto::chacha_key key;
13184 crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds);
13185 std::string ciphertext;
13186 crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>();
13187 ciphertext.resize(len + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0));
13188 crypto::chacha20(plaintext, len, key, iv, &ciphertext[sizeof(iv)]);
13189 memcpy(&ciphertext[0], &iv, sizeof(iv));
13190 if (authenticated)
13191 {
13193 crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash);
13194 crypto::public_key pkey;
13196 crypto::signature &signature = *(crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)];
13198 }
13199 return ciphertext;
13200}
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig)
Definition crypto.h:292
std::enable_if< std::is_pod< T >::value, T >::type rand()
Definition crypto.h:216
Here is the call graph for this function:
Here is the caller graph for this function:

◆ encrypt() [2/4]

std::string tools::wallet2::encrypt ( const epee::span< char > & span,
const crypto::secret_key & skey,
bool authenticated = true ) const
Here is the call graph for this function:

◆ encrypt() [3/4]

std::string tools::wallet2::encrypt ( const epee::wipeable_string & plaintext,
const crypto::secret_key & skey,
bool authenticated = true ) const

Definition at line 13212 of file wallet2.cpp.

13213{
13214 return encrypt(plaintext.data(), plaintext.size(), skey, authenticated);
13215}
std::string encrypt(const char *plaintext, size_t len, const crypto::secret_key &skey, bool authenticated=true) const
Here is the call graph for this function:

◆ encrypt() [4/4]

std::string tools::wallet2::encrypt ( const std::string & plaintext,
const crypto::secret_key & skey,
bool authenticated = true ) const

Definition at line 13207 of file wallet2.cpp.

13208{
13209 return encrypt(plaintext.data(), plaintext.size(), skey, authenticated);
13210}
Here is the call graph for this function:

◆ encrypt_keys() [1/2]

void tools::wallet2::encrypt_keys ( const crypto::chacha_key & key)

Definition at line 4746 of file wallet2.cpp.

4747{
4748 m_account.encrypt_keys(key);
4749 m_account.decrypt_viewkey(key);
4750}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ encrypt_keys() [2/2]

void tools::wallet2::encrypt_keys ( const epee::wipeable_string & password)

Definition at line 4758 of file wallet2.cpp.

4759{
4760 crypto::chacha_key key;
4761 crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
4763}
void encrypt_keys(const crypto::chacha_key &key)
Definition wallet2.cpp:4746
Here is the call graph for this function:

◆ encrypt_with_view_secret_key()

std::string tools::wallet2::encrypt_with_view_secret_key ( const std::string & plaintext,
bool authenticated = true ) const

Definition at line 13217 of file wallet2.cpp.

13218{
13219 return encrypt(plaintext, get_account().get_keys().m_view_secret_key, authenticated);
13220}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ estimate_backlog() [1/2]

std::vector< std::pair< uint64_t, uint64_t > > tools::wallet2::estimate_backlog ( const std::vector< std::pair< double, double > > & fee_levels)

Definition at line 13489 of file wallet2.cpp.

13490{
13491 for (const auto &fee_level: fee_levels)
13492 {
13493 THROW_WALLET_EXCEPTION_IF(fee_level.first == 0.0, error::wallet_internal_error, "Invalid 0 fee");
13494 THROW_WALLET_EXCEPTION_IF(fee_level.second == 0.0, error::wallet_internal_error, "Invalid 0 fee");
13495 }
13496
13497 // get txpool backlog
13500 m_daemon_rpc_mutex.lock();
13501 bool r = invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, rpc_timeout);
13502 m_daemon_rpc_mutex.unlock();
13503 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "Failed to connect to daemon");
13504 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog");
13505 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
13506
13507 uint64_t block_weight_limit = 0;
13508 const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
13509 throw_on_rpc_response_error(result, "get_info");
13510 uint64_t full_reward_zone = block_weight_limit / 2;
13511 THROW_WALLET_EXCEPTION_IF(full_reward_zone == 0, error::wallet_internal_error, "Invalid block weight limit from daemon");
13512
13513 std::vector<std::pair<uint64_t, uint64_t>> blocks;
13514 for (const auto &fee_level: fee_levels)
13515 {
13516 const double our_fee_byte_min = fee_level.first;
13517 const double our_fee_byte_max = fee_level.second;
13518 uint64_t priority_weight_min = 0, priority_weight_max = 0;
13519 for (const auto &i: res.backlog)
13520 {
13521 if (i.weight == 0)
13522 {
13523 MWARNING("Got 0 weight tx from txpool, ignored");
13524 continue;
13525 }
13526 double this_fee_byte = i.fee / (double)i.weight;
13527 if (this_fee_byte >= our_fee_byte_min)
13528 priority_weight_min += i.weight;
13529 if (this_fee_byte >= our_fee_byte_max)
13530 priority_weight_max += i.weight;
13531 }
13532
13533 uint64_t nblocks_min = priority_weight_min / full_reward_zone;
13534 uint64_t nblocks_max = priority_weight_max / full_reward_zone;
13535 MDEBUG("estimate_backlog: priority_weight " << priority_weight_min << " - " << priority_weight_max << " for "
13536 << our_fee_byte_min << " - " << our_fee_byte_max << " piconero byte fee, "
13537 << nblocks_min << " - " << nblocks_max << " blocks at block weight " << full_reward_zone);
13538 blocks.push_back(std::make_pair(nblocks_min, nblocks_max));
13539 }
13540 return blocks;
13541}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ estimate_backlog() [2/2]

std::vector< std::pair< uint64_t, uint64_t > > tools::wallet2::estimate_backlog ( uint64_t min_tx_weight,
uint64_t max_tx_weight,
const std::vector< uint64_t > & fees )

Definition at line 13543 of file wallet2.cpp.

13544{
13545 THROW_WALLET_EXCEPTION_IF(min_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
13546 THROW_WALLET_EXCEPTION_IF(max_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
13547 for (uint64_t fee: fees)
13548 {
13549 THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee");
13550 }
13551 std::vector<std::pair<double, double>> fee_levels;
13552 for (uint64_t fee: fees)
13553 {
13554 double our_fee_byte_min = fee / (double)min_tx_weight, our_fee_byte_max = fee / (double)max_tx_weight;
13555 fee_levels.emplace_back(our_fee_byte_min, our_fee_byte_max);
13556 }
13557 return estimate_backlog(fee_levels);
13558}
Here is the call graph for this function:

◆ estimate_blockchain_height()

uint64_t tools::wallet2::estimate_blockchain_height ( )

Definition at line 4990 of file wallet2.cpp.

4991 {
4992 // -1 month for fluctuations in block time and machine date/time setup.
4993 // avg seconds per block
4994 const int seconds_per_block = DIFFICULTY_TARGET_V6;
4995 // ~num blocks per month
4996 const uint64_t blocks_per_month = 60*60*24*30/seconds_per_block;
4997
4998 // try asking the daemon first
4999 std::string err;
5000 uint64_t height = 0;
5001
5002 // we get the max of approximated height and local height.
5003 // approximated height is the least of daemon target height
5004 // (the max of what the other daemons are claiming is their
5005 // height) and the theoretical height based on the local
5006 // clock. This will be wrong only if both the local clock
5007 // is bad *and* a peer daemon claims a highest height than
5008 // the real chain.
5009 // local height is the height the local daemon is currently
5010 // synced to, it will be lower than the real chain height if
5011 // the daemon is currently syncing.
5012 // If we use the approximate height we subtract one month as
5013 // a safety margin.
5015 uint64_t target_height = get_daemon_blockchain_target_height(err);
5016 if (err.empty()) {
5017 if (target_height < height)
5018 height = target_height;
5019 } else {
5020 // if we couldn't talk to the daemon, check safety margin.
5021 if (height > blocks_per_month)
5022 height -= blocks_per_month;
5023 else
5024 height = 0;
5025 }
5026 uint64_t local_height = get_daemon_blockchain_height(err);
5027 if (err.empty() && local_height > height)
5028 height = local_height;
5029 return height;
5030 }
uint64_t get_daemon_blockchain_target_height(std::string &err)
uint64_t get_approximate_blockchain_height() const
Calculates the approximate blockchain height from current date/time.
#define DIFFICULTY_TARGET_V6
Here is the call graph for this function:
Here is the caller graph for this function:

◆ exchange_multisig_keys() [1/2]

std::string tools::wallet2::exchange_multisig_keys ( const epee::wipeable_string & password,
const std::vector< std::string > & info )

Definition at line 5280 of file wallet2.cpp.

5282{
5284 error::wallet_internal_error, "Empty multisig info");
5285
5286 if (info[0].substr(0, MULTISIG_EXTRA_INFO_MAGIC.size()) != MULTISIG_EXTRA_INFO_MAGIC)
5287 {
5289 error::wallet_internal_error, "Unsupported info string");
5290 }
5291
5292 std::vector<crypto::public_key> signers;
5293 std::unordered_set<crypto::public_key> pkeys;
5294
5295 THROW_WALLET_EXCEPTION_IF(!unpack_extra_multisig_info(info, signers, pkeys),
5296 error::wallet_internal_error, "Bad extra multisig info");
5297
5298 return exchange_multisig_keys(password, pkeys, signers);
5299}
std::string exchange_multisig_keys(const epee::wipeable_string &password, const std::vector< std::string > &info)
Definition wallet2.cpp:5280
CXA_THROW_INFO_T * info
Here is the call graph for this function:
Here is the caller graph for this function:

◆ exchange_multisig_keys() [2/2]

std::string tools::wallet2::exchange_multisig_keys ( const epee::wipeable_string & password,
std::unordered_set< crypto::public_key > pkeys,
std::vector< crypto::public_key > signers )

Any but first round of keys exchange.

Definition at line 5301 of file wallet2.cpp.

5304{
5305 CHECK_AND_ASSERT_THROW_MES(!derivations.empty(), "empty pkeys");
5306 CHECK_AND_ASSERT_THROW_MES(!signers.empty(), "empty signers");
5307
5308 bool ready = false;
5309 CHECK_AND_ASSERT_THROW_MES(multisig(&ready), "The wallet is not multisig");
5310 CHECK_AND_ASSERT_THROW_MES(!ready, "Multisig wallet creation process has already been finished");
5311
5312 // keys are decrypted
5314 if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
5315 {
5316 crypto::chacha_key chacha_key;
5317 crypto::generate_chacha_key(password.data(), password.size(), chacha_key, m_kdf_rounds);
5318 m_account.encrypt_viewkey(chacha_key);
5319 m_account.decrypt_keys(chacha_key);
5320 keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this, chacha_key]() { m_account.encrypt_keys(chacha_key); m_account.decrypt_viewkey(chacha_key); });
5321 }
5322
5323 if (m_multisig_rounds_passed == multisig_rounds_required(m_multisig_signers.size(), m_multisig_threshold) - 1)
5324 {
5325 // the last round is passed and we have to calculate spend public key
5326 // add ours if not included
5328
5329 if (std::find(signers.begin(), signers.end(), local_signer) == signers.end())
5330 {
5331 signers.push_back(local_signer);
5332 for (const auto &msk: get_account().get_multisig_keys())
5333 {
5334 derivations.insert(rct::rct2pk(rct::scalarmultBase(rct::sk2rct(msk))));
5335 }
5336 }
5337
5338 CHECK_AND_ASSERT_THROW_MES(signers.size() == m_multisig_signers.size(), "Bad signers size");
5339
5340 // Summing all of unique public multisig keys to calculate common public spend key
5341 crypto::public_key spend_public_key = cryptonote::generate_multisig_M_N_spend_public_key(std::vector<crypto::public_key>(derivations.begin(), derivations.end()));
5342 m_account_public_address.m_spend_public_key = spend_public_key;
5343 m_account.finalize_multisig(spend_public_key);
5344
5345 m_multisig_signers = signers;
5346 std::sort(m_multisig_signers.begin(), m_multisig_signers.end(), [](const crypto::public_key &e0, const crypto::public_key &e1){ return memcmp(&e0, &e1, sizeof(e0)); });
5347
5348 ++m_multisig_rounds_passed;
5349 m_multisig_derivations.clear();
5350
5351 // keys are encrypted again
5352 keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
5353
5354 if (!m_wallet_file.empty())
5355 {
5356 bool r = store_keys(m_keys_file, password, false);
5358
5359 if (boost::filesystem::exists(m_wallet_file + ".address.txt"))
5360 {
5361 r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
5362 if(!r) MERROR("String with address text not saved");
5363 }
5364 }
5365
5366 m_subaddresses.clear();
5367 m_subaddress_labels.clear();
5368 add_subaddress_account(tr("Primary account"));
5369
5370 if (!m_wallet_file.empty())
5371 store();
5372
5373 return {};
5374 }
5375
5376 // Below are either middle or secret spend key establishment rounds
5377
5378 for (const auto& key: m_multisig_derivations)
5379 derivations.erase(key);
5380
5381 // Deriving multisig keys (set of Mi = b * Bi) according to DH from other participants' multisig keys.
5382 auto new_derivations = cryptonote::generate_multisig_derivations(get_account().get_keys(), std::vector<crypto::public_key>(derivations.begin(), derivations.end()));
5383
5384 std::string extra_multisig_info;
5385 if (m_multisig_rounds_passed == multisig_rounds_required(m_multisig_signers.size(), m_multisig_threshold) - 2) // next round is last
5386 {
5387 // Next round is last therefore we are performing secret spend establishment round as described above.
5388 MINFO("Creating spend key...");
5389
5390 // Calculating our secret multisig keys by hashing our public multisig keys.
5391 auto multisig_keys = cryptonote::calculate_multisig_keys(std::vector<crypto::public_key>(new_derivations.begin(), new_derivations.end()));
5392 // And summing it to get personal secret spend key
5394
5395 m_account.make_multisig(m_account.get_keys().m_view_secret_key, spend_skey, rct::rct2pk(rct::identity()), multisig_keys);
5396
5397 // Packing public multisig keys to exchange with others and calculate common public spend key in the last round
5398 extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, secret_keys_to_public_keys(multisig_keys), spend_skey);
5399 }
5400 else
5401 {
5402 // This is just middle round
5403 MINFO("Preparing keys for next exchange round...");
5404 extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, new_derivations, m_account.get_keys().m_spend_secret_key);
5405 m_multisig_derivations = new_derivations;
5406 }
5407
5408 ++m_multisig_rounds_passed;
5409
5410 create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
5411 return extra_multisig_info;
5412}
void add_subaddress_account(const std::string &label, const bool update_account_tags=true)
Definition wallet2.cpp:1463
crypto::public_key get_multisig_signer_public_key() const
bool multisig(bool *ready=NULL, uint32_t *threshold=NULL, uint32_t *total=NULL) const
Definition wallet2.cpp:5634
#define tr(x)
crypto::secret_key calculate_multisig_signer_key(const std::vector< crypto::secret_key > &multisig_keys)
Definition multisig.cpp:100
crypto::public_key generate_multisig_M_N_spend_public_key(const std::vector< crypto::public_key > &pkeys)
generate_multisig_M_N_spend_public_key calculates multisig wallet's spend public key by summing all o...
Definition multisig.cpp:132
uint32_t multisig_rounds_required(uint32_t participants, uint32_t threshold)
Definition multisig.cpp:181
std::vector< crypto::public_key > generate_multisig_derivations(const account_keys &keys, const std::vector< crypto::public_key > &derivations)
generate_multisig_derivations performs common DH key derivation. Each middle round in M/N scheme is D...
Definition multisig.cpp:87
std::vector< crypto::secret_key > calculate_multisig_keys(const std::vector< crypto::public_key > &derivations)
calculate_multisig_keys. Calculates secret multisig keys from others' participants ones as follows: m...
Definition multisig.cpp:111
bool save_string_to_file(const std::string &path_to_file, const std::string &str)
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
void scalarmultBase(key &aG, const key &a)
Definition rctOps.cpp:350
key identity()
Definition rctOps.h:73
file_error_base< file_save_error_message_index > file_save_error
Here is the call graph for this function:

◆ expand_subaddresses()

void tools::wallet2::expand_subaddresses ( const cryptonote::subaddress_index & index,
const bool udpate_account_tags = true )

Definition at line 1478 of file wallet2.cpp.

1479{
1480 hw::device &hwdev = m_account.get_device();
1481 if (m_subaddress_labels.size() <= index.major)
1482 {
1483 // add new accounts
1484 cryptonote::subaddress_index index2;
1485 const uint32_t major_end = get_subaddress_clamped_sum(index.major, m_subaddress_lookahead_major);
1486 for (index2.major = m_subaddress_labels.size(); index2.major < major_end; ++index2.major)
1487 {
1488 const uint32_t end = get_subaddress_clamped_sum((index2.major == index.major ? index.minor : 0), m_subaddress_lookahead_minor);
1489 const std::vector<crypto::public_key> pkeys = hwdev.get_subaddress_spend_public_keys(m_account.get_keys(), index2.major + (index2.major != 0 ? m_account_major_offset : 0), 0, end);
1490 for (index2.minor = 0; index2.minor < end; ++index2.minor)
1491 {
1492 const crypto::public_key &D = pkeys[index2.minor];
1493 m_subaddresses[D] = index2;
1494 }
1495 }
1496 m_subaddress_labels.resize(index.major + 1, {"Untitled account"});
1497 m_subaddress_labels[index.major].resize(index.minor + 1);
1498
1499 if(update_account_tags)
1501 }
1502 else if (m_subaddress_labels[index.major].size() <= index.minor)
1503 {
1504 // add new subaddresses
1505 const uint32_t end = get_subaddress_clamped_sum(index.minor, m_subaddress_lookahead_minor);
1506 const uint32_t begin = m_subaddress_labels[index.major].size();
1507 cryptonote::subaddress_index index2 = {index.major, begin};
1508 const std::vector<crypto::public_key> pkeys = hwdev.get_subaddress_spend_public_keys(m_account.get_keys(), index2.major + (index2.major != 0 ? m_account_major_offset : 0), index2.minor, end);
1509 for (; index2.minor < end; ++index2.minor)
1510 {
1511 const crypto::public_key &D = pkeys[index2.minor - begin];
1512 m_subaddresses[D] = index2;
1513 }
1514 m_subaddress_labels[index.major].resize(index.minor + 1);
1515 }
1516}
virtual std::vector< crypto::public_key > get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end)=0
const std::pair< std::map< std::string, std::string >, std::vector< std::string > > & get_account_tags()
Get the list of registered account tags.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ explicit_refresh_from_block_height() [1/2]

bool tools::wallet2::explicit_refresh_from_block_height ( ) const
inline

Definition at line 746 of file wallet2.h.

746{return m_explicit_refresh_from_block_height;}

◆ explicit_refresh_from_block_height() [2/2]

void tools::wallet2::explicit_refresh_from_block_height ( bool expl)
inline

Definition at line 745 of file wallet2.h.

745{m_explicit_refresh_from_block_height = expl;}

◆ export_blockchain()

std::tuple< size_t, crypto::hash, std::vector< crypto::hash > > tools::wallet2::export_blockchain ( ) const

Definition at line 12691 of file wallet2.cpp.

12692{
12693 std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> bc;
12694 std::get<0>(bc) = m_blockchain.offset();
12695 std::get<1>(bc) = m_blockchain.empty() ? crypto::null_hash: m_blockchain.genesis();
12696 for (size_t n = m_blockchain.offset(); n < m_blockchain.size(); ++n)
12697 {
12698 std::get<2>(bc).push_back(m_blockchain[n]);
12699 }
12700 return bc;
12701}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ export_key_images() [1/2]

std::pair< size_t, std::vector< std::pair< crypto::key_image, crypto::signature > > > tools::wallet2::export_key_images ( bool all = false) const

Definition at line 12221 of file wallet2.cpp.

12222{
12223 PERF_TIMER(export_key_images_raw);
12224 std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
12225
12226 size_t offset = 0;
12227 if (!all)
12228 {
12229 while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_request)
12230 ++offset;
12231 }
12232
12233 ski.reserve(m_transfers.size() - offset);
12234 for (size_t n = offset; n < m_transfers.size(); ++n)
12235 {
12236 const transfer_details &td = m_transfers[n];
12237
12238 // get ephemeral public key
12239 const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index];
12240 THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error,
12241 "Output is not txout_to_key");
12242 const cryptonote::txout_to_key &o = boost::get<const cryptonote::txout_to_key>(out.target);
12243 const crypto::public_key pkey = o.key;
12244
12245 // get tx pub key
12246 std::vector<tx_extra_field> tx_extra_fields;
12247 if(!parse_tx_extra(td.m_tx.extra, tx_extra_fields))
12248 {
12249 // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
12250 }
12251
12253 const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
12254
12255 // generate ephemeral secret key
12257 cryptonote::keypair in_ephemeral;
12258 bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device(), m_account_major_offset);
12259 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
12260
12261 THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image,
12262 error::wallet_internal_error, "key_image generated not matched with cached key image");
12263 THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != pkey,
12264 error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
12265
12266 // sign the key image with the output secret key
12268 std::vector<const crypto::public_key*> key_ptrs;
12269 key_ptrs.push_back(&pkey);
12270
12271 crypto::generate_ring_signature((const crypto::hash&)td.m_key_image, td.m_key_image, key_ptrs, in_ephemeral.sec, 0, &signature);
12272
12273 ski.push_back(std::make_pair(td.m_key_image, signature));
12274 }
12275 return std::make_pair(offset, ski);
12276}
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const
void generate_ring_signature(const hash &prefix_hash, const key_image &image, const public_key *const *pubs, std::size_t pubs_count, const secret_key &sec, std::size_t sec_index, signature *sig)
Definition crypto.h:327
bool generate_key_image_helper(const account_keys &ack, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, const crypto::public_key &out_key, const crypto::public_key &tx_public_key, const std::vector< crypto::public_key > &additional_tx_public_keys, size_t real_output_index, keypair &in_ephemeral, crypto::key_image &ki, hw::device &hwdev, const uint32_t account_major_offset)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
#define PERF_TIMER(name)
Definition perf_timer.h:82
crypto::secret_key sec
crypto::public_key pub
Here is the call graph for this function:

◆ export_key_images() [2/2]

bool tools::wallet2::export_key_images ( const std::string & filename) const

Definition at line 12191 of file wallet2.cpp.

12192{
12194 std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images();
12195 std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC));
12196 const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
12197 const uint32_t offset = ski.first;
12198
12199 std::string data;
12200 data.reserve(4 + ski.second.size() * (sizeof(crypto::key_image) + sizeof(crypto::signature)) + 2 * sizeof(crypto::public_key));
12201 data.resize(4);
12202 data[0] = offset & 0xff;
12203 data[1] = (offset >> 8) & 0xff;
12204 data[2] = (offset >> 16) & 0xff;
12205 data[3] = (offset >> 24) & 0xff;
12206 data += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
12207 data += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
12208 for (const auto &i: ski.second)
12209 {
12210 data += std::string((const char *)&i.first, sizeof(crypto::key_image));
12211 data += std::string((const char *)&i.second, sizeof(crypto::signature));
12212 }
12213
12214 // encrypt data, keep magic plaintext
12215 PERF_TIMER(export_key_images_encrypt);
12216 std::string ciphertext = encrypt_with_view_secret_key(data);
12217 return epee::file_io_utils::save_string_to_file(filename, magic + ciphertext);
12218}
const account_keys & get_keys() const
Definition account.cpp:264
bool export_key_images(const std::string &filename) const
account_public_address m_account_address
Definition account.h:43
#define KEY_IMAGE_EXPORT_FILE_MAGIC
Definition wallet2.cpp:123
Here is the call graph for this function:
Here is the caller graph for this function:

◆ export_multisig()

cryptonote::blobdata tools::wallet2::export_multisig ( )

Export multisig info This will generate and remember new k values

Definition at line 12994 of file wallet2.cpp.

12995{
12996 std::vector<tools::wallet2::multisig_info> info;
12997
12999
13000 info.resize(m_transfers.size());
13001 for (size_t n = 0; n < m_transfers.size(); ++n)
13002 {
13003 transfer_details &td = m_transfers[n];
13005 td.m_multisig_k.clear();
13006 info[n].m_LR.clear();
13007 info[n].m_partial_key_images.clear();
13008
13009 for (size_t m = 0; m < get_account().get_multisig_keys().size(); ++m)
13010 {
13011 // we want to export the partial key image, not the full one, so we can't use td.m_key_image
13012 bool r = generate_multisig_key_image(get_account().get_keys(), m, td.get_public_key(), ki);
13013 CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate key image");
13014 info[n].m_partial_key_images.push_back(ki);
13015 }
13016
13017 // Wallet tries to create as many transactions as many signers combinations. We calculate the maximum number here as follows:
13018 // if we have 2/4 wallet with signers: A, B, C, D and A is a transaction creator it will need to pick up 1 signer from 3 wallets left.
13019 // That means counting combinations for excluding 2-of-3 wallets (k = total signers count - threshold, n = total signers count - 1).
13020 size_t nlr = tools::combinations_count(m_multisig_signers.size() - m_multisig_threshold, m_multisig_signers.size() - 1);
13021 for (size_t m = 0; m < nlr; ++m)
13022 {
13023 td.m_multisig_k.push_back(rct::skGen());
13024 const rct::multisig_kLRki kLRki = get_multisig_kLRki(n, td.m_multisig_k.back());
13025 info[n].m_LR.push_back({kLRki.L, kLRki.R});
13026 }
13027
13028 info[n].m_signer = signer;
13029 }
13030
13031 std::stringstream oss;
13032 boost::archive::portable_binary_oarchive ar(oss);
13033 ar << info;
13034
13035 const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
13036 std::string header;
13037 header += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
13038 header += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
13039 header += std::string((const char *)&signer, sizeof(crypto::public_key));
13040 std::string ciphertext = encrypt_with_view_secret_key(header + oss.str());
13041
13042 return MULTISIG_EXPORT_FILE_MAGIC + ciphertext;
13043}
const std::vector< crypto::secret_key > & get_multisig_keys() const
Definition account.h:102
bool generate_multisig_key_image(const account_keys &keys, size_t multisig_key_index, const crypto::public_key &out_key, crypto::key_image &ki)
Definition multisig.cpp:142
key skGen()
Definition rctOps.cpp:258
uint64_t combinations_count(uint32_t k, uint32_t n)
std::vector< rct::key > m_multisig_k
Definition wallet2.h:320
#define MULTISIG_EXPORT_FILE_MAGIC
Definition wallet2.cpp:125
Here is the call graph for this function:
Here is the caller graph for this function:

◆ export_outputs()

std::pair< size_t, std::vector< tools::wallet2::transfer_details > > tools::wallet2::export_outputs ( bool all = false) const

Definition at line 12723 of file wallet2.cpp.

12724{
12726 std::vector<tools::wallet2::transfer_details> outs;
12727
12728 size_t offset = 0;
12729 if (!all)
12730 while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
12731 ++offset;
12732
12733 outs.reserve(m_transfers.size() - offset);
12734 for (size_t n = offset; n < m_transfers.size(); ++n)
12735 {
12736 const transfer_details &td = m_transfers[n];
12737
12738 outs.push_back(td);
12739 }
12740
12741 return std::make_pair(offset, outs);
12742}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ export_outputs_to_str()

std::string tools::wallet2::export_outputs_to_str ( bool all = false) const

Definition at line 12744 of file wallet2.cpp.

12745{
12747
12748 std::stringstream oss;
12749 boost::archive::portable_binary_oarchive ar(oss);
12750 const auto& outputs = export_outputs(all);
12751 ar << outputs;
12752
12753 std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC));
12754 const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
12755 std::string header;
12756 header += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
12757 header += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
12758 PERF_TIMER(export_outputs_encryption);
12759 std::string ciphertext = encrypt_with_view_secret_key(header + oss.str());
12760 return magic + ciphertext;
12761}
std::string export_outputs_to_str(bool all=false) const
#define OUTPUT_EXPORT_FILE_MAGIC
Here is the call graph for this function:
Here is the caller graph for this function:

◆ export_payments()

wallet2::payment_container tools::wallet2::export_payments ( ) const

Definition at line 12665 of file wallet2.cpp.

12666{
12667 payment_container payments;
12668 for (auto const &p : m_payments)
12669 {
12670 payments.emplace(p);
12671 }
12672 return payments;
12673}
std::unordered_multimap< crypto::hash, payment_details > payment_container
Definition wallet2.h:450
Here is the call graph for this function:
Here is the caller graph for this function:

◆ finalize_multisig() [1/2]

bool tools::wallet2::finalize_multisig ( const epee::wipeable_string & password,
const std::unordered_set< crypto::public_key > & pkeys,
std::vector< crypto::public_key > signers )

Finalizes creation of a multisig wallet.

Definition at line 5476 of file wallet2.cpp.

5477{
5478 bool ready;
5479 uint32_t threshold, total;
5480 if (!multisig(&ready, &threshold, &total))
5481 {
5482 MERROR("This is not a multisig wallet");
5483 return false;
5484 }
5485 if (ready)
5486 {
5487 MERROR("This multisig wallet is already finalized");
5488 return false;
5489 }
5490 if (threshold + 1 != total)
5491 {
5492 MERROR("finalize_multisig should only be used for N-1/N wallets, use exchange_multisig_keys instead");
5493 return false;
5494 }
5495 exchange_multisig_keys(password, pkeys, signers);
5496 return true;
5497}
uint8_t threshold
Here is the call graph for this function:

◆ finalize_multisig() [2/2]

bool tools::wallet2::finalize_multisig ( const epee::wipeable_string & password,
const std::vector< std::string > & info )

Finalizes creation of a multisig wallet.

Definition at line 5516 of file wallet2.cpp.

5517{
5518 std::unordered_set<crypto::public_key> public_keys;
5519 std::vector<crypto::public_key> signers;
5520 if (!unpack_extra_multisig_info(info, signers, public_keys))
5521 {
5522 MERROR("Bad multisig info");
5523 return false;
5524 }
5525
5526 return finalize_multisig(password, public_keys, signers);
5527}
bool finalize_multisig(const epee::wipeable_string &password, const std::vector< std::string > &info)
Finalizes creation of a multisig wallet.
Definition wallet2.cpp:5516
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_and_save_rings()

bool tools::wallet2::find_and_save_rings ( bool force = true)

Definition at line 8109 of file wallet2.cpp.

8110{
8111 if (!force && m_ring_history_saved)
8112 return true;
8113 if (!m_ringdb)
8114 return false;
8115
8118
8119 MDEBUG("Finding and saving rings...");
8120
8121 // get payments we made
8122 std::vector<crypto::hash> txs_hashes;
8123 std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> payments;
8124 get_payments_out(payments, 0, std::numeric_limits<uint64_t>::max(), boost::none, std::set<uint32_t>());
8125 for (const std::pair<crypto::hash,wallet2::confirmed_transfer_details> &entry: payments)
8126 {
8127 const crypto::hash &txid = entry.first;
8128 txs_hashes.push_back(txid);
8129 }
8130
8131 MDEBUG("Found " << std::to_string(txs_hashes.size()) << " transactions");
8132
8133 // get those transactions from the daemon
8134 auto it = txs_hashes.begin();
8135 static const size_t SLICE_SIZE = 200;
8136 for (size_t slice = 0; slice < txs_hashes.size(); slice += SLICE_SIZE)
8137 {
8138 req.decode_as_json = false;
8139 req.prune = true;
8140 req.txs_hashes.clear();
8141 size_t ntxes = slice + SLICE_SIZE > txs_hashes.size() ? txs_hashes.size() - slice : SLICE_SIZE;
8142 for (size_t s = slice; s < slice + ntxes; ++s)
8143 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txs_hashes[s]));
8144 bool r;
8145 {
8146 const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
8147 r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
8148 }
8149 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
8150 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
8151 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
8152 THROW_WALLET_EXCEPTION_IF(res.txs.size() != req.txs_hashes.size(), error::wallet_internal_error,
8153 "daemon returned wrong response for gettransactions, wrong txs count = " +
8154 std::to_string(res.txs.size()) + ", expected " + std::to_string(req.txs_hashes.size()));
8155
8156 MDEBUG("Scanning " << res.txs.size() << " transactions");
8157 THROW_WALLET_EXCEPTION_IF(slice + res.txs.size() > txs_hashes.size(), error::wallet_internal_error, "Unexpected tx array size");
8158 for (size_t i = 0; i < res.txs.size(); ++i, ++it)
8159 {
8160 const auto &tx_info = res.txs[i];
8161 cryptonote::transaction tx;
8162 crypto::hash tx_hash;
8163 THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(tx_info, tx, tx_hash), error::wallet_internal_error,
8164 "Failed to get transaction from daemon");
8165 THROW_WALLET_EXCEPTION_IF(!(tx_hash == *it), error::wallet_internal_error, "Wrong txid received");
8166 THROW_WALLET_EXCEPTION_IF(!add_rings(get_ringdb_key(), tx), error::wallet_internal_error, "Failed to save ring");
8167 }
8168 }
8169
8170 MINFO("Found and saved rings for " << txs_hashes.size() << " transactions");
8171 m_ring_history_saved = true;
8172 return true;
8173}
void get_payments_out(std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > &confirmed_payments, uint64_t min_height, uint64_t max_height=(uint64_t) -1, const boost::optional< uint32_t > &subaddr_account=boost::none, const std::set< uint32_t > &subaddr_indices={}) const
Definition wallet2.cpp:6346
Here is the call graph for this function:
Here is the caller graph for this function:

◆ finish_rescan_bc_keep_key_images()

void tools::wallet2::finish_rescan_bc_keep_key_images ( uint64_t transfer_height,
const crypto::hash & hash )

Definition at line 13734 of file wallet2.cpp.

13735{
13736 // Compute hash of m_transfers, if differs there had to be BC reorg.
13737 crypto::hash new_transfers_hash{};
13738 hash_m_transfers((int64_t) transfer_height, new_transfers_hash);
13739
13740 if (new_transfers_hash != hash)
13741 {
13742 // Soft-Reset to avoid inconsistency in case of BC reorg.
13743 clear_soft(false); // keep_key_images works only with soft reset.
13744 THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Transfers changed during rescan, soft or hard rescan is needed");
13745 }
13746
13747 // Restore key images in m_transfers from m_key_images
13748 for(auto it = m_key_images.begin(); it != m_key_images.end(); it++)
13749 {
13750 THROW_WALLET_EXCEPTION_IF(it->second >= m_transfers.size(), error::wallet_internal_error, "Key images cache contains illegal transfer offset");
13751 m_transfers[it->second].m_key_image = it->first;
13752 m_transfers[it->second].m_key_image_known = true;
13753 }
13754}
uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const
signed __int64 int64_t
Definition stdint.h:135
Here is the call graph for this function:
Here is the caller graph for this function:

◆ freeze() [1/2]

void tools::wallet2::freeze ( const crypto::key_image & ki)

Definition at line 1605 of file wallet2.cpp.

1606{
1608}
const transfer_details & get_transfer_details(size_t idx) const
Here is the call graph for this function:

◆ freeze() [2/2]

void tools::wallet2::freeze ( size_t idx)

Definition at line 1584 of file wallet2.cpp.

1585{
1586 CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
1587 transfer_details &td = m_transfers[idx];
1588 td.m_frozen = true;
1589}
Here is the caller graph for this function:

◆ frozen() [1/3]

bool tools::wallet2::frozen ( const crypto::key_image & ki) const

Definition at line 1615 of file wallet2.cpp.

1616{
1617 return frozen(get_transfer_details(ki));
1618}
bool frozen(size_t idx) const
Definition wallet2.cpp:1598
Here is the call graph for this function:

◆ frozen() [2/3]

bool tools::wallet2::frozen ( const transfer_details & td) const

Definition at line 1631 of file wallet2.cpp.

1632{
1633 return td.m_frozen;
1634}

◆ frozen() [3/3]

bool tools::wallet2::frozen ( size_t idx) const

Definition at line 1598 of file wallet2.cpp.

1599{
1600 CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
1601 const transfer_details &td = m_transfers[idx];
1602 return td.m_frozen;
1603}
Here is the caller graph for this function:

◆ generate() [1/4]

crypto::secret_key tools::wallet2::generate ( const std::string & wallet,
const epee::wipeable_string & password,
const crypto::secret_key & recovery_param = crypto::secret_key(),
bool recover = false,
bool two_random = false,
bool create_address_file = false )

Generates a wallet or restores one.

Parameters
wallet_Name of wallet file
passwordPassword of wallet file
recovery_paramIf it is a restore, the recovery key
recoverWhether it is a restore
two_randomWhether it is a non-deterministic wallet
create_address_fileWhether to create an address file
Returns
The secret key of the generated wallet

◆ generate() [2/4]

void tools::wallet2::generate ( const std::string & wallet,
const epee::wipeable_string & password,
const cryptonote::account_public_address & account_public_address,
const crypto::secret_key & spendkey,
const crypto::secret_key & viewkey,
bool create_address_file = false )

Creates a wallet from a public address and a spend/view secret key pair.

Parameters
wallet_Name of wallet file
passwordPassword of wallet file
account_public_addressThe account's public address
spendkeyspend secret key
viewkeyview secret key
create_address_fileWhether to create an address file

◆ generate() [3/4]

void tools::wallet2::generate ( const std::string & wallet,
const epee::wipeable_string & password,
const cryptonote::account_public_address & account_public_address,
const crypto::secret_key & viewkey = crypto::secret_key(),
bool create_address_file = false )

Creates a watch only wallet from a public address and a view secret key.

Parameters
wallet_Name of wallet file
passwordPassword of wallet file
account_public_addressThe account's public address
viewkeyview secret key
create_address_fileWhether to create an address file
Here is the call graph for this function:

◆ generate() [4/4]

void tools::wallet2::generate ( const std::string & wallet_,
const epee::wipeable_string & password,
const epee::wipeable_string & multisig_data,
bool create_address_file = false )

Generates a wallet or restores one.

Parameters
wallet_Name of wallet file
passwordPassword of wallet file
multisig_dataThe multisig restore info and keys
create_address_fileWhether to create an address file

Definition at line 4869 of file wallet2.cpp.

4871{
4872 clear();
4873 prepare_file_names(wallet_);
4874
4875 if (!wallet_.empty())
4876 {
4877 boost::system::error_code ignored_ec;
4878 THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
4879 THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
4880 }
4881
4882 m_account.generate(rct::rct2sk(rct::zero()), true, false);
4883
4884 THROW_WALLET_EXCEPTION_IF(multisig_data.size() < 32, error::invalid_multisig_seed);
4885 size_t offset = 0;
4886 uint32_t threshold = *(uint32_t*)(multisig_data.data() + offset);
4887 offset += sizeof(uint32_t);
4888 uint32_t total = *(uint32_t*)(multisig_data.data() + offset);
4889 offset += sizeof(uint32_t);
4890 THROW_WALLET_EXCEPTION_IF(threshold < 2, error::invalid_multisig_seed);
4891 THROW_WALLET_EXCEPTION_IF(total != threshold && total != threshold + 1, error::invalid_multisig_seed);
4892 const size_t n_multisig_keys = total == threshold ? 1 : threshold;
4893 THROW_WALLET_EXCEPTION_IF(multisig_data.size() != 8 + 32 * (4 + n_multisig_keys + total), error::invalid_multisig_seed);
4894
4895 std::vector<crypto::secret_key> multisig_keys;
4896 std::vector<crypto::public_key> multisig_signers;
4897 crypto::secret_key spend_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset);
4898 offset += sizeof(crypto::secret_key);
4899 crypto::public_key spend_public_key = *(crypto::public_key*)(multisig_data.data() + offset);
4900 offset += sizeof(crypto::public_key);
4901 crypto::secret_key view_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset);
4902 offset += sizeof(crypto::secret_key);
4903 crypto::public_key view_public_key = *(crypto::public_key*)(multisig_data.data() + offset);
4904 offset += sizeof(crypto::public_key);
4905 for (size_t n = 0; n < n_multisig_keys; ++n)
4906 {
4907 multisig_keys.push_back(*(crypto::secret_key*)(multisig_data.data() + offset));
4908 offset += sizeof(crypto::secret_key);
4909 }
4910 for (size_t n = 0; n < total; ++n)
4911 {
4912 multisig_signers.push_back(*(crypto::public_key*)(multisig_data.data() + offset));
4913 offset += sizeof(crypto::public_key);
4914 }
4915
4916 crypto::public_key calculated_view_public_key;
4917 THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(view_secret_key, calculated_view_public_key), error::invalid_multisig_seed);
4918 THROW_WALLET_EXCEPTION_IF(view_public_key != calculated_view_public_key, error::invalid_multisig_seed);
4919 crypto::public_key local_signer;
4920 THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(spend_secret_key, local_signer), error::invalid_multisig_seed);
4921 THROW_WALLET_EXCEPTION_IF(std::find(multisig_signers.begin(), multisig_signers.end(), local_signer) == multisig_signers.end(), error::invalid_multisig_seed);
4922 rct::key skey = rct::zero();
4923 for (const auto &msk: multisig_keys)
4924 sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes);
4925 THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed);
4926 memwipe(&skey, sizeof(rct::key));
4927
4928 m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys);
4929 m_account.finalize_multisig(spend_public_key);
4930
4931 // Not possible to restore a multisig wallet that is able to activate the MMS
4932 // (because the original keys are not (yet) part of the restore info), so
4933 // keep m_original_keys_available to false
4935 m_multisig = true;
4936 m_multisig_threshold = threshold;
4937 m_multisig_signers = multisig_signers;
4938 setup_keys(password);
4939
4940 create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
4941 setup_new_blockchain();
4942
4943 if (!wallet_.empty())
4944 store();
4945}
void sc_add(unsigned char *, const unsigned char *, const unsigned char *)
key zero()
Definition rctOps.h:70
file_error_base< file_exists_message_index > file_exists
unsigned char bytes[32]
Definition rctTypes.h:86
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_account() [1/2]

cryptonote::account_base & tools::wallet2::get_account ( )
inline

Definition at line 734 of file wallet2.h.

734{return m_account;}
Here is the caller graph for this function:

◆ get_account() [2/2]

const cryptonote::account_base & tools::wallet2::get_account ( ) const
inline

Definition at line 735 of file wallet2.h.

735{return m_account;}

◆ get_account_tags()

const std::pair< std::map< std::string, std::string >, std::vector< std::string > > & tools::wallet2::get_account_tags ( )

Get the list of registered account tags.

Returns
first.Key=(tag's name), first.Value=(tag's label), second[i]=(i-th account's tag)

Definition at line 12036 of file wallet2.cpp.

12037{
12038 // ensure consistency
12039 if (m_account_tags.second.size() != get_num_subaddress_accounts())
12040 m_account_tags.second.resize(get_num_subaddress_accounts(), "");
12041 for (const std::string& tag : m_account_tags.second)
12042 {
12043 if (!tag.empty() && m_account_tags.first.count(tag) == 0)
12044 m_account_tags.first.insert({tag, ""});
12045 }
12046 for (auto i = m_account_tags.first.begin(); i != m_account_tags.first.end(); )
12047 {
12048 if (std::find(m_account_tags.second.begin(), m_account_tags.second.end(), i->first) == m_account_tags.second.end())
12049 i = m_account_tags.first.erase(i);
12050 else
12051 ++i;
12052 }
12053 return m_account_tags;
12054}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_address()

cryptonote::account_public_address tools::wallet2::get_address ( ) const
inline

Definition at line 793 of file wallet2.h.

793{ return get_subaddress({0,0}); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_address_as_str()

std::string tools::wallet2::get_address_as_str ( ) const
inline

Definition at line 798 of file wallet2.h.

798{ return get_subaddress_as_str({0, 0}); }
std::string get_subaddress_as_str(const cryptonote::subaddress_index &index) const
Definition wallet2.cpp:1452
Here is the call graph for this function:

◆ get_address_book()

std::vector< address_book_row > tools::wallet2::get_address_book ( ) const
inline

GUI Address book get/store.

Definition at line 1150 of file wallet2.h.

1150{ return m_address_book; }

◆ get_approximate_blockchain_height()

uint64_t tools::wallet2::get_approximate_blockchain_height ( ) const

Calculates the approximate blockchain height from current date/time.

Definition at line 11965 of file wallet2.cpp.

11966{
11967 // time of v2 fork
11968 const time_t fork_time = m_nettype == TESTNET ? 1341378000 : m_nettype == STAGENET ? 1521000000 : 1538815057;
11969 // v2 fork block
11970 const uint64_t fork_block = m_nettype == TESTNET ? 190060 : m_nettype == STAGENET ? 32000 : 307500;
11971 // avg seconds per block
11972 const int seconds_per_block = DIFFICULTY_TARGET_V6;
11973 // Calculated blockchain height
11974 uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
11975 // testnet got some huge rollbacks, so the estimation is way off
11976 static const uint64_t approximate_testnet_rolled_back_blocks = 303967;
11977 if (m_nettype == TESTNET && approx_blockchain_height > approximate_testnet_rolled_back_blocks)
11978 approx_blockchain_height -= approximate_testnet_rolled_back_blocks;
11979 // estiamte blocks from v6
11980 if(m_nettype == MAINNET) {
11981 approx_blockchain_height += 82000;
11982 }
11983 LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
11984 return approx_blockchain_height;
11985}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_attribute()

std::string tools::wallet2::get_attribute ( const std::string & key) const

Definition at line 12018 of file wallet2.cpp.

12019{
12020 std::unordered_map<std::string, std::string>::const_iterator i = m_attributes.find(key);
12021 if (i == m_attributes.end())
12022 return std::string();
12023 return i->second;
12024}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_base_fee()

uint64_t tools::wallet2::get_base_fee ( ) const

Definition at line 7785 of file wallet2.cpp.

7786{
7787 if(m_light_wallet)
7788 {
7790 return m_light_wallet_per_kb_fee / 1024;
7791 else
7792 return m_light_wallet_per_kb_fee;
7793 }
7794 bool use_dyn_fee = use_fork_rules(HF_VERSION_DYNAMIC_FEE, -720 * 1);
7795 if (!use_dyn_fee){
7797 return FEE_PER_KB_V11;
7798 } else{
7799 return FEE_PER_KB_V6;
7800 }
7801 }
7802
7803
7804 return get_dynamic_base_fee_estimate(); //this never gets hit for any version before 100
7805}
#define FEE_PER_KB_V11
#define HF_VERSION_DYNAMIC_FEE
#define FEE_PER_KB_V6
#define HF_VERSION_ZERO_FEE
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_blockchain_current_height()

uint64_t tools::wallet2::get_blockchain_current_height ( ) const
inline

Definition at line 898 of file wallet2.h.

898{ return m_light_wallet_blockchain_height ? m_light_wallet_blockchain_height : m_blockchain.size(); }
Here is the caller graph for this function:

◆ get_blockchain_height_by_date()

uint64_t tools::wallet2::get_blockchain_height_by_date ( uint16_t year,
uint8_t month,
uint8_t day )

Definition at line 13393 of file wallet2.cpp.

13394{
13397 {
13398 throw std::runtime_error("failed to connect to daemon: " + get_daemon_address());
13399 }
13400 if (version < MAKE_CORE_RPC_VERSION(1, 6))
13401 {
13402 throw std::runtime_error("this function requires RPC version 1.6 or higher");
13403 }
13404 std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 };
13405 date.tm_year = year - 1900;
13406 date.tm_mon = month - 1;
13407 date.tm_mday = day;
13408 if (date.tm_mon < 0 || 11 < date.tm_mon || date.tm_mday < 1 || 31 < date.tm_mday)
13409 {
13410 throw std::runtime_error("month or day out of range");
13411 }
13412 uint64_t timestamp_target = std::mktime(&date);
13413 std::string err;
13414 uint64_t height_min = 0;
13415 uint64_t height_max = get_daemon_blockchain_height(err) - 1;
13416 if (!err.empty())
13417 {
13418 throw std::runtime_error("failed to get blockchain height");
13419 }
13420 while (true)
13421 {
13424 uint64_t height_mid = (height_min + height_max) / 2;
13425 req.heights =
13426 {
13427 height_min,
13428 height_mid,
13429 height_max
13430 };
13431 bool r = invoke_http_bin("/getblocks_by_height.bin", req, res, rpc_timeout);
13432 if (!r || res.status != CORE_RPC_STATUS_OK)
13433 {
13434 std::ostringstream oss;
13435 oss << "failed to get blocks by heights: ";
13436 for (auto height : req.heights)
13437 oss << height << ' ';
13438 oss << endl << "reason: ";
13439 if (!r)
13440 oss << "possibly lost connection to daemon";
13441 else if (res.status == CORE_RPC_STATUS_BUSY)
13442 oss << "daemon is busy";
13443 else
13444 oss << get_rpc_status(res.status);
13445 throw std::runtime_error(oss.str());
13446 }
13447 cryptonote::block blk_min, blk_mid, blk_max;
13448 if (res.blocks.size() < 3) throw std::runtime_error("Not enough blocks returned from daemon");
13449 if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_min));
13450 if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_mid));
13451 if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_max));
13452 uint64_t timestamp_min = blk_min.timestamp;
13453 uint64_t timestamp_mid = blk_mid.timestamp;
13454 uint64_t timestamp_max = blk_max.timestamp;
13455 if (!(timestamp_min <= timestamp_mid && timestamp_mid <= timestamp_max))
13456 {
13457 // the timestamps are not in the chronological order.
13458 // assuming they're sufficiently close to each other, simply return the smallest height
13459 return std::min({height_min, height_mid, height_max});
13460 }
13461 if (timestamp_target > timestamp_max)
13462 {
13463 throw std::runtime_error("specified date is in the future");
13464 }
13465 if (timestamp_target <= timestamp_min + 2 * 24 * 60 * 60) // two days of "buffer" period
13466 {
13467 return height_min;
13468 }
13469 if (timestamp_target <= timestamp_mid)
13470 height_max = height_mid;
13471 else
13472 height_min = height_mid;
13473 if (height_max - height_min <= 2 * 24 * 30) // don't divide the height range finer than two days
13474 {
13475 return height_min;
13476 }
13477 }
13478}
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_bytes_received()

uint64_t tools::wallet2::get_bytes_received ( ) const

Definition at line 13761 of file wallet2.cpp.

13762{
13763 return m_http_client.get_bytes_received();
13764}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_bytes_sent()

uint64_t tools::wallet2::get_bytes_sent ( ) const

Definition at line 13756 of file wallet2.cpp.

13757{
13758 return m_http_client.get_bytes_sent();
13759}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_confirm_backlog_threshold()

uint32_t tools::wallet2::get_confirm_backlog_threshold ( ) const
inline

Definition at line 1090 of file wallet2.h.

1090{ return m_confirm_backlog_threshold; };

◆ get_daemon_address()

std::string tools::wallet2::get_daemon_address ( ) const

Definition at line 11926 of file wallet2.cpp.

11927{
11928 return m_daemon_address;
11929}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_daemon_blockchain_height()

uint64_t tools::wallet2::get_daemon_blockchain_height ( std::string & err) const

Definition at line 11931 of file wallet2.cpp.

11932{
11934
11935 boost::optional<std::string> result = m_node_rpc_proxy.get_height(height);
11936 if (result)
11937 {
11938 if (m_trusted_daemon)
11939 err = *result;
11940 else
11941 err = "daemon error";
11942 return 0;
11943 }
11944
11945 err = "";
11946 return height;
11947}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_daemon_blockchain_target_height()

uint64_t tools::wallet2::get_daemon_blockchain_target_height ( std::string & err)

Definition at line 11949 of file wallet2.cpp.

11950{
11951 err = "";
11952 uint64_t target_height = 0;
11953 const auto result = m_node_rpc_proxy.get_target_height(target_height);
11954 if (result && *result != CORE_RPC_STATUS_OK)
11955 {
11956 if (m_trusted_daemon)
11957 err = *result;
11958 else
11959 err = "daemon error";
11960 return 0;
11961 }
11962 return target_height;
11963}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_daemon_login()

const boost::optional< epee::net_utils::http::login > & tools::wallet2::get_daemon_login ( ) const
inline

Definition at line 1165 of file wallet2.h.

1165{ return m_daemon_login; }
Here is the caller graph for this function:

◆ get_default_priority()

uint32_t tools::wallet2::get_default_priority ( ) const
inline

Definition at line 1073 of file wallet2.h.

1073{ return m_default_priority; }

◆ get_description()

std::string tools::wallet2::get_description ( ) const

Definition at line 12031 of file wallet2.cpp.

12032{
12034}
std::string get_attribute(const std::string &key) const
const char *const ATTRIBUTE_DESCRIPTION
Definition wallet2.h:1309
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_device_last_key_image_sync()

uint64_t tools::wallet2::get_device_last_key_image_sync ( ) const
inline

Definition at line 907 of file wallet2.h.

907{ return m_device_last_key_image_sync; }

◆ get_device_type()

hw::device::device_type tools::wallet2::get_device_type ( ) const
inline

Definition at line 831 of file wallet2.h.

831{ return m_key_device_type; }
Here is the caller graph for this function:

◆ get_fee_algorithm()

int tools::wallet2::get_fee_algorithm ( ) const

Definition at line 7824 of file wallet2.cpp.

7825{
7826 // changes at v3, v5, v8
7827 if (use_fork_rules(6, 0))
7828 return 3;
7829 if (use_fork_rules(5, 0))
7830 return 2;
7831 if (use_fork_rules(3, -720 * 14))
7832 return 1;
7833 return 0;
7834}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_fee_multiplier()

uint64_t tools::wallet2::get_fee_multiplier ( uint32_t priority,
int fee_algorithm = -1 ) const

Definition at line 7732 of file wallet2.cpp.

7733{
7734 static const struct
7735 {
7736 size_t count;
7737 uint64_t multipliers[4];
7738 }
7739 multipliers[] =
7740 {
7741 { 3, {1, 2, 3} },
7742 { 3, {1, 20, 166} },
7743 { 4, {1, 4, 20, 166} },
7744 { 4, {1, 2, 4, 8} },
7745 };
7746
7747 if (fee_algorithm == -1)
7748 fee_algorithm = get_fee_algorithm();
7749
7750 // 0 -> default (here, x1 till fee algorithm 2, x4 from it)
7751 if (priority == 0)
7752 priority = m_default_priority;
7753 if (priority == 0)
7754 {
7755 if (fee_algorithm == 2)
7756 priority = 2;
7757 else
7758 priority = 1;
7759 }
7760
7761 THROW_WALLET_EXCEPTION_IF(fee_algorithm < 0 || fee_algorithm > 4, error::invalid_priority);
7762
7763 // 1 to 3/4 are allowed as priorities
7764 const uint32_t max_priority = multipliers[fee_algorithm].count;
7765 if (priority >= 1 && priority <= max_priority)
7766 {
7767 return multipliers[fee_algorithm].multipliers[priority-1];
7768 }
7769
7770 THROW_WALLET_EXCEPTION_IF (false, error::invalid_priority);
7771 return 1;
7772}
mdb_size_t count(MDB_cursor *cur)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_fee_quantization_mask()

uint64_t tools::wallet2::get_fee_quantization_mask ( ) const

Definition at line 7807 of file wallet2.cpp.

7808{
7809 if(m_light_wallet)
7810 {
7811 return 1; // TODO
7812 }
7813 bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
7814 if (!use_per_byte_fee)
7815 return 1;
7816
7817 uint64_t fee_quantization_mask;
7818 boost::optional<std::string> result = m_node_rpc_proxy.get_fee_quantization_mask(fee_quantization_mask);
7819 if (result)
7820 return 1;
7821 return fee_quantization_mask;
7822}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_hard_fork_info()

void tools::wallet2::get_hard_fork_info ( uint8_t version,
uint64_t & earliest_height ) const

Definition at line 10714 of file wallet2.cpp.

10715{
10716 boost::optional<std::string> result = m_node_rpc_proxy.get_earliest_height(version, earliest_height);
10717 throw_on_rpc_response_error(result, "get_hard_fork_info");
10718}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_human_readable_timestamp()

std::string tools::wallet2::get_human_readable_timestamp ( uint64_t ts)
inlinestatic

Check if wallet file path is valid format.

Parameters
file_pathWallet file path
Returns
Whether path is valid format

Definition at line 1039 of file wallet2.h.

1040 {
1041 char buffer[64];
1042 if (ts < 1234567890)
1043 return "<unknown>";
1044 time_t tt = ts;
1045 struct tm tm;
1046 #ifdef WIN32
1047 gmtime_s(&tm, &tt);
1048 #else
1049 gmtime_r(&tt, &tm);
1050 #endif
1051 uint64_t now = time(NULL);
1052 uint64_t diff = ts > now ? ts - now : now - ts;
1053 if (diff > 24*3600)
1054 strftime(buffer, sizeof(buffer), "%Y-%m-%d", &tm);
1055 else
1056 strftime(buffer, sizeof(buffer), "%I:%M:%S %p", &tm);
1057 return std::string(buffer);
1058}

◆ get_integrated_address_as_str()

std::string tools::wallet2::get_integrated_address_as_str ( const crypto::hash8 & payment_id) const

Definition at line 1458 of file wallet2.cpp.

1459{
1460 return cryptonote::get_account_integrated_address_as_str(m_nettype, get_address(), payment_id);
1461}
cryptonote::account_public_address get_address() const
Definition wallet2.h:793
std::string get_account_integrated_address_as_str(network_type nettype, account_public_address const &adr, crypto::hash8 const &payment_id)
Here is the call graph for this function:

◆ get_keys_file()

std::string tools::wallet2::get_keys_file ( ) const

Definition at line 11921 of file wallet2.cpp.

11922{
11923 return m_keys_file;
11924}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_last_block_reward()

uint64_t tools::wallet2::get_last_block_reward ( ) const
inline

Definition at line 906 of file wallet2.h.

906{ return m_last_block_reward; }

◆ get_light_wallet_blockchain_height()

uint64_t tools::wallet2::get_light_wallet_blockchain_height ( ) const
inline

Definition at line 780 of file wallet2.h.

780{ return m_light_wallet_blockchain_height; }

◆ get_light_wallet_scanned_block_height()

uint64_t tools::wallet2::get_light_wallet_scanned_block_height ( ) const
inline

Definition at line 779 of file wallet2.h.

779{ return m_light_wallet_scanned_block_height; }

◆ get_max_ring_size()

uint64_t tools::wallet2::get_max_ring_size ( ) const

Definition at line 7851 of file wallet2.cpp.

7852{
7854 return 11;
7856 return 1;
7857 return 0;
7858}
#define HF_VERSION_ENFORCE_0_DECOY_TXS
#define HF_VERSION_MAX_RING_11
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_message_store() [1/2]

mms::message_store & tools::wallet2::get_message_store ( )
inline

Definition at line 1367 of file wallet2.h.

1367{ return m_message_store; };

◆ get_message_store() [2/2]

const mms::message_store & tools::wallet2::get_message_store ( ) const
inline

Definition at line 1368 of file wallet2.h.

1368{ return m_message_store; };

◆ get_min_output_count()

uint32_t tools::wallet2::get_min_output_count ( ) const
inline

Definition at line 1082 of file wallet2.h.

1082{ return m_min_output_count; }

◆ get_min_output_value()

uint64_t tools::wallet2::get_min_output_value ( ) const
inline

Definition at line 1084 of file wallet2.h.

1084{ return m_min_output_value; }

◆ get_min_ring_size()

uint64_t tools::wallet2::get_min_ring_size ( ) const

Definition at line 7836 of file wallet2.cpp.

7837{
7839 return 11;
7841 return 7;
7843 return 5;
7845 return 1;
7847 return 3;
7848 return 0;
7849}
#define HF_VERSION_MIN_MIXIN_6
#define HF_VERSION_MIN_MIXIN_2
#define HF_VERSION_MIN_MIXIN_10
#define HF_VERSION_MIN_MIXIN_4
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_multisig_info()

std::string tools::wallet2::get_multisig_info ( ) const

Get a packaged multisig information string

Definition at line 5529 of file wallet2.cpp.

5530{
5531 // It's a signed package of private view key and public spend key
5532 const crypto::secret_key skey = cryptonote::get_multisig_blinded_secret_key(get_account().get_keys().m_view_secret_key);
5533 const crypto::public_key pkey = get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key);
5535
5536 std::string data;
5537 data += std::string((const char *)&skey, sizeof(crypto::secret_key));
5538 data += std::string((const char *)&pkey, sizeof(crypto::public_key));
5539
5540 data.resize(data.size() + sizeof(crypto::signature));
5541 crypto::cn_fast_hash(data.data(), data.size() - sizeof(signature), hash);
5542 crypto::signature &signature = *(crypto::signature*)&data[data.size() - sizeof(crypto::signature)];
5544
5545 return std::string("MultisigV1") + tools::base58::encode(data);
5546}
crypto::secret_key get_multisig_blinded_secret_key(const crypto::secret_key &key)
Definition multisig.cpp:47
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_multisig_seed()

bool tools::wallet2::get_multisig_seed ( epee::wipeable_string & seed,
const epee::wipeable_string & passphrase = std::string(),
bool raw = true ) const

Definition at line 1327 of file wallet2.cpp.

1328{
1329 bool ready;
1330 uint32_t threshold, total;
1331 if (!multisig(&ready, &threshold, &total))
1332 {
1333 std::cout << "This is not a multisig wallet" << std::endl;
1334 return false;
1335 }
1336 if (!ready)
1337 {
1338 std::cout << "This multisig wallet is not yet finalized" << std::endl;
1339 return false;
1340 }
1341 if (!raw && seed_language.empty())
1342 {
1343 std::cout << "seed_language not set" << std::endl;
1344 return false;
1345 }
1346
1347 crypto::secret_key skey;
1348 crypto::public_key pkey;
1349 const account_keys &keys = get_account().get_keys();
1350 epee::wipeable_string data;
1351 data.append((const char*)&threshold, sizeof(uint32_t));
1352 data.append((const char*)&total, sizeof(uint32_t));
1353 skey = keys.m_spend_secret_key;
1354 data.append((const char*)&skey, sizeof(skey));
1356 data.append((const char*)&pkey, sizeof(pkey));
1357 skey = keys.m_view_secret_key;
1358 data.append((const char*)&skey, sizeof(skey));
1360 data.append((const char*)&pkey, sizeof(pkey));
1361 for (const auto &skey: keys.m_multisig_keys)
1362 data.append((const char*)&skey, sizeof(skey));
1363 for (const auto &signer: m_multisig_signers)
1364 data.append((const char*)&signer, sizeof(signer));
1365
1366 if (!passphrase.empty())
1367 {
1369 crypto::cn_slow_hash(passphrase.data(), passphrase.size(), (crypto::hash&)key);
1370 sc_reduce32((unsigned char*)key.data);
1371 data = encrypt(data, key, true);
1372 }
1373
1374 if (raw)
1375 {
1376 seed = epee::to_hex::wipeable_string({(const unsigned char*)data.data(), data.size()});
1377 }
1378 else
1379 {
1380 if (!crypto::ElectrumWords::bytes_to_words(data.data(), data.size(), seed, seed_language))
1381 {
1382 std::cout << "Failed to encode seed";
1383 return false;
1384 }
1385 }
1386
1387 return true;
1388}
void append(const char *ptr, size_t len)
bool empty() const noexcept
void sc_reduce32(unsigned char *)
bool bytes_to_words(const char *src, size_t len, epee::wipeable_string &words, const std::string &language_name)
Converts bytes (secret key) to seed words.
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height)
crypto::secret_key m_view_secret_key
Definition account.h:45
crypto::secret_key m_spend_secret_key
Definition account.h:44
std::vector< crypto::secret_key > m_multisig_keys
Definition account.h:46
static epee::wipeable_string wipeable_string(const span< const std::uint8_t > src)
Definition hex.cpp:69
Here is the call graph for this function:

◆ get_multisig_signer_public_key() [1/2]

crypto::public_key tools::wallet2::get_multisig_signer_public_key ( ) const

Definition at line 12898 of file wallet2.cpp.

12899{
12900 CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12901 crypto::public_key signer;
12902 CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(get_account().get_keys().m_spend_secret_key, signer), "Failed to generate signer public key");
12903 return signer;
12904}
Here is the call graph for this function:

◆ get_multisig_signer_public_key() [2/2]

crypto::public_key tools::wallet2::get_multisig_signer_public_key ( const crypto::secret_key & spend_skey) const

Definition at line 12891 of file wallet2.cpp.

12892{
12893 crypto::public_key pkey;
12895 return pkey;
12896}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_multisig_signing_public_key() [1/2]

crypto::public_key tools::wallet2::get_multisig_signing_public_key ( const crypto::secret_key & skey) const

Definition at line 12906 of file wallet2.cpp.

12907{
12908 CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12909 crypto::public_key pkey;
12910 CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(msk, pkey), "Failed to derive public key");
12911 return pkey;
12912}
Here is the call graph for this function:

◆ get_multisig_signing_public_key() [2/2]

crypto::public_key tools::wallet2::get_multisig_signing_public_key ( size_t idx) const

Definition at line 12914 of file wallet2.cpp.

12915{
12916 CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12917 CHECK_AND_ASSERT_THROW_MES(idx < get_account().get_multisig_keys().size(), "Multisig signing key index out of range");
12918 return get_multisig_signing_public_key(get_account().get_multisig_keys()[idx]);
12919}
crypto::public_key get_multisig_signing_public_key(size_t idx) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_multisig_wallet_state()

mms::multisig_wallet_state tools::wallet2::get_multisig_wallet_state ( ) const

Definition at line 13615 of file wallet2.cpp.

13616{
13617 mms::multisig_wallet_state state;
13618 state.nettype = m_nettype;
13619 state.multisig = multisig(&state.multisig_is_ready);
13621 state.multisig_rounds_passed = m_multisig_rounds_passed;
13622 state.num_transfer_details = m_transfers.size();
13623 if (state.multisig)
13624 {
13625 THROW_WALLET_EXCEPTION_IF(!m_original_keys_available, error::wallet_internal_error, "MMS use not possible because own original Electroneum address not available");
13626 state.address = m_original_address;
13627 state.view_secret_key = m_original_view_secret_key;
13628 }
13629 else
13630 {
13631 state.address = m_account.get_keys().m_account_address;
13632 state.view_secret_key = m_account.get_keys().m_view_secret_key;
13633 }
13634 state.mms_file=m_mms_file;
13635 return state;
13636}
bool has_multisig_partial_key_images() const
Definition wallet2.cpp:5647
cryptonote::network_type nettype
crypto::secret_key view_secret_key
cryptonote::account_public_address address
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_num_rct_outputs()

uint64_t tools::wallet2::get_num_rct_outputs ( )

Definition at line 10831 of file wallet2.cpp.

10832{
10835 m_daemon_rpc_mutex.lock();
10836 req_t.amounts.push_back(0);
10837 req_t.min_count = 0;
10838 req_t.max_count = 0;
10839 req_t.unlocked = true;
10840 req_t.recent_cutoff = 0;
10841 bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
10842 m_daemon_rpc_mutex.unlock();
10843 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_num_rct_outputs");
10844 THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
10845 THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status);
10846 THROW_WALLET_EXCEPTION_IF(resp_t.histogram.size() != 1, error::get_histogram_error, "Expected exactly one response");
10847 THROW_WALLET_EXCEPTION_IF(resp_t.histogram[0].amount != 0, error::get_histogram_error, "Expected 0 amount");
10848
10849 return resp_t.histogram[0].total_instances;
10850}
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_num_subaddress_accounts()

size_t tools::wallet2::get_num_subaddress_accounts ( ) const
inline

Definition at line 801 of file wallet2.h.

801{ return m_subaddress_labels.size(); } // number of accounts in wallet
Here is the caller graph for this function:

◆ get_num_subaddresses()

size_t tools::wallet2::get_num_subaddresses ( uint32_t index_major) const
inline

Definition at line 802 of file wallet2.h.

802{ return index_major < m_subaddress_labels.size() ? m_subaddress_labels[index_major].size() : 0; } // number of subaddresses in a particular account
Here is the caller graph for this function:

◆ get_num_transfer_details()

size_t tools::wallet2::get_num_transfer_details ( ) const
inline

Definition at line 1155 of file wallet2.h.

1155{ return m_transfers.size(); }
Here is the caller graph for this function:

◆ get_payments() [1/2]

void tools::wallet2::get_payments ( const crypto::hash & payment_id,
std::list< wallet2::payment_details > & payments,
uint64_t min_height = 0,
const boost::optional< uint32_t > & subaddr_account = boost::none,
const std::set< uint32_t > & subaddr_indices = {} ) const

Definition at line 6320 of file wallet2.cpp.

6321{
6322 auto range = m_payments.equal_range(payment_id);
6323 std::for_each(range.first, range.second, [&payments, &min_height, &subaddr_account, &subaddr_indices](const payment_container::value_type& x) {
6324 if (min_height < x.second.m_block_height &&
6325 (!subaddr_account || *subaddr_account == x.second.m_subaddr_index.major) &&
6326 (subaddr_indices.empty() || subaddr_indices.count(x.second.m_subaddr_index.minor) == 1))
6327 {
6328 payments.push_back(x.second);
6329 }
6330 });
6331}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_payments() [2/2]

void tools::wallet2::get_payments ( std::list< std::pair< crypto::hash, wallet2::payment_details > > & payments,
uint64_t min_height,
uint64_t max_height = (uint64_t)-1,
const boost::optional< uint32_t > & subaddr_account = boost::none,
const std::set< uint32_t > & subaddr_indices = {} ) const

Definition at line 6333 of file wallet2.cpp.

6334{
6335 auto range = std::make_pair(m_payments.begin(), m_payments.end());
6336 std::for_each(range.first, range.second, [&payments, &min_height, &max_height, &subaddr_account, &subaddr_indices](const payment_container::value_type& x) {
6337 if (min_height < x.second.m_block_height && max_height >= x.second.m_block_height &&
6338 (!subaddr_account || *subaddr_account == x.second.m_subaddr_index.major) &&
6339 (subaddr_indices.empty() || subaddr_indices.count(x.second.m_subaddr_index.minor) == 1))
6340 {
6341 payments.push_back(x);
6342 }
6343 });
6344}
Here is the call graph for this function:

◆ get_payments_out()

void tools::wallet2::get_payments_out ( std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > & confirmed_payments,
uint64_t min_height,
uint64_t max_height = (uint64_t)-1,
const boost::optional< uint32_t > & subaddr_account = boost::none,
const std::set< uint32_t > & subaddr_indices = {} ) const

Definition at line 6346 of file wallet2.cpp.

6348{
6349 for (auto i = m_confirmed_txs.begin(); i != m_confirmed_txs.end(); ++i) {
6350 if (i->second.m_block_height <= min_height || i->second.m_block_height > max_height)
6351 continue;
6352 if (subaddr_account && *subaddr_account != i->second.m_subaddr_account)
6353 continue;
6354 if (!subaddr_indices.empty() && std::count_if(i->second.m_subaddr_indices.begin(), i->second.m_subaddr_indices.end(), [&subaddr_indices](uint32_t index) { return subaddr_indices.count(index) == 1; }) == 0)
6355 continue;
6356 if (i->second.m_is_migration) //avoid as processed by separate function
6357 continue;
6358 if(i->second.m_is_sc_migration) //avoid as processed by separate function
6359 continue;
6360 confirmed_payments.push_back(*i);
6361 }
6362}//----------------------------------------------------------------------------------------------------
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_payments_out_migration()

void tools::wallet2::get_payments_out_migration ( std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > & confirmed_payments,
uint64_t min_height,
uint64_t max_height = (uint64_t)-1,
const boost::optional< uint32_t > & subaddr_account = boost::none,
const std::set< uint32_t > & subaddr_indices = {} ) const

Definition at line 6363 of file wallet2.cpp.

6365{
6366 for (auto i = m_confirmed_txs.begin(); i != m_confirmed_txs.end(); ++i) {
6367 if (i->second.m_block_height <= min_height || i->second.m_block_height > max_height)
6368 continue;
6369 if (subaddr_account && *subaddr_account != i->second.m_subaddr_account)
6370 continue;
6371 if (!subaddr_indices.empty() && std::count_if(i->second.m_subaddr_indices.begin(), i->second.m_subaddr_indices.end(), [&subaddr_indices](uint32_t index) { return subaddr_indices.count(index) == 1; }) == 0)
6372 continue;
6373 if (!i->second.m_is_migration)
6374 continue;
6375
6376 confirmed_payments.push_back(*i);
6377 }
6378}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_payments_out_sc_migration()

void tools::wallet2::get_payments_out_sc_migration ( std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > & confirmed_payments,
uint64_t min_height,
uint64_t max_height = (uint64_t)-1,
const boost::optional< uint32_t > & subaddr_account = boost::none,
const std::set< uint32_t > & subaddr_indices = {} ) const

Definition at line 6380 of file wallet2.cpp.

6381 {
6382
6383 for (auto i = m_confirmed_txs.begin(); i != m_confirmed_txs.end(); ++i) {
6384 if (i->second.m_block_height <= min_height || i->second.m_block_height > max_height)
6385 continue;
6386 if (subaddr_account && *subaddr_account != i->second.m_subaddr_account)
6387 continue;
6388 if (!subaddr_indices.empty() && std::count_if(i->second.m_subaddr_indices.begin(), i->second.m_subaddr_indices.end(), [&subaddr_indices](uint32_t index) { return subaddr_indices.count(index) == 1; }) == 0)
6389 continue;
6390 if (!i->second.m_is_sc_migration)
6391 continue;
6392 confirmed_payments.push_back(*i);
6393 }
6394}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_refresh_from_block_height()

uint64_t tools::wallet2::get_refresh_from_block_height ( ) const
inline

Definition at line 743 of file wallet2.h.

743{return m_refresh_from_block_height;}

◆ get_refresh_type()

RefreshType tools::wallet2::get_refresh_type ( ) const
inline

Definition at line 822 of file wallet2.h.

822{ return m_refresh_type; }

◆ get_reserve_proof()

std::string tools::wallet2::get_reserve_proof ( const boost::optional< std::pair< uint32_t, uint64_t > > & account_minreserve,
const std::string & message )

Generates a proof that proves the reserve of unspent funds.

Parameters
account_minreserveWhen specified, collect outputs only belonging to the given account and prove the smallest reserve above the given amount When unspecified, proves for all unspent outputs across all accounts
messageArbitrary challenge message to be signed together
Returns
Signature string

Definition at line 11669 of file wallet2.cpp.

11670{
11671 THROW_WALLET_EXCEPTION_IF(m_watch_only || m_multisig, error::wallet_internal_error, "Reserve proof can only be generated by a full wallet");
11672 THROW_WALLET_EXCEPTION_IF(balance_all(false) == 0, error::wallet_internal_error, "Zero balance");
11673 THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first, false) < account_minreserve->second, error::wallet_internal_error,
11674 "Not enough balance in this account for the requested minimum reserve amount");
11675
11676 // determine which outputs to include in the proof
11677 std::vector<size_t> selected_transfers;
11678 for (size_t i = 0; i < m_transfers.size(); ++i)
11679 {
11680 const transfer_details &td = m_transfers[i];
11681 if (!td.m_spent && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
11682 selected_transfers.push_back(i);
11683 }
11684
11685 if (account_minreserve)
11686 {
11687 THROW_WALLET_EXCEPTION_IF(account_minreserve->second == 0, error::wallet_internal_error, "Proved amount must be greater than 0");
11688 // minimize the number of outputs included in the proof, by only picking the N largest outputs that can cover the requested min reserve amount
11689 std::sort(selected_transfers.begin(), selected_transfers.end(), [&](const size_t a, const size_t b)
11690 { return m_transfers[a].amount() > m_transfers[b].amount(); });
11691 while (selected_transfers.size() >= 2 && m_transfers[selected_transfers[1]].amount() >= account_minreserve->second)
11692 selected_transfers.erase(selected_transfers.begin());
11693 size_t sz = 0;
11694 uint64_t total = 0;
11695 while (total < account_minreserve->second)
11696 {
11697 total += m_transfers[selected_transfers[sz]].amount();
11698 ++sz;
11699 }
11700 selected_transfers.resize(sz);
11701 }
11702
11703 // compute signature prefix hash
11704 std::string prefix_data = message;
11705 prefix_data.append((const char*)&m_account.get_keys().m_account_address, sizeof(cryptonote::account_public_address));
11706 for (size_t i = 0; i < selected_transfers.size(); ++i)
11707 {
11708 prefix_data.append((const char*)&m_transfers[selected_transfers[i]].m_key_image, sizeof(crypto::key_image));
11709 }
11710 crypto::hash prefix_hash;
11711 crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11712
11713 // generate proof entries
11714 std::vector<reserve_proof_entry> proofs(selected_transfers.size());
11715 std::unordered_set<cryptonote::subaddress_index> subaddr_indices = { {0,0} };
11716 for (size_t i = 0; i < selected_transfers.size(); ++i)
11717 {
11718 transfer_details &td = m_transfers[selected_transfers[i]];
11719 reserve_proof_entry& proof = proofs[i];
11720 proof.txid = td.m_txid;
11721 proof.index_in_tx = td.m_internal_output_index;
11722 proof.key_image = td.m_key_image;
11723 cryptonote::subaddress_index index2 = {td.m_subaddr_index.major + (td.m_subaddr_index.major != 0 ? m_account_major_offset : 0), td.m_subaddr_index.minor};
11724 td.m_subaddr_index = index2;
11725 subaddr_indices.insert(td.m_subaddr_index);
11726
11727 // get tx pub key
11728 const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
11729 THROW_WALLET_EXCEPTION_IF(tx_pub_key == crypto::null_pkey, error::wallet_internal_error, "The tx public key isn't found");
11730 const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
11731
11732 // determine which tx pub key was used for deriving the output key
11733 const crypto::public_key *tx_pub_key_used = &tx_pub_key;
11734 for (int i = 0; i < 2; ++i)
11735 {
11736 proof.shared_secret = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(*tx_pub_key_used), rct::sk2rct(m_account.get_keys().m_view_secret_key)));
11737 crypto::key_derivation derivation;
11738 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(proof.shared_secret, rct::rct2sk(rct::I), derivation),
11739 error::wallet_internal_error, "Failed to generate key derivation");
11740 crypto::public_key subaddress_spendkey;
11741 THROW_WALLET_EXCEPTION_IF(!derive_subaddress_public_key(td.get_public_key(), derivation, proof.index_in_tx, subaddress_spendkey),
11742 error::wallet_internal_error, "Failed to derive subaddress public key");
11743 if (m_subaddresses.count(subaddress_spendkey) == 1)
11744 break;
11745 THROW_WALLET_EXCEPTION_IF(additional_tx_pub_keys.empty(), error::wallet_internal_error,
11746 "Normal tx pub key doesn't derive the expected output, while the additional tx pub keys are empty");
11747 THROW_WALLET_EXCEPTION_IF(i == 1, error::wallet_internal_error,
11748 "Neither normal tx pub key nor additional tx pub key derive the expected output key");
11749 tx_pub_key_used = &additional_tx_pub_keys[proof.index_in_tx];
11750 }
11751
11752 // generate signature for shared secret
11753 crypto::generate_tx_proof(prefix_hash, m_account.get_keys().m_account_address.m_view_public_key, *tx_pub_key_used, boost::none, proof.shared_secret, m_account.get_keys().m_view_secret_key, proof.shared_secret_sig);
11754
11755 // derive ephemeral secret key
11757 cryptonote::keypair ephemeral;
11758 const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device(), m_account_major_offset);
11759 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
11760 THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one");
11761
11762 // generate signature for key image
11763 const std::vector<const crypto::public_key*> pubs = { &ephemeral.pub };
11764 crypto::generate_ring_signature(prefix_hash, td.m_key_image, &pubs[0], 1, ephemeral.sec, 0, &proof.key_image_sig);
11765 }
11766
11767 // collect all subaddress spend keys that received those outputs and generate their signatures
11768 std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
11769 for (const cryptonote::subaddress_index &index : subaddr_indices)
11770 {
11771 crypto::secret_key subaddr_spend_skey = m_account.get_keys().m_spend_secret_key;
11772 if (!index.is_zero())
11773 {
11774 crypto::secret_key m = m_account.get_device().get_subaddress_secret_key(m_account.get_keys().m_view_secret_key, index);
11775 crypto::secret_key tmp = subaddr_spend_skey;
11776 sc_add((unsigned char*)&subaddr_spend_skey, (unsigned char*)&m, (unsigned char*)&tmp);
11777 }
11778 crypto::public_key subaddr_spend_pkey;
11779 secret_key_to_public_key(subaddr_spend_skey, subaddr_spend_pkey);
11780 crypto::generate_signature(prefix_hash, subaddr_spend_pkey, subaddr_spend_skey, subaddr_spendkeys[subaddr_spend_pkey]);
11781 }
11782
11783 // serialize & encode
11784 std::ostringstream oss;
11785 boost::archive::portable_binary_oarchive ar(oss);
11786 ar << proofs << subaddr_spendkeys;
11787 return "ReserveProofV1" + tools::base58::encode(oss.str());
11788}
uint64_t balance_all(bool public_blockchain) const
Definition wallet2.cpp:6292
void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional< public_key > &B, const public_key &D, const secret_key &r, signature &sig)
Definition crypto.h:311
void scalarmultKey(key &aP, const key &P, const key &a)
Definition rctOps.cpp:368
crypto::hash txid
Definition wallet2.h:554
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_ring()

bool tools::wallet2::get_ring ( const crypto::key_image & key_image,
std::vector< uint64_t > & outs )

Definition at line 8057 of file wallet2.cpp.

8058{
8059 try { return get_ring(get_ringdb_key(), key_image, outs); }
8060 catch (const std::exception &e) { return false; }
8061}
bool get_ring(const crypto::key_image &key_image, std::vector< uint64_t > &outs)
Definition wallet2.cpp:8057
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_ring_database()

const std::string tools::wallet2::get_ring_database ( ) const
inline

Definition at line 1341 of file wallet2.h.

1341{ return m_ring_database; }

◆ get_rings()

bool tools::wallet2::get_rings ( const crypto::hash & txid,
std::vector< std::pair< crypto::key_image, std::vector< uint64_t > > > & outs )

Definition at line 8034 of file wallet2.cpp.

8035{
8036 for (auto i: m_confirmed_txs)
8037 {
8038 if (txid == i.first)
8039 {
8040 for (const auto &x: i.second.m_rings)
8041 outs.push_back({x.first, cryptonote::relative_output_offsets_to_absolute(x.second)});
8042 return true;
8043 }
8044 }
8045 for (auto i: m_unconfirmed_txs)
8046 {
8047 if (txid == i.first)
8048 {
8049 for (const auto &x: i.second.m_rings)
8050 outs.push_back({x.first, cryptonote::relative_output_offsets_to_absolute(x.second)});
8051 return true;
8052 }
8053 }
8054 return false;
8055}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_seed()

bool tools::wallet2::get_seed ( epee::wipeable_string & electrum_words,
const epee::wipeable_string & passphrase = epee::wipeable_string() ) const

Definition at line 1301 of file wallet2.cpp.

1302{
1303 bool keys_deterministic = is_deterministic();
1304 if (!keys_deterministic)
1305 {
1306 std::cout << "This is not a deterministic wallet" << std::endl;
1307 return false;
1308 }
1309 if (seed_language.empty())
1310 {
1311 std::cout << "seed_language not set" << std::endl;
1312 return false;
1313 }
1314
1316 if (!passphrase.empty())
1317 key = cryptonote::encrypt_key(key, passphrase);
1318 if (!crypto::ElectrumWords::bytes_to_words(key, electrum_words, seed_language))
1319 {
1320 std::cout << "Failed to create seed from key for language: " << seed_language << std::endl;
1321 return false;
1322 }
1323
1324 return true;
1325}
bool is_deterministic() const
Checks if deterministic wallet.
Definition wallet2.cpp:1293
crypto::secret_key encrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase)
Here is the call graph for this function:

◆ get_seed_language()

const std::string & tools::wallet2::get_seed_language ( ) const

Gets the seed language.

Definition at line 1417 of file wallet2.cpp.

1418{
1419 return seed_language;
1420}

◆ get_spend_proof()

std::string tools::wallet2::get_spend_proof ( const crypto::hash & txid,
const std::string & message )

Definition at line 11047 of file wallet2.cpp.

11048{
11049 THROW_WALLET_EXCEPTION_IF(m_watch_only, error::wallet_internal_error,
11050 "get_spend_proof requires spend secret key and is not available for a watch-only wallet");
11051
11052 // fetch tx from daemon
11054 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11055 req.decode_as_json = false;
11056 req.prune = true;
11058 bool r;
11059 {
11060 const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
11061 r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11062 }
11063 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
11064 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
11065 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
11066 THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
11067 "daemon returned wrong response for gettransactions, wrong txs count = " +
11068 std::to_string(res.txs.size()) + ", expected 1");
11069
11070 cryptonote::transaction tx;
11071 crypto::hash tx_hash;
11072 THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(res.txs[0], tx, tx_hash), error::wallet_internal_error, "Failed to get tx from daemon");
11073
11074 std::vector<std::vector<crypto::signature>> signatures;
11075
11076 // get signature prefix hash
11077 std::string sig_prefix_data((const char*)&txid, sizeof(crypto::hash));
11078 sig_prefix_data += message;
11079 crypto::hash sig_prefix_hash;
11080 crypto::cn_fast_hash(sig_prefix_data.data(), sig_prefix_data.size(), sig_prefix_hash);
11081
11082 for(size_t i = 0; i < tx.vin.size(); ++i)
11083 {
11084 const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
11085 if (in_key == nullptr)
11086 continue;
11087
11088 // check if the key image belongs to us
11089 const auto found = m_key_images.find(in_key->k_image);
11090 if(found == m_key_images.end())
11091 {
11092 THROW_WALLET_EXCEPTION_IF(i > 0, error::wallet_internal_error, "subset of key images belong to us, very weird!");
11093 THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "This tx wasn't generated by this wallet!");
11094 }
11095
11096 // derive the real output keypair
11097 const transfer_details& in_td = m_transfers[found->second];
11098 const txout_to_key* const in_tx_out_pkey = boost::get<txout_to_key>(std::addressof(in_td.m_tx.vout[in_td.m_internal_output_index].target));
11099 THROW_WALLET_EXCEPTION_IF(in_tx_out_pkey == nullptr, error::wallet_internal_error, "Output is not txout_to_key");
11100 const crypto::public_key in_tx_pub_key = get_tx_pub_key_from_extra(in_td.m_tx, in_td.m_pk_index);
11101 const std::vector<crypto::public_key> in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx);
11102 keypair in_ephemeral;
11103 crypto::key_image in_img;
11104 THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey->key, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device(), m_account_major_offset),
11105 error::wallet_internal_error, "failed to generate key image");
11106 THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch");
11107
11108 // get output pubkeys in the ring
11109 const std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key->key_offsets);
11110 const size_t ring_size = in_key->key_offsets.size();
11111 THROW_WALLET_EXCEPTION_IF(absolute_offsets.size() != ring_size, error::wallet_internal_error, "absolute offsets size is wrong");
11113 req.outputs.resize(ring_size);
11114 for (size_t j = 0; j < ring_size; ++j)
11115 {
11116 req.outputs[j].amount = in_key->amount;
11117 req.outputs[j].index = absolute_offsets[j];
11118 }
11120 bool r;
11121 {
11122 const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
11123 r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
11124 }
11125 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
11126 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
11127 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "get_outs.bin");
11128 THROW_WALLET_EXCEPTION_IF(res.outs.size() != ring_size, error::wallet_internal_error,
11129 "daemon returned wrong response for get_outs.bin, wrong amounts count = " +
11130 std::to_string(res.outs.size()) + ", expected " + std::to_string(ring_size));
11131
11132 // copy pubkey pointers
11133 std::vector<const crypto::public_key *> p_output_keys;
11134 for (const COMMAND_RPC_GET_OUTPUTS_BIN::outkey &out : res.outs)
11135 p_output_keys.push_back(&out.key);
11136
11137 // figure out real output index and secret key
11138 size_t sec_index = -1;
11139 for (size_t j = 0; j < ring_size; ++j)
11140 {
11141 if (res.outs[j].key == in_ephemeral.pub)
11142 {
11143 sec_index = j;
11144 break;
11145 }
11146 }
11147 THROW_WALLET_EXCEPTION_IF(sec_index >= ring_size, error::wallet_internal_error, "secret index not found");
11148
11149 // generate ring sig for this input
11150 signatures.push_back(std::vector<crypto::signature>());
11151 std::vector<crypto::signature>& sigs = signatures.back();
11152 sigs.resize(in_key->key_offsets.size());
11153 crypto::generate_ring_signature(sig_prefix_hash, in_key->k_image, p_output_keys, in_ephemeral.sec, sec_index, sigs.data());
11154 }
11155
11156 std::string sig_str = "SpendProofV1";
11157 for (const std::vector<crypto::signature>& ring_sig : signatures)
11158 for (const crypto::signature& sig : ring_sig)
11159 sig_str += tools::base58::encode(std::string((const char *)&sig, sizeof(crypto::signature)));
11160 return sig_str;
11161}
std::vector< std::string > keypair
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_subaddress()

cryptonote::account_public_address tools::wallet2::get_subaddress ( const cryptonote::subaddress_index & index) const

Definition at line 1430 of file wallet2.cpp.

1431{
1432 hw::device &hwdev = m_account.get_device();
1433 cryptonote::subaddress_index index2 = {index.major + (index.major != 0 ? m_account_major_offset : 0), index.minor};
1434 return hwdev.get_subaddress(m_account.get_keys(), index2);
1435}
virtual cryptonote::account_public_address get_subaddress(const cryptonote::account_keys &keys, const cryptonote::subaddress_index &index)=0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_subaddress_as_str()

std::string tools::wallet2::get_subaddress_as_str ( const cryptonote::subaddress_index & index) const

Definition at line 1452 of file wallet2.cpp.

1453{
1454 cryptonote::account_public_address address = get_subaddress(index);
1455 return cryptonote::get_account_address_as_str(m_nettype, !index.is_zero(), address);
1456}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_subaddress_index()

boost::optional< cryptonote::subaddress_index > tools::wallet2::get_subaddress_index ( const cryptonote::account_public_address & address) const

Definition at line 1437 of file wallet2.cpp.

1438{
1439 auto index = m_subaddresses.find(address.m_spend_public_key);
1440 if (index == m_subaddresses.end())
1441 return boost::none;
1442 return index->second;
1443}

◆ get_subaddress_label()

std::string tools::wallet2::get_subaddress_label ( const cryptonote::subaddress_index & index) const

Definition at line 1518 of file wallet2.cpp.

1519{
1520 if (index.major >= m_subaddress_labels.size() || index.minor >= m_subaddress_labels[index.major].size())
1521 {
1522 MERROR("Subaddress label doesn't exist");
1523 return "";
1524 }
1525 return m_subaddress_labels[index.major][index.minor];
1526}

◆ get_subaddress_lookahead()

std::pair< size_t, size_t > tools::wallet2::get_subaddress_lookahead ( ) const
inline

Definition at line 808 of file wallet2.h.

808{ return {m_subaddress_lookahead_major, m_subaddress_lookahead_minor}; }

◆ get_subaddress_spend_public_key()

crypto::public_key tools::wallet2::get_subaddress_spend_public_key ( const cryptonote::subaddress_index & index) const

Definition at line 1445 of file wallet2.cpp.

1446{
1447 hw::device &hwdev = m_account.get_device();
1448 cryptonote::subaddress_index index2 = {index.major + (index.major != 0 ? m_account_major_offset : 0), index.minor};
1449 return hwdev.get_subaddress_spend_public_key(m_account.get_keys(), index2);
1450}
virtual crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys &keys, const cryptonote::subaddress_index &index)=0
Here is the call graph for this function:

◆ get_subaddress_spend_public_keys()

std::vector< crypto::public_key > tools::wallet2::get_subaddress_spend_public_keys ( uint32_t account,
uint32_t begin,
uint32_t end ) const
Here is the call graph for this function:

◆ get_transfer_details()

const wallet2::transfer_details & tools::wallet2::get_transfer_details ( size_t idx) const

Definition at line 10852 of file wallet2.cpp.

10853{
10854 THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Bad transfer index");
10855 return m_transfers[idx];
10856}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transfers()

void tools::wallet2::get_transfers ( wallet2::transfer_container & incoming_transfers) const

Definition at line 6315 of file wallet2.cpp.

6316{
6317 incoming_transfers = m_transfers;
6318}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_tx_device_aux()

std::string tools::wallet2::get_tx_device_aux ( const crypto::hash & txid) const

Definition at line 12005 of file wallet2.cpp.

12006{
12007 std::unordered_map<crypto::hash, std::string>::const_iterator i = m_tx_device.find(txid);
12008 if (i == m_tx_device.end())
12009 return std::string();
12010 return i->second;
12011}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_tx_key()

bool tools::wallet2::get_tx_key ( const crypto::hash & txid,
crypto::secret_key & tx_key,
std::vector< crypto::secret_key > & additional_tx_keys )

Definition at line 10924 of file wallet2.cpp.

10925{
10926 bool r = get_tx_key_cached(txid, tx_key, additional_tx_keys);
10927 if (r)
10928 {
10929 return true;
10930 }
10931
10932 auto & hwdev = get_account().get_device();
10933
10934 // So far only Cold protocol devices are supported.
10935 if (hwdev.device_protocol() != hw::device::PROTOCOL_COLD)
10936 {
10937 return false;
10938 }
10939
10940 const auto tx_data_it = m_tx_device.find(txid);
10941 if (tx_data_it == m_tx_device.end())
10942 {
10943 MDEBUG("Aux data not found for txid: " << txid);
10944 return false;
10945 }
10946
10947 auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
10948 CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
10949 if (!dev_cold->is_get_tx_key_supported())
10950 {
10951 MDEBUG("get_tx_key not supported by the device");
10952 return false;
10953 }
10954
10955 hw::device_cold::tx_key_data_t tx_key_data;
10956 dev_cold->load_tx_key_data(tx_key_data, tx_data_it->second);
10957
10958 // Load missing tx prefix hash
10959 if (tx_key_data.tx_prefix_hash.empty())
10960 {
10963 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
10964 req.decode_as_json = false;
10965 req.prune = true;
10966 m_daemon_rpc_mutex.lock();
10967 bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
10968 m_daemon_rpc_mutex.unlock();
10969 THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
10970 error::wallet_internal_error, "Failed to get transaction from daemon");
10971
10972 cryptonote::transaction tx;
10973 crypto::hash tx_hash{};
10974 cryptonote::blobdata tx_data;
10975 crypto::hash tx_prefix_hash{};
10976 ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
10977 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
10978 THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash),
10979 error::wallet_internal_error, "Failed to validate transaction from daemon");
10980 THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error,
10981 "Failed to get the right transaction from daemon");
10982
10983 tx_key_data.tx_prefix_hash = std::string(tx_prefix_hash.data, 32);
10984 }
10985
10986 std::vector<crypto::secret_key> tx_keys;
10987 dev_cold->get_tx_key(tx_keys, tx_key_data, m_account.get_keys().m_view_secret_key);
10988 if (tx_keys.empty())
10989 {
10990 return false;
10991 }
10992
10993 tx_key = tx_keys[0];
10994 tx_keys.erase(tx_keys.begin());
10995 additional_tx_keys = tx_keys;
10996
10997 return true;
10998}
@ PROTOCOL_COLD
Definition device.hpp:115
bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_tx_key_cached()

bool tools::wallet2::get_tx_key_cached ( const crypto::hash & txid,
crypto::secret_key & tx_key,
std::vector< crypto::secret_key > & additional_tx_keys ) const

Definition at line 10911 of file wallet2.cpp.

10912{
10913 additional_tx_keys.clear();
10914 const std::unordered_map<crypto::hash, crypto::secret_key>::const_iterator i = m_tx_keys.find(txid);
10915 if (i == m_tx_keys.end())
10916 return false;
10917 tx_key = i->second;
10918 const auto j = m_additional_tx_keys.find(txid);
10919 if (j != m_additional_tx_keys.end())
10920 additional_tx_keys = j->second;
10921 return true;
10922}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_tx_note()

std::string tools::wallet2::get_tx_note ( const crypto::hash & txid) const

Definition at line 11992 of file wallet2.cpp.

11993{
11994 std::unordered_map<crypto::hash, std::string>::const_iterator i = m_tx_notes.find(txid);
11995 if (i == m_tx_notes.end())
11996 return std::string();
11997 return i->second;
11998}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_tx_proof() [1/2]

std::string tools::wallet2::get_tx_proof ( const crypto::hash & txid,
const cryptonote::account_public_address & address,
bool is_subaddress,
const std::string & message )

Definition at line 11371 of file wallet2.cpp.

11372{
11373 // fetch tx pubkey from the daemon
11376 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11377 req.decode_as_json = false;
11378 req.prune = true;
11379 m_daemon_rpc_mutex.lock();
11380 bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11381 m_daemon_rpc_mutex.unlock();
11382 THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
11383 error::wallet_internal_error, "Failed to get transaction from daemon");
11384
11385 cryptonote::transaction tx;
11386 crypto::hash tx_hash;
11387 if (res.txs.size() == 1)
11388 {
11389 ok = get_pruned_tx(res.txs.front(), tx, tx_hash);
11390 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11391 }
11392 else
11393 {
11394 cryptonote::blobdata tx_data;
11395 ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
11396 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11398 error::wallet_internal_error, "Failed to validate transaction from daemon");
11400 }
11401
11402 CHECK_AND_ASSERT_THROW_MES(tx.version == 1, "Tx proofs are for v1 transactions only");
11403 THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
11404
11405 // determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound)
11407 std::vector<crypto::secret_key> additional_tx_keys;
11408 const bool is_out = m_subaddresses.count(address.m_spend_public_key) == 0;
11409 if (is_out)
11410 {
11411 THROW_WALLET_EXCEPTION_IF(!get_tx_key(txid, tx_key, additional_tx_keys), error::wallet_internal_error, "Tx secret key wasn't found in the wallet file.");
11412 }
11413
11414 return get_tx_proof(tx, tx_key, additional_tx_keys, address, is_subaddress, message);
11415}
bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys)
std::string get_tx_proof(const crypto::hash &txid, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message)
const crypto::secret_key null_skey
Definition crypto.cpp:73
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_tx_proof() [2/2]

std::string tools::wallet2::get_tx_proof ( const cryptonote::transaction & tx,
const crypto::secret_key & tx_key,
const std::vector< crypto::secret_key > & additional_tx_keys,
const cryptonote::account_public_address & address,
bool is_subaddress,
const std::string & message ) const

Definition at line 11417 of file wallet2.cpp.

11418{
11419 hw::device &hwdev = m_account.get_device();
11420 rct::key aP;
11421 // determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound)
11422 const bool is_out = m_subaddresses.count(address.m_spend_public_key) == 0;
11423
11425 std::string prefix_data((const char*)&txid, sizeof(crypto::hash));
11426 prefix_data += message;
11427 crypto::hash prefix_hash;
11428 crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11429
11430 std::vector<crypto::public_key> shared_secret;
11431 std::vector<crypto::signature> sig;
11432 std::string sig_str;
11433 if (is_out)
11434 {
11435 const size_t num_sigs = 1 + additional_tx_keys.size();
11436 shared_secret.resize(num_sigs);
11437 sig.resize(num_sigs);
11438
11439 hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key));
11440 shared_secret[0] = rct::rct2pk(aP);
11441 crypto::public_key tx_pub_key;
11442 if (is_subaddress)
11443 {
11444 hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key));
11445 tx_pub_key = rct2pk(aP);
11446 hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], tx_key, sig[0]);
11447 }
11448 else
11449 {
11450 hwdev.secret_key_to_public_key(tx_key, tx_pub_key);
11451 hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]);
11452 }
11453 for (size_t i = 1; i < num_sigs; ++i)
11454 {
11455 hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
11456 shared_secret[i] = rct::rct2pk(aP);
11457 if (is_subaddress)
11458 {
11459 hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
11460 tx_pub_key = rct2pk(aP);
11461 hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
11462 }
11463 else
11464 {
11465 hwdev.secret_key_to_public_key(additional_tx_keys[i - 1], tx_pub_key);
11466 hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
11467 }
11468 }
11469 sig_str = std::string("OutProofV1");
11470 }
11471 else
11472 {
11474 THROW_WALLET_EXCEPTION_IF(tx_pub_key == null_pkey, error::wallet_internal_error, "Tx pubkey was not found");
11475
11476 std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
11477 const size_t num_sigs = 1 + additional_tx_pub_keys.size();
11478 shared_secret.resize(num_sigs);
11479 sig.resize(num_sigs);
11480
11481 const crypto::secret_key& a = m_account.get_keys().m_view_secret_key;
11482 hwdev.scalarmultKey(aP, rct::pk2rct(tx_pub_key), rct::sk2rct(a));
11483 shared_secret[0] = rct2pk(aP);
11484 if (is_subaddress)
11485 {
11486 hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], a, sig[0]);
11487 }
11488 else
11489 {
11490 hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], a, sig[0]);
11491 }
11492 for (size_t i = 1; i < num_sigs; ++i)
11493 {
11494 hwdev.scalarmultKey(aP,rct::pk2rct(additional_tx_pub_keys[i - 1]), rct::sk2rct(a));
11495 shared_secret[i] = rct2pk(aP);
11496 if (is_subaddress)
11497 {
11498 hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], address.m_spend_public_key, shared_secret[i], a, sig[i]);
11499 }
11500 else
11501 {
11502 hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], boost::none, shared_secret[i], a, sig[i]);
11503 }
11504 }
11505 sig_str = std::string("InProofV1");
11506 }
11507 const size_t num_sigs = shared_secret.size();
11508
11509 // check if this address actually received any funds
11510 crypto::key_derivation derivation;
11511 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[0], rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
11512 std::vector<crypto::key_derivation> additional_derivations(num_sigs - 1);
11513 for (size_t i = 1; i < num_sigs; ++i)
11514 THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
11515 uint64_t received;
11516 check_tx_key_helper(tx, derivation, additional_derivations, address, received);
11517 THROW_WALLET_EXCEPTION_IF(!received, error::wallet_internal_error, tr("No funds received in this tx."));
11518
11519 // concatenate all signature strings
11520 for (size_t i = 0; i < num_sigs; ++i)
11521 sig_str +=
11522 tools::base58::encode(std::string((const char *)&shared_secret[i], sizeof(crypto::public_key))) +
11523 tools::base58::encode(std::string((const char *)&sig[i], sizeof(crypto::signature)));
11524 return sig_str;
11525}
virtual void generate_tx_proof(const crypto::hash &prefix_hash, const crypto::public_key &R, const crypto::public_key &A, const boost::optional< crypto::public_key > &B, const crypto::public_key &D, const crypto::secret_key &r, crypto::signature &sig)=0
virtual bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub)=0
virtual bool scalarmultKey(rct::key &aP, const rct::key &P, const rct::key &a)=0
Here is the call graph for this function:

◆ get_tx_pub_key_from_received_outs()

crypto::public_key tools::wallet2::get_tx_pub_key_from_received_outs ( const tools::wallet2::transfer_details & td) const

Definition at line 12143 of file wallet2.cpp.

12144{
12145 std::vector<tx_extra_field> tx_extra_fields;
12146 if(!parse_tx_extra(td.m_tx.extra, tx_extra_fields))
12147 {
12148 // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
12149 }
12150
12151 // Due to a previous bug, there might be more than one tx pubkey in extra, one being
12152 // the result of a previously discarded signature.
12153 // For speed, since scanning for outputs is a slow process, we check whether extra
12154 // contains more than one pubkey. If not, the first one is returned. If yes, they're
12155 // checked for whether they yield at least one output
12156 tx_extra_pub_key pub_key_field;
12157 THROW_WALLET_EXCEPTION_IF(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 0), error::wallet_internal_error,
12158 "Public key wasn't found in the transaction extra");
12159 const crypto::public_key tx_pub_key = pub_key_field.pub_key;
12160 bool two_found = find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 1);
12161 if (!two_found) {
12162 // easy case, just one found
12163 return tx_pub_key;
12164 }
12165
12166 // more than one, loop and search
12167 const cryptonote::account_keys& keys = m_account.get_keys();
12168 size_t pk_index = 0;
12169 hw::device &hwdev = m_account.get_device();
12170
12171 while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) {
12172 const crypto::public_key tx_pub_key = pub_key_field.pub_key;
12173 crypto::key_derivation derivation;
12174 bool r = hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
12175 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
12176
12177 for (size_t i = 0; i < td.m_tx.vout.size(); ++i)
12178 {
12179 tx_scan_info_t tx_scan_info;
12180 check_acc_out_precomp(td.m_tx.vout[i], derivation, {}, i, tx_scan_info);
12181 if (!tx_scan_info.error && tx_scan_info.received)
12182 return tx_pub_key;
12183 }
12184 }
12185
12186 // we found no key yielding an output, but it might be in the additional
12187 // tx pub keys only, which we do not need to check, so return the first one
12188 return tx_pub_key;
12189}
virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation)=0
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
crypto::public_key pub_key
Definition tx_extra.h:102
cryptonote::transaction_prefix m_tx
Definition wallet2.h:304
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_unconfirmed_payments()

void tools::wallet2::get_unconfirmed_payments ( std::list< std::pair< crypto::hash, wallet2::pool_payment_details > > & unconfirmed_payments,
const boost::optional< uint32_t > & subaddr_account = boost::none,
const std::set< uint32_t > & subaddr_indices = {} ) const

Definition at line 6408 of file wallet2.cpp.

6409{
6410 for (auto i = m_unconfirmed_payments.begin(); i != m_unconfirmed_payments.end(); ++i) {
6411 if ((!subaddr_account || *subaddr_account == i->second.m_pd.m_subaddr_index.major) &&
6412 (subaddr_indices.empty() || subaddr_indices.count(i->second.m_pd.m_subaddr_index.minor) == 1))
6413 unconfirmed_payments.push_back(*i);
6414 }
6415}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_unconfirmed_payments_out()

void tools::wallet2::get_unconfirmed_payments_out ( std::list< std::pair< crypto::hash, wallet2::unconfirmed_transfer_details > > & unconfirmed_payments,
const boost::optional< uint32_t > & subaddr_account = boost::none,
const std::set< uint32_t > & subaddr_indices = {} ) const

Definition at line 6396 of file wallet2.cpp.

6397{
6398 for (auto i = m_unconfirmed_txs.begin(); i != m_unconfirmed_txs.end(); ++i) {
6399 if (subaddr_account && *subaddr_account != i->second.m_subaddr_account)
6400 continue;
6401 if (!subaddr_indices.empty() && std::count_if(i->second.m_subaddr_indices.begin(), i->second.m_subaddr_indices.end(), [&subaddr_indices](uint32_t index) { return subaddr_indices.count(index) == 1; }) == 0)
6402 continue;
6403 unconfirmed_payments.push_back(*i);
6404 }
6405}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_wallet_file()

std::string tools::wallet2::get_wallet_file ( ) const

Definition at line 11916 of file wallet2.cpp.

11917{
11918 return m_wallet_file;
11919}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_multisig_partial_key_images()

bool tools::wallet2::has_multisig_partial_key_images ( ) const

Definition at line 5647 of file wallet2.cpp.

5648{
5649 if (!m_multisig)
5650 return false;
5651 for (const auto &td: m_transfers)
5652 if (td.m_key_image_partial && td.m_tx.version == 1)
5653 return true;
5654 return false;
5655}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_stagenet_option()

bool tools::wallet2::has_stagenet_option ( const boost::program_options::variables_map & vm)
static

Definition at line 1178 of file wallet2.cpp.

1179{
1180 return command_line::get_arg(vm, options().stagenet);
1181}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_testnet_option()

bool tools::wallet2::has_testnet_option ( const boost::program_options::variables_map & vm)
static

Definition at line 1173 of file wallet2.cpp.

1174{
1175 return command_line::get_arg(vm, options().testnet);
1176}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_unknown_key_images()

bool tools::wallet2::has_unknown_key_images ( ) const

Definition at line 5657 of file wallet2.cpp.

5658{
5659 for (const auto &td: m_transfers)
5660 if (!td.m_key_image_known && td.m_tx.version == 1)
5661 return true;
5662 return false;
5663}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hash_m_transfer()

void tools::wallet2::hash_m_transfer ( const transfer_details & transfer,
crypto::hash & hash ) const

Definition at line 13699 of file wallet2.cpp.

13700{
13701 KECCAK_CTX state;
13702 keccak_init(&state);
13703 keccak_update(&state, (const uint8_t *) transfer.m_txid.data, sizeof(transfer.m_txid.data));
13704 keccak_update(&state, (const uint8_t *) transfer.m_internal_output_index, sizeof(transfer.m_internal_output_index));
13705 keccak_update(&state, (const uint8_t *) transfer.m_global_output_index, sizeof(transfer.m_global_output_index));
13706 keccak_update(&state, (const uint8_t *) transfer.m_amount, sizeof(transfer.m_amount));
13707 keccak_finish(&state, (uint8_t *) hash.data);
13708}
void keccak_finish(KECCAK_CTX *ctx, uint8_t *md)
void keccak_update(KECCAK_CTX *ctx, const uint8_t *in, size_t inlen)
struct KECCAK_CTX KECCAK_CTX
void keccak_init(KECCAK_CTX *ctx)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hash_m_transfers()

uint64_t tools::wallet2::hash_m_transfers ( int64_t transfer_height,
crypto::hash & hash ) const

Definition at line 13710 of file wallet2.cpp.

13711{
13712 CHECK_AND_ASSERT_THROW_MES(transfer_height > (int64_t)m_transfers.size(), "Hash height is greater than number of transfers");
13713
13714 KECCAK_CTX state;
13715 crypto::hash tmp_hash{};
13716 uint64_t current_height = 0;
13717
13718 keccak_init(&state);
13719 for(const transfer_details & transfer : m_transfers){
13720 if (transfer_height >= 0 && current_height >= (uint64_t)transfer_height){
13721 break;
13722 }
13723
13724 hash_m_transfer(transfer, tmp_hash);
13725 keccak_update(&state, (const uint8_t *) transfer.m_block_height, sizeof(transfer.m_block_height));
13726 keccak_update(&state, (const uint8_t *) tmp_hash.data, sizeof(tmp_hash.data));
13727 current_height += 1;
13728 }
13729
13730 keccak_finish(&state, (uint8_t *) hash.data);
13731 return current_height;
13732}
void hash_m_transfer(const transfer_details &transfer, crypto::hash &hash) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ignore_fractional_outputs() [1/2]

bool tools::wallet2::ignore_fractional_outputs ( ) const
inline

Definition at line 1101 of file wallet2.h.

1101{ return m_ignore_fractional_outputs; }

◆ ignore_fractional_outputs() [2/2]

void tools::wallet2::ignore_fractional_outputs ( bool value)
inline

Definition at line 1102 of file wallet2.h.

1102{ m_ignore_fractional_outputs = value; }

◆ import_blockchain()

void tools::wallet2::import_blockchain ( const std::tuple< size_t, crypto::hash, std::vector< crypto::hash > > & bc)

Definition at line 12703 of file wallet2.cpp.

12704{
12705 m_blockchain.clear();
12706 if (std::get<0>(bc))
12707 {
12708 for (size_t n = std::get<0>(bc); n > 0; --n)
12709 m_blockchain.push_back(std::get<1>(bc));
12710 m_blockchain.trim(std::get<0>(bc));
12711 }
12712 for (auto const &b : std::get<2>(bc))
12713 {
12714 m_blockchain.push_back(b);
12715 }
12716 cryptonote::block genesis;
12717 generate_genesis(genesis);
12718 crypto::hash genesis_hash = get_block_hash(genesis);
12719 check_genesis(genesis_hash);
12720 m_last_block_reward = cryptonote::get_outs_etn_amount(genesis.miner_tx);
12721}
uint64_t get_outs_etn_amount(const transaction &tx)
crypto::hash get_block_hash(uint64_t height)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_key_images() [1/4]

uint64_t tools::wallet2::import_key_images ( const std::string & filename,
uint64_t & spent,
uint64_t & unspent )

Definition at line 12278 of file wallet2.cpp.

12279{
12280 PERF_TIMER(import_key_images_fsu);
12281 std::string data;
12282 bool r = epee::file_io_utils::load_file_to_string(filename, data);
12283
12284 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename);
12285
12286 const size_t magiclen = strlen(KEY_IMAGE_EXPORT_FILE_MAGIC);
12287 if (data.size() < magiclen || memcmp(data.data(), KEY_IMAGE_EXPORT_FILE_MAGIC, magiclen))
12288 {
12289 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad key image export file magic in ") + filename);
12290 }
12291
12292 try
12293 {
12294 PERF_TIMER(import_key_images_decrypt);
12295 data = decrypt_with_view_secret_key(std::string(data, magiclen));
12296 }
12297 catch (const std::exception &e)
12298 {
12299 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt ") + filename + ": " + e.what());
12300 }
12301
12302 const size_t headerlen = 4 + 2 * sizeof(crypto::public_key);
12303 THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, std::string("Bad data size from file ") + filename);
12304 const uint32_t offset = (uint8_t)data[0] | (((uint8_t)data[1]) << 8) | (((uint8_t)data[2]) << 16) | (((uint8_t)data[3]) << 24);
12305 const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[4];
12306 const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[4 + sizeof(crypto::public_key)];
12307 const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
12308 if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key)
12309 {
12310 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string( "Key images from ") + filename + " are for a different account");
12311 }
12312 THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Offset larger than known outputs");
12313
12314 const size_t record_size = sizeof(crypto::key_image) + sizeof(crypto::signature);
12315 THROW_WALLET_EXCEPTION_IF((data.size() - headerlen) % record_size,
12316 error::wallet_internal_error, std::string("Bad data size from file ") + filename);
12317 size_t nki = (data.size() - headerlen) / record_size;
12318
12319 std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
12320 ski.reserve(nki);
12321 for (size_t n = 0; n < nki; ++n)
12322 {
12323 crypto::key_image key_image = *reinterpret_cast<const crypto::key_image*>(&data[headerlen + n * record_size]);
12324 crypto::signature signature = *reinterpret_cast<const crypto::signature*>(&data[headerlen + n * record_size + sizeof(crypto::key_image)]);
12325
12326 ski.push_back(std::make_pair(key_image, signature));
12327 }
12328
12329 return import_key_images(ski, offset, spent, unspent);
12330}
std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated=true) const
bool load_file_to_string(const std::string &path_to_file, std::string &target_str, size_t max_size=1000000000)
#define THROW_WALLET_EXCEPTION(err_type,...)
Here is the call graph for this function:

◆ import_key_images() [2/4]

uint64_t tools::wallet2::import_key_images ( const std::vector< std::pair< crypto::key_image, crypto::signature > > & signed_key_images,
size_t offset,
uint64_t & spent,
uint64_t & unspent,
bool check_spent = true )

Definition at line 12333 of file wallet2.cpp.

12334{
12335 PERF_TIMER(import_key_images_lots);
12338
12339 THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Offset larger than known outputs");
12340 THROW_WALLET_EXCEPTION_IF(signed_key_images.size() > m_transfers.size() - offset, error::wallet_internal_error,
12341 "The blockchain is out of date compared to the signed key images");
12342
12343 if (signed_key_images.empty() && offset == 0)
12344 {
12345 spent = 0;
12346 unspent = 0;
12347 return 0;
12348 }
12349
12350 req.key_images.reserve(signed_key_images.size());
12351
12352 PERF_TIMER_START(import_key_images_A);
12353 for (size_t n = 0; n < signed_key_images.size(); ++n)
12354 {
12355 const transfer_details &td = m_transfers[n + offset];
12356 const crypto::key_image &key_image = signed_key_images[n].first;
12357 const crypto::signature &signature = signed_key_images[n].second;
12358
12359 // get ephemeral public key
12360 const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index];
12361 THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error,
12362 "Non txout_to_key output found");
12363 const cryptonote::txout_to_key &o = boost::get<cryptonote::txout_to_key>(out.target);
12364 const crypto::public_key pkey = o.key;
12365
12366 if (!td.m_key_image_known || !(key_image == td.m_key_image))
12367 {
12368 std::vector<const crypto::public_key*> pkeys;
12369 pkeys.push_back(&pkey);
12371 error::wallet_internal_error, "Key image out of validity domain: input " + boost::lexical_cast<std::string>(n + offset) + "/"
12372 + boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image));
12373
12375 error::signature_check_failed, boost::lexical_cast<std::string>(n + offset) + "/"
12376 + boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image)
12377 + ", signature " + epee::string_tools::pod_to_hex(signature) + ", pubkey " + epee::string_tools::pod_to_hex(*pkeys[0]));
12378 }
12379 req.key_images.push_back(epee::string_tools::pod_to_hex(key_image));
12380 }
12381 PERF_TIMER_STOP(import_key_images_A);
12382
12383 PERF_TIMER_START(import_key_images_B);
12384 for (size_t n = 0; n < signed_key_images.size(); ++n)
12385 {
12386 m_transfers[n + offset].m_key_image = signed_key_images[n].first;
12387 m_key_images[m_transfers[n + offset].m_key_image] = n + offset;
12388 m_transfers[n + offset].m_key_image_known = true;
12389 m_transfers[n + offset].m_key_image_request = false;
12390 m_transfers[n + offset].m_key_image_partial = false;
12391 }
12392 PERF_TIMER_STOP(import_key_images_B);
12393
12394 if(check_spent)
12395 {
12396 PERF_TIMER(import_key_images_RPC);
12397 m_daemon_rpc_mutex.lock();
12398 bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout);
12399 m_daemon_rpc_mutex.unlock();
12400 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
12401 THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
12402 THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
12403 THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
12404 "daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
12405 std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
12406 for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
12407 {
12408 transfer_details &td = m_transfers[n + offset];
12409 td.m_spent = daemon_resp.spent_status[n] != SPENT_STATUS::UNSPENT;
12410 }
12411 }
12412 spent = 0;
12413 unspent = 0;
12414 std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input.
12415 std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
12416 // was created by sweep_all, so we can't know the spent height and other detailed info.
12417 std::unordered_map<crypto::key_image, crypto::hash> spent_key_images;
12418
12419 PERF_TIMER_START(import_key_images_C);
12420 for (const transfer_details &td: m_transfers)
12421 {
12422 for (const cryptonote::txin_v& in : td.m_tx.vin)
12423 {
12424 if (in.type() == typeid(cryptonote::txin_to_key))
12425 spent_key_images.insert(std::make_pair(boost::get<cryptonote::txin_to_key>(in).k_image, td.m_txid));
12426 }
12427 }
12428 PERF_TIMER_STOP(import_key_images_C);
12429
12430 // accumulate outputs before the updated data
12431 for(size_t i = 0; i < offset; ++i)
12432 {
12433 const transfer_details &td = m_transfers[i];
12434 if (td.m_frozen)
12435 continue;
12436 uint64_t amount = td.amount();
12437 if (td.m_spent)
12438 spent += amount;
12439 else
12440 unspent += amount;
12441 }
12442
12443 PERF_TIMER_START(import_key_images_D);
12444 for(size_t i = 0; i < signed_key_images.size(); ++i)
12445 {
12446 const transfer_details &td = m_transfers[i + offset];
12447 if (td.m_frozen)
12448 continue;
12449 uint64_t amount = td.amount();
12450 if (td.m_spent)
12451 spent += amount;
12452 else
12453 unspent += amount;
12454 LOG_PRINT_L2("Transfer " << i << ": " << print_etn(amount) << " (" << td.m_global_output_index << "): "
12455 << (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[i] << ")");
12456
12457 if (i < daemon_resp.spent_status.size() && daemon_resp.spent_status[i] == SPENT_STATUS::SPENT_IN_BLOCKCHAIN)
12458 {
12459 const std::unordered_map<crypto::key_image, crypto::hash>::const_iterator skii = spent_key_images.find(td.m_key_image);
12460 if (skii == spent_key_images.end())
12461 swept_transfers.push_back(i);
12462 else
12463 spent_txids.insert(skii->second);
12464 }
12465 }
12466 PERF_TIMER_STOP(import_key_images_D);
12467
12468 MDEBUG("Total: " << print_etn(spent) << " spent, " << print_etn(unspent) << " unspent");
12469
12470 if (check_spent)
12471 {
12472 // query outgoing txes
12475 gettxs_req.decode_as_json = false;
12476 gettxs_req.prune = true;
12477 gettxs_req.txs_hashes.reserve(spent_txids.size());
12478 for (const crypto::hash& spent_txid : spent_txids)
12479 gettxs_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(spent_txid));
12480
12481
12482 PERF_TIMER_START(import_key_images_E);
12483 m_daemon_rpc_mutex.lock();
12484 bool r = invoke_http_json("/gettransactions", gettxs_req, gettxs_res, rpc_timeout);
12485 m_daemon_rpc_mutex.unlock();
12486 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
12487 THROW_WALLET_EXCEPTION_IF(gettxs_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
12488 THROW_WALLET_EXCEPTION_IF(gettxs_res.txs.size() != spent_txids.size(), error::wallet_internal_error,
12489 "daemon returned wrong response for gettransactions, wrong count = " + std::to_string(gettxs_res.txs.size()) + ", expected " + std::to_string(spent_txids.size()));
12490 PERF_TIMER_STOP(import_key_images_E);
12491
12492 // process each outgoing tx
12493 PERF_TIMER_START(import_key_images_F);
12494 auto spent_txid = spent_txids.begin();
12495 hw::device &hwdev = m_account.get_device();
12496 auto it = spent_txids.begin();
12497 for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs)
12498 {
12499 THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool");
12500
12501 cryptonote::transaction spent_tx;
12502 crypto::hash spnet_txid_parsed;
12503 THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(e, spent_tx, spnet_txid_parsed), error::wallet_internal_error, "Failed to get tx from daemon");
12504 THROW_WALLET_EXCEPTION_IF(!(spnet_txid_parsed == *it), error::wallet_internal_error, "parsed txid mismatch");
12505 ++it;
12506
12507 // get received (change) amount
12508 uint64_t tx_etn_got_in_outs = 0;
12509 const cryptonote::account_keys& keys = m_account.get_keys();
12510 const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx);
12511 crypto::key_derivation derivation;
12512 bool r = hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
12513 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
12514 const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(spent_tx);
12515 std::vector<crypto::key_derivation> additional_derivations;
12516 for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
12517 {
12518 additional_derivations.push_back({});
12519 r = hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back());
12520 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
12521 }
12522 size_t output_index = 0;
12523 bool miner_tx = cryptonote::is_coinbase(spent_tx);
12524 for (const cryptonote::tx_out& out : spent_tx.vout)
12525 {
12526 tx_scan_info_t tx_scan_info;
12527 check_acc_out_precomp(out, derivation, additional_derivations, output_index, tx_scan_info);
12528 THROW_WALLET_EXCEPTION_IF(tx_scan_info.error, error::wallet_internal_error, "check_acc_out_precomp failed");
12529 if (tx_scan_info.received)
12530 {
12531 if (tx_scan_info.etn_transfered == 0 && !miner_tx)
12532 {
12533 rct::key mask;
12534 tx_scan_info.etn_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask, hwdev);
12535 }
12536 THROW_WALLET_EXCEPTION_IF(tx_etn_got_in_outs >= std::numeric_limits<uint64_t>::max() - tx_scan_info.etn_transfered,
12537 error::wallet_internal_error, "Overflow in received amounts");
12538 tx_etn_got_in_outs += tx_scan_info.etn_transfered;
12539 }
12540 ++output_index;
12541 }
12542
12543 // get spent amount
12544 uint64_t tx_etn_spent_in_ins = 0;
12545 uint32_t subaddr_account = (uint32_t)-1;
12546 std::set<uint32_t> subaddr_indices;
12547 for (const cryptonote::txin_v& in : spent_tx.vin)
12548 {
12549 if (in.type() != typeid(cryptonote::txin_to_key))
12550 continue;
12551 auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
12552 if (it != m_key_images.end())
12553 {
12554 THROW_WALLET_EXCEPTION_IF(it->second >= m_transfers.size(), error::wallet_internal_error, std::string("Key images cache contains illegal transfer offset: ") + std::to_string(it->second) + std::string(" m_transfers.size() = ") + std::to_string(m_transfers.size()));
12555 const transfer_details& td = m_transfers[it->second];
12556 uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
12557 if (amount > 0)
12558 {
12559 THROW_WALLET_EXCEPTION_IF(amount != td.amount(), error::wallet_internal_error,
12560 std::string("Inconsistent amount in tx input: got ") + print_etn(amount) +
12561 std::string(", expected ") + print_etn(td.amount()));
12562 }
12563 amount = td.amount();
12564 tx_etn_spent_in_ins += amount;
12565
12566 LOG_PRINT_L0("Spent ETN: " << print_etn(amount) << ", with tx: " << *spent_txid);
12567 set_spent(it->second, e.block_height);
12568 if (m_callback)
12569 m_callback->on_etn_spent(e.block_height, *spent_txid, spent_tx, amount, spent_tx, td.m_subaddr_index);
12570 if (subaddr_account != (uint32_t)-1 && subaddr_account != td.m_subaddr_index.major)
12571 LOG_PRINT_L0("WARNING: This tx spends outputs received by different subaddress accounts, which isn't supposed to happen");
12572 subaddr_account = td.m_subaddr_index.major;
12573 subaddr_indices.insert(td.m_subaddr_index.minor);
12574 }
12575 }
12576
12577 // create outgoing payment
12578 process_outgoing(*spent_txid, spent_tx, e.block_height, e.block_timestamp, tx_etn_spent_in_ins, tx_etn_got_in_outs, subaddr_account, subaddr_indices);
12579
12580 // erase corresponding incoming payment
12581 for (auto j = m_payments.begin(); j != m_payments.end(); ++j)
12582 {
12583 if (j->second.m_tx_hash == *spent_txid)
12584 {
12585 m_payments.erase(j);
12586 break;
12587 }
12588 }
12589
12590 ++spent_txid;
12591 }
12592 PERF_TIMER_STOP(import_key_images_F);
12593
12594 PERF_TIMER_START(import_key_images_G);
12595 for (size_t n : swept_transfers)
12596 {
12597 const transfer_details& td = m_transfers[n];
12599 pd.m_change = (uint64_t)-1; // change is unknown
12600 pd.m_amount_in = pd.m_amount_out = td.amount(); // fee is unknown
12601 pd.m_block_height = 0; // spent block height is unknown
12602 pd.m_is_migration = td.m_tx.version == 2;
12603 if(td.m_tx.version == 3){
12604 cryptonote::account_public_address dest_address = boost::get<cryptonote::txout_to_key_public>(td.m_tx.vout[0].target).address;
12605 bool is_portal_address;
12606 if(m_nettype == MAINNET){
12607 is_portal_address = epee::string_tools::pod_to_hex(dest_address.m_spend_public_key) == "8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137" && epee::string_tools::pod_to_hex(dest_address.m_view_public_key) == "2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
12608 }else{
12609 is_portal_address = epee::string_tools::pod_to_hex(dest_address.m_spend_public_key) == "5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3" && epee::string_tools::pod_to_hex(dest_address.m_view_public_key) == "5866666666666666666666666666666666666666666666666666666666666666";
12610 }
12611 pd.m_is_sc_migration = is_portal_address;
12612 }
12613 const crypto::hash &spent_txid = crypto::null_hash; // spent txid is unknown
12614 m_confirmed_txs.insert(std::make_pair(spent_txid, pd));
12615 }
12616 PERF_TIMER_STOP(import_key_images_G);
12617 }
12618
12619 // this can be 0 if we do not know the height
12620 return m_transfers[signed_key_images.size() + offset - 1].m_block_height;
12621}
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
bool is_coinbase(const transaction &tx)
key curveOrder()
Definition rctOps.h:76
#define PERF_TIMER_START(name)
Definition perf_timer.h:85
#define PERF_TIMER_STOP(name)
Definition perf_timer.h:86
Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_key_images() [3/4]

bool tools::wallet2::import_key_images ( signed_tx_set & signed_tx,
size_t offset = 0,
bool only_selected_transfers = false )

Definition at line 12650 of file wallet2.cpp.

12651{
12652 std::unordered_set<size_t> selected_transfers;
12653 if (only_selected_transfers)
12654 {
12655 for (const pending_tx & ptx : signed_tx.ptx)
12656 {
12657 for (const size_t s: ptx.selected_transfers)
12658 selected_transfers.insert(s);
12659 }
12660 }
12661
12662 return import_key_images(signed_tx.key_images, offset, only_selected_transfers ? boost::make_optional(selected_transfers) : boost::none);
12663}
Here is the call graph for this function:

◆ import_key_images() [4/4]

bool tools::wallet2::import_key_images ( std::vector< crypto::key_image > key_images,
size_t offset = 0,
boost::optional< std::unordered_set< size_t > > selected_transfers = boost::none )

Definition at line 12623 of file wallet2.cpp.

12624{
12625 if (key_images.size() + offset > m_transfers.size())
12626 {
12627 LOG_PRINT_L1("More key images returned that we know outputs for");
12628 return false;
12629 }
12630 for (size_t ki_idx = 0; ki_idx < key_images.size(); ++ki_idx)
12631 {
12632 const size_t transfer_idx = ki_idx + offset;
12633 if (selected_transfers && selected_transfers.get().find(transfer_idx) == selected_transfers.get().end())
12634 continue;
12635
12636 transfer_details &td = m_transfers[transfer_idx];
12637 if (td.m_key_image_known && !td.m_key_image_partial && td.m_key_image != key_images[ki_idx])
12638 LOG_PRINT_L0("WARNING: imported key image differs from previously known key image at index " << ki_idx << ": trusting imported one");
12639 td.m_key_image = key_images[ki_idx];
12640 m_key_images[td.m_key_image] = transfer_idx;
12641 td.m_key_image_known = true;
12642 td.m_key_image_request = false;
12643 td.m_key_image_partial = false;
12644 m_pub_keys[td.get_public_key()] = transfer_idx;
12645 }
12646
12647 return true;
12648}
Here is the call graph for this function:

◆ import_multisig()

size_t tools::wallet2::import_multisig ( std::vector< cryptonote::blobdata > info)

Import a set of multisig info from multisig partners

Returns
the number of inputs which were imported

Definition at line 13067 of file wallet2.cpp.

13068{
13069 CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
13070
13071 std::vector<std::vector<tools::wallet2::multisig_info>> info;
13072 std::unordered_set<crypto::public_key> seen;
13073 for (cryptonote::blobdata &data: blobs)
13074 {
13075 const size_t magiclen = strlen(MULTISIG_EXPORT_FILE_MAGIC);
13076 THROW_WALLET_EXCEPTION_IF(data.size() < magiclen || memcmp(data.data(), MULTISIG_EXPORT_FILE_MAGIC, magiclen),
13077 error::wallet_internal_error, "Bad multisig info file magic in ");
13078
13079 data = decrypt_with_view_secret_key(std::string(data, magiclen));
13080
13081 const size_t headerlen = 3 * sizeof(crypto::public_key);
13082 THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, "Bad data size");
13083
13084 const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0];
13085 const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)];
13086 const crypto::public_key &signer = *(const crypto::public_key*)&data[2*sizeof(crypto::public_key)];
13087 const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
13088 THROW_WALLET_EXCEPTION_IF(public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key,
13089 error::wallet_internal_error, "Multisig info is for a different account");
13090 if (get_multisig_signer_public_key() == signer)
13091 {
13092 MINFO("Multisig info from this wallet ignored");
13093 continue;
13094 }
13095 if (seen.find(signer) != seen.end())
13096 {
13097 MINFO("Duplicate multisig info ignored");
13098 continue;
13099 }
13100 seen.insert(signer);
13101
13102 std::string body(data, headerlen);
13103 std::istringstream iss(body);
13104 std::vector<tools::wallet2::multisig_info> i;
13105 boost::archive::portable_binary_iarchive ar(iss);
13106 ar >> i;
13107 MINFO(boost::format("%u outputs found") % boost::lexical_cast<std::string>(i.size()));
13108 info.push_back(std::move(i));
13109 }
13110
13111 CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources");
13112
13113 std::vector<std::vector<rct::key>> k;
13114 k.reserve(m_transfers.size());
13115 for (const auto &td: m_transfers)
13116 k.push_back(td.m_multisig_k);
13117
13118 // how many outputs we're going to update
13119 size_t n_outputs = m_transfers.size();
13120 for (const auto &pi: info)
13121 if (pi.size() < n_outputs)
13122 n_outputs = pi.size();
13123
13124 if (n_outputs == 0)
13125 return 0;
13126
13127 // check signers are consistent
13128 for (const auto &pi: info)
13129 {
13130 CHECK_AND_ASSERT_THROW_MES(std::find(m_multisig_signers.begin(), m_multisig_signers.end(), pi[0].m_signer) != m_multisig_signers.end(),
13131 "Signer is not a member of this multisig wallet");
13132 for (size_t n = 1; n < n_outputs; ++n)
13133 CHECK_AND_ASSERT_THROW_MES(pi[n].m_signer == pi[0].m_signer, "Mismatched signers in imported multisig info");
13134 }
13135
13136 // trim data we don't have info for from all participants
13137 for (auto &pi: info)
13138 pi.resize(n_outputs);
13139
13140 // sort by signer
13141 if (!info.empty() && !info.front().empty())
13142 {
13143 std::sort(info.begin(), info.end(), [](const std::vector<tools::wallet2::multisig_info> &i0, const std::vector<tools::wallet2::multisig_info> &i1){ return memcmp(&i0[0].m_signer, &i1[0].m_signer, sizeof(i0[0].m_signer)); });
13144 }
13145
13146 // first pass to determine where to detach the blockchain
13147 for (size_t n = 0; n < n_outputs; ++n)
13148 {
13149 const transfer_details &td = m_transfers[n];
13150 if (!td.m_key_image_partial)
13151 continue;
13152 MINFO("Multisig info importing from block height " << td.m_block_height);
13153 detach_blockchain(td.m_block_height);
13154 break;
13155 }
13156
13157 for (size_t n = 0; n < n_outputs && n < m_transfers.size(); ++n)
13158 {
13159 update_multisig_rescan_info(k, info, n);
13160 }
13161
13162 m_multisig_rescan_k = &k;
13163 m_multisig_rescan_info = &info;
13164 try
13165 {
13166
13167 refresh(false);
13168 }
13169 catch (...)
13170 {
13171 m_multisig_rescan_info = NULL;
13172 m_multisig_rescan_k = NULL;
13173 throw;
13174 }
13175 m_multisig_rescan_info = NULL;
13176 m_multisig_rescan_k = NULL;
13177
13178 return n_outputs;
13179}
void refresh(bool trusted_daemon)
Definition wallet2.cpp:3060
Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_outputs()

size_t tools::wallet2::import_outputs ( const std::pair< size_t, std::vector< tools::wallet2::transfer_details > > & outputs)

Definition at line 12763 of file wallet2.cpp.

12764{
12766
12767 THROW_WALLET_EXCEPTION_IF(outputs.first > m_transfers.size(), error::wallet_internal_error,
12768 "Imported outputs omit more outputs that we know of");
12769
12770 const size_t offset = outputs.first;
12771 const size_t original_size = m_transfers.size();
12772 m_transfers.resize(offset + outputs.second.size());
12773 for (size_t i = 0; i < offset; ++i)
12774 m_transfers[i].m_key_image_request = false;
12775 for (size_t i = 0; i < outputs.second.size(); ++i)
12776 {
12777 transfer_details td = outputs.second[i];
12778
12779 // skip those we've already imported, or which have different data
12780 if (i + offset < original_size)
12781 {
12782 // compare the data used to create the key image below
12783 const transfer_details &org_td = m_transfers[i + offset];
12784 if (!org_td.m_key_image_known)
12785 goto process;
12786#define CMPF(f) if (!(td.f == org_td.f)) goto process
12787 CMPF(m_txid);
12788 CMPF(m_key_image);
12789 CMPF(m_internal_output_index);
12790#undef CMPF
12791 if (!(get_transaction_prefix_hash(td.m_tx) == get_transaction_prefix_hash(org_td.m_tx)))
12792 goto process;
12793
12794 // copy anyway, since the comparison does not include ancillary fields which may have changed
12795 m_transfers[i + offset] = std::move(td);
12796 continue;
12797 }
12798
12799process:
12800
12801 // the hot wallet wouldn't have known about key images (except if we already exported them)
12802 cryptonote::keypair in_ephemeral;
12803
12804 THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + boost::lexical_cast<std::string>(i + offset));
12806 const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
12807
12808 THROW_WALLET_EXCEPTION_IF(td.m_tx.vout[td.m_internal_output_index].target.type() != typeid(cryptonote::txout_to_key),
12809 error::wallet_internal_error, "Unsupported output type");
12810 const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
12811 bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), m_account_major_offset);
12812 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
12813 expand_subaddresses(td.m_subaddr_index);
12814 td.m_key_image_known = true;
12815 td.m_key_image_request = true;
12816 td.m_key_image_partial = false;
12817 THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
12818 error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i + offset));
12819
12820 m_key_images[td.m_key_image] = i + offset;
12821 m_pub_keys[td.get_public_key()] = i + offset;
12822 m_transfers[i + offset] = std::move(td);
12823 }
12824
12825 return m_transfers.size();
12826}
size_t import_outputs(const std::pair< size_t, std::vector< tools::wallet2::transfer_details > > &outputs)
void get_transaction_prefix_hash(const transaction_prefix &tx, crypto::hash &h)
#define CMPF(f)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_outputs_from_str()

size_t tools::wallet2::import_outputs_from_str ( const std::string & outputs_st)

Definition at line 12828 of file wallet2.cpp.

12829{
12831 std::string data = outputs_st;
12832 const size_t magiclen = strlen(OUTPUT_EXPORT_FILE_MAGIC);
12833 if (data.size() < magiclen || memcmp(data.data(), OUTPUT_EXPORT_FILE_MAGIC, magiclen))
12834 {
12835 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad magic from outputs"));
12836 }
12837
12838 try
12839 {
12840 PERF_TIMER(import_outputs_decrypt);
12841 data = decrypt_with_view_secret_key(std::string(data, magiclen));
12842 }
12843 catch (const std::exception &e)
12844 {
12845 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt outputs: ") + e.what());
12846 }
12847
12848 const size_t headerlen = 2 * sizeof(crypto::public_key);
12849 if (data.size() < headerlen)
12850 {
12851 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad data size for outputs"));
12852 }
12853 const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0];
12854 const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)];
12855 const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
12856 if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key)
12857 {
12858 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Outputs from are for a different account"));
12859 }
12860
12861 size_t imported_outputs = 0;
12862 try
12863 {
12864 std::string body(data, headerlen);
12865 std::stringstream iss;
12866 iss << body;
12867 std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
12868 try
12869 {
12870 boost::archive::portable_binary_iarchive ar(iss);
12871 ar >> outputs;
12872 }
12873 catch (...)
12874 {
12875 iss.str("");
12876 iss << body;
12877 boost::archive::binary_iarchive ar(iss);
12878 ar >> outputs;
12879 }
12880
12881 imported_outputs = import_outputs(outputs);
12882 }
12883 catch (const std::exception &e)
12884 {
12885 THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to import outputs") + e.what());
12886 }
12887
12888 return imported_outputs;
12889}
size_t import_outputs_from_str(const std::string &outputs_st)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_payments()

void tools::wallet2::import_payments ( const payment_container & payments)

Definition at line 12674 of file wallet2.cpp.

12675{
12676 m_payments.clear();
12677 for (auto const &p : payments)
12678 {
12679 m_payments.emplace(p);
12680 }
12681}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_payments_out()

void tools::wallet2::import_payments_out ( const std::list< std::pair< crypto::hash, wallet2::confirmed_transfer_details > > & confirmed_payments)

Definition at line 12682 of file wallet2.cpp.

12683{
12684 m_confirmed_txs.clear();
12685 for (auto const &p : confirmed_payments)
12686 {
12687 m_confirmed_txs.emplace(p);
12688 }
12689}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

bool tools::wallet2::init ( std::string daemon_address = "http://localhost:8080",
boost::optional< epee::net_utils::http::login > daemon_login = boost::none,
boost::asio::ip::tcp::endpoint proxy = {},
uint64_t upper_transaction_weight_limit = 0,
bool trusted_daemon = true,
epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
std::string blockchain_db_path = "" )

Definition at line 1282 of file wallet2.cpp.

1283{
1284 m_checkpoints.init_default_checkpoints(m_nettype);
1285 m_is_initialized = true;
1286 m_upper_transaction_weight_limit = upper_transaction_weight_limit;
1287
1288 if (proxy != boost::asio::ip::tcp::endpoint{})
1289 m_http_client.set_connector(net::socks::connector{std::move(proxy)});
1290 return set_daemon(daemon_address, daemon_login, trusted_daemon, std::move(ssl_options));
1291}
bool set_daemon(std::string daemon_address="http://localhost:8080", boost::optional< epee::net_utils::http::login > daemon_login=boost::none, bool trusted_daemon=true, epee::net_utils::ssl_options_t ssl_options=epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
Definition wallet2.cpp:1268
string daemon_address
Definition transfers.cpp:42
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_options()

void tools::wallet2::init_options ( boost::program_options::options_description & desc_params)
static

Definition at line 1193 of file wallet2.cpp.

1194{
1195 const options opts{};
1196 command_line::add_arg(desc_params, opts.daemon_address);
1197 command_line::add_arg(desc_params, opts.daemon_host);
1198 command_line::add_arg(desc_params, opts.proxy);
1199 command_line::add_arg(desc_params, opts.trusted_daemon);
1200 command_line::add_arg(desc_params, opts.untrusted_daemon);
1201 command_line::add_arg(desc_params, opts.password);
1202 command_line::add_arg(desc_params, opts.password_file);
1203 command_line::add_arg(desc_params, opts.daemon_port);
1204 command_line::add_arg(desc_params, opts.daemon_login);
1205 command_line::add_arg(desc_params, opts.daemon_ssl);
1206 command_line::add_arg(desc_params, opts.daemon_ssl_private_key);
1207 command_line::add_arg(desc_params, opts.daemon_ssl_certificate);
1208 command_line::add_arg(desc_params, opts.daemon_ssl_ca_certificates);
1209 command_line::add_arg(desc_params, opts.daemon_ssl_allowed_fingerprints);
1210 command_line::add_arg(desc_params, opts.daemon_ssl_allow_any_cert);
1211 command_line::add_arg(desc_params, opts.daemon_ssl_allow_chained);
1212 command_line::add_arg(desc_params, opts.testnet);
1213 command_line::add_arg(desc_params, opts.stagenet);
1214 command_line::add_arg(desc_params, opts.shared_ringdb_dir);
1215 command_line::add_arg(desc_params, opts.kdf_rounds);
1217 command_line::add_arg(desc_params, opts.hw_device);
1218 command_line::add_arg(desc_params, opts.hw_device_derivation_path);
1219 command_line::add_arg(desc_params, opts.tx_notify);
1220 command_line::add_arg(desc_params, opts.no_dns);
1221 command_line::add_arg(desc_params, opts.offline);
1222 command_line::add_arg(desc_params, opts.data_dir);
1223 command_line::add_arg(desc_params, opts.fallback_to_pow_checkpoint_height);
1224 command_line::add_arg(desc_params, opts.fallback_to_pow_checkpoint_hash);
1225}
static void init_options(boost::program_options::options_description &desc_params)
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ invoke_http_bin()

template<class t_request, class t_response>
bool tools::wallet2::invoke_http_bin ( const boost::string_ref uri,
const t_request & req,
t_response & res,
std::chrono::milliseconds timeout = std::chrono::seconds(15),
const boost::string_ref http_method = "GET" )
inline

Definition at line 1326 of file wallet2.h.

1327 {
1328 if (m_offline) return false;
1329 boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1330 return epee::net_utils::invoke_http_bin(uri, req, res, m_http_client, timeout, http_method);
1331 }
bool invoke_http_bin(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref method="GET")
Here is the call graph for this function:
Here is the caller graph for this function:

◆ invoke_http_json()

template<class t_request, class t_response>
bool tools::wallet2::invoke_http_json ( const boost::string_ref uri,
const t_request & req,
t_response & res,
std::chrono::milliseconds timeout = std::chrono::seconds(15),
const boost::string_ref http_method = "GET" )
inline

Definition at line 1319 of file wallet2.h.

1320 {
1321 if (m_offline) return false;
1322 boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1323 return epee::net_utils::invoke_http_json(uri, req, res, m_http_client, timeout, http_method);
1324 }
bool invoke_http_json(const boost::string_ref uri, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref method="GET")
Here is the call graph for this function:
Here is the caller graph for this function:

◆ invoke_http_json_rpc()

template<class t_request, class t_response>
bool tools::wallet2::invoke_http_json_rpc ( const boost::string_ref uri,
const std::string & method_name,
const t_request & req,
t_response & res,
std::chrono::milliseconds timeout = std::chrono::seconds(15),
const boost::string_ref http_method = "GET",
const std::string & req_id = "0" )
inline

Definition at line 1333 of file wallet2.h.

1334 {
1335 if (m_offline) return false;
1336 boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1337 return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, m_http_client, timeout, http_method, req_id);
1338 }
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET", const std::string &req_id="0")
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_deprecated()

bool tools::wallet2::is_deprecated ( ) const

Tells if the wallet file is deprecated.

Definition at line 1546 of file wallet2.cpp.

1547{
1548 return is_old_file_format;
1549}

◆ is_deterministic()

bool tools::wallet2::is_deterministic ( ) const

Checks if deterministic wallet.

Definition at line 1293 of file wallet2.cpp.

1294{
1295 crypto::secret_key second;
1296 keccak((uint8_t *)&get_account().get_keys().m_spend_secret_key, sizeof(crypto::secret_key), (uint8_t *)&second, sizeof(crypto::secret_key));
1297 sc_reduce32((uint8_t *)&second);
1298 return memcmp(second.data,get_account().get_keys().m_view_secret_key.data, sizeof(crypto::secret_key)) == 0;
1299}
void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_keys_file_locked()

bool tools::wallet2::is_keys_file_locked ( ) const

Definition at line 8236 of file wallet2.cpp.

8237{
8238 return m_keys_file_locker->locked();
8239}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_output_blackballed()

bool tools::wallet2::is_output_blackballed ( const std::pair< uint64_t, uint64_t > & output) const

Definition at line 8206 of file wallet2.cpp.

8207{
8208 if (!m_ringdb)
8209 return false;
8210 try { return m_ringdb->blackballed(output); }
8211 catch (const std::exception &e) { return false; }
8212}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_synced()

bool tools::wallet2::is_synced ( ) const

Definition at line 13480 of file wallet2.cpp.

13481{
13483 boost::optional<std::string> result = m_node_rpc_proxy.get_target_height(height);
13484 if (result && *result != CORE_RPC_STATUS_OK)
13485 return false;
13487}
uint64_t get_blockchain_current_height() const
Definition wallet2.h:898
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_transfer_unlocked() [1/2]

bool tools::wallet2::is_transfer_unlocked ( const transfer_details & td) const

Definition at line 6565 of file wallet2.cpp.

6566{
6567 return is_transfer_unlocked(td.m_tx.unlock_time, td.m_block_height);
6568}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_transfer_unlocked() [2/2]

bool tools::wallet2::is_transfer_unlocked ( uint64_t unlock_time,
uint64_t block_height ) const

Definition at line 6570 of file wallet2.cpp.

6571{
6572 if(!is_tx_spendtime_unlocked(unlock_time, block_height))
6573 return false;
6574
6575 uint64_t v8height = m_nettype == TESTNET ? 446674 : 589169;
6576 uint16_t UNLOCK_WINDOW = block_height > v8height ? ETN_DEFAULT_TX_SPENDABLE_AGE_V8 : CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
6577
6578 if(block_height + UNLOCK_WINDOW > get_blockchain_current_height())
6579 return false;
6580
6581 return true;
6582}
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const
Definition wallet2.cpp:6584
#define ETN_DEFAULT_TX_SPENDABLE_AGE_V8
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
unsigned short uint16_t
Definition stdint.h:125
Here is the call graph for this function:

◆ is_trusted_daemon()

bool tools::wallet2::is_trusted_daemon ( ) const
inline

Definition at line 765 of file wallet2.h.

765{ return m_trusted_daemon; }
Here is the caller graph for this function:

◆ is_tx_spendtime_unlocked()

bool tools::wallet2::is_tx_spendtime_unlocked ( uint64_t unlock_time,
uint64_t block_height ) const

Definition at line 6584 of file wallet2.cpp.

6585{
6586 if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
6587 {
6588 //interpret as block index
6590 return true;
6591 else
6592 return false;
6593 }else
6594 {
6595 //interpret as time
6596 uint64_t current_time = static_cast<uint64_t>(time(NULL));
6597 // XXX: this needs to be fast, so we'd need to get the starting heights
6598 // from the daemon to be correct once voting kicks in
6599 uint64_t v6height = m_nettype == TESTNET ? 190059 : 307499;
6601 if(current_time + leeway >= unlock_time)
6602 return true;
6603 else
6604 return false;
6605 }
6606 return false;
6607}
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V6
#define CRYPTONOTE_MAX_BLOCK_NUMBER
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_unattended()

bool tools::wallet2::is_unattended ( ) const
inline

Definition at line 1274 of file wallet2.h.

1274{ return m_unattended; }

◆ key_on_device()

bool tools::wallet2::key_on_device ( ) const
inline

Definition at line 830 of file wallet2.h.

hw::device::device_type get_device_type() const
Definition wallet2.h:831
Here is the call graph for this function:
Here is the caller graph for this function:

◆ key_reuse_mitigation2() [1/2]

bool tools::wallet2::key_reuse_mitigation2 ( ) const
inline

Definition at line 1097 of file wallet2.h.

1097{ return m_key_reuse_mitigation2; }

◆ key_reuse_mitigation2() [2/2]

void tools::wallet2::key_reuse_mitigation2 ( bool value)
inline

Definition at line 1098 of file wallet2.h.

1098{ m_key_reuse_mitigation2 = value; }

◆ light_wallet()

bool tools::wallet2::light_wallet ( ) const
inline

Checks if light wallet. A light wallet sends view key to a server where the blockchain is scanned.

Definition at line 777 of file wallet2.h.

777{ return m_light_wallet; }
Here is the caller graph for this function:

◆ light_wallet_get_address_info()

bool tools::wallet2::light_wallet_get_address_info ( tools::COMMAND_RPC_GET_ADDRESS_INFO::response & response)

Definition at line 9438 of file wallet2.cpp.

9439{
9440 MTRACE(__FUNCTION__);
9441
9443
9444 request.address = get_account().get_public_address_str(m_nettype);
9445 request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9446 m_daemon_rpc_mutex.lock();
9447 bool r = invoke_http_json("/get_address_info", request, response, rpc_timeout, "POST");
9448 m_daemon_rpc_mutex.unlock();
9449 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_info");
9450 // TODO: Validate result
9451 return true;
9452}
#define MTRACE(x)
Definition misc_log_ex.h:77
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ light_wallet_get_address_txs()

void tools::wallet2::light_wallet_get_address_txs ( )

Definition at line 9454 of file wallet2.cpp.

9455{
9456 MDEBUG("Refreshing light wallet");
9457
9460
9461 ireq.address = get_account().get_public_address_str(m_nettype);
9462 ireq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9463 m_daemon_rpc_mutex.lock();
9464 bool r = invoke_http_json("/get_address_txs", ireq, ires, rpc_timeout, "POST");
9465 m_daemon_rpc_mutex.unlock();
9466 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_txs");
9467 //OpenMonero sends status=success, Mymonero doesn't.
9468 THROW_WALLET_EXCEPTION_IF((!ires.status.empty() && ires.status != "success"), error::no_connection_to_daemon, "get_address_txs");
9469
9470
9471 // Abort if no transactions
9472 if(ires.transactions.empty())
9473 return;
9474
9475 // Create searchable vectors
9476 std::vector<crypto::hash> payments_txs;
9477 for(const auto &p: m_payments)
9478 payments_txs.push_back(p.second.m_tx_hash);
9479 std::vector<crypto::hash> unconfirmed_payments_txs;
9480 for(const auto &up: m_unconfirmed_payments)
9481 unconfirmed_payments_txs.push_back(up.second.m_pd.m_tx_hash);
9482
9483 // for balance calculation
9484 uint64_t wallet_total_sent = 0;
9485 // txs in pool
9486 std::vector<crypto::hash> pool_txs;
9487
9488 for (const auto &t: ires.transactions) {
9489 const uint64_t total_received = t.total_received;
9490 uint64_t total_sent = t.total_sent;
9491
9492 // Check key images - subtract fake outputs from total_sent
9493 for(const auto &so: t.spent_outputs)
9494 {
9495 crypto::public_key tx_public_key;
9497 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, so.tx_pub_key), error::wallet_internal_error, "Invalid tx_pub_key field");
9498 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, so.key_image), error::wallet_internal_error, "Invalid key_image field");
9499 string_tools::hex_to_pod(so.tx_pub_key, tx_public_key);
9500 string_tools::hex_to_pod(so.key_image, key_image);
9501
9502 if(!light_wallet_key_image_is_ours(key_image, tx_public_key, so.out_index)) {
9503 THROW_WALLET_EXCEPTION_IF(so.amount > t.total_sent, error::wallet_internal_error, "Lightwallet: total sent is negative!");
9504 total_sent -= so.amount;
9505 }
9506 }
9507
9508 // Do not add tx if empty.
9509 if(total_sent == 0 && total_received == 0)
9510 continue;
9511
9512 crypto::hash payment_id = null_hash;
9513 crypto::hash tx_hash;
9514
9515 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, t.payment_id), error::wallet_internal_error, "Invalid payment_id field");
9516 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, t.hash), error::wallet_internal_error, "Invalid hash field");
9517 string_tools::hex_to_pod(t.payment_id, payment_id);
9518 string_tools::hex_to_pod(t.hash, tx_hash);
9519
9520 // lightwallet specific info
9521 bool incoming = (total_received > total_sent);
9523 address_tx.m_tx_hash = tx_hash;
9524 address_tx.m_incoming = incoming;
9525 address_tx.m_amount = incoming ? total_received - total_sent : total_sent - total_received;
9526 address_tx.m_fee = 0; // TODO
9527 address_tx.m_block_height = t.height;
9528 address_tx.m_unlock_time = t.unlock_time;
9529 address_tx.m_timestamp = t.timestamp;
9530 address_tx.m_coinbase = t.coinbase;
9531 address_tx.m_mempool = t.mempool;
9532 m_light_wallet_address_txs.emplace(tx_hash,address_tx);
9533
9534 // populate data needed for history (m_payments, m_unconfirmed_payments, m_confirmed_txs)
9535 // INCOMING transfers
9536 if(total_received > total_sent) {
9537 payment_details payment;
9538 payment.m_tx_hash = tx_hash;
9539 payment.m_amount = total_received - total_sent;
9540 payment.m_fee = 0; // TODO
9541 payment.m_block_height = t.height;
9542 payment.m_unlock_time = t.unlock_time;
9543 payment.m_timestamp = t.timestamp;
9544 payment.m_coinbase = t.coinbase;
9545
9546 if (t.mempool) {
9547 if (std::find(unconfirmed_payments_txs.begin(), unconfirmed_payments_txs.end(), tx_hash) == unconfirmed_payments_txs.end()) {
9548 pool_txs.push_back(tx_hash);
9549 // assume false as we don't get that info from the light wallet server
9550 crypto::hash payment_id;
9552 error::wallet_internal_error, "Failed to parse payment id");
9553 emplace_or_replace(m_unconfirmed_payments, payment_id, pool_payment_details{payment, false, false});
9554 if (0 != m_callback) {
9555 m_callback->on_lw_unconfirmed_etn_received(t.height, payment.m_tx_hash, payment.m_amount);
9556 }
9557 }
9558 } else {
9559 if (std::find(payments_txs.begin(), payments_txs.end(), tx_hash) == payments_txs.end()) {
9560 m_payments.emplace(tx_hash, payment);
9561 if (0 != m_callback) {
9562 m_callback->on_lw_etn_received(t.height, payment.m_tx_hash, payment.m_amount);
9563 }
9564 }
9565 }
9566 // Outgoing transfers
9567 } else {
9568 uint64_t amount_sent = total_sent - total_received;
9569 cryptonote::transaction dummy_tx; // not used by light wallet
9570 // increase wallet total sent
9571 wallet_total_sent += total_sent;
9572 if (t.mempool)
9573 {
9574 // Handled by add_unconfirmed_tx in commit_tx
9575 // If sent from another wallet instance we need to add it
9576 if(m_unconfirmed_txs.find(tx_hash) == m_unconfirmed_txs.end())
9577 {
9579 utd.m_amount_in = amount_sent;
9580 utd.m_amount_out = amount_sent;
9581 utd.m_change = 0;
9582 utd.m_payment_id = payment_id;
9583 utd.m_timestamp = t.timestamp;
9585 m_unconfirmed_txs.emplace(tx_hash,utd);
9586 }
9587 }
9588 else
9589 {
9590 // Only add if new
9591 auto confirmed_tx = m_confirmed_txs.find(tx_hash);
9592 if(confirmed_tx == m_confirmed_txs.end()) {
9593 // tx is added to m_unconfirmed_txs - move to confirmed
9594 if(m_unconfirmed_txs.find(tx_hash) != m_unconfirmed_txs.end())
9595 {
9596 process_unconfirmed(tx_hash, dummy_tx, t.height);
9597 }
9598 // Tx sent by another wallet instance
9599 else
9600 {
9602 ctd.m_amount_in = amount_sent;
9603 ctd.m_amount_out = amount_sent;
9604 ctd.m_change = 0;
9605 ctd.m_payment_id = payment_id;
9606 ctd.m_block_height = t.height;
9607 ctd.m_timestamp = t.timestamp;
9608 m_confirmed_txs.emplace(tx_hash,ctd);
9609 }
9610 if (0 != m_callback)
9611 {
9612 m_callback->on_lw_etn_spent(t.height, tx_hash, amount_sent);
9613 }
9614 }
9615 // If not new - check the amount and update if necessary.
9616 // when sending a tx to same wallet the receiving amount has to be credited
9617 else
9618 {
9619 if(confirmed_tx->second.m_amount_in != amount_sent || confirmed_tx->second.m_amount_out != amount_sent)
9620 {
9621 MDEBUG("Adjusting amount sent/received for tx: <" + t.hash + ">. Is tx sent to own wallet? " << print_etn(amount_sent) << " != " << print_etn(confirmed_tx->second.m_amount_in));
9622 confirmed_tx->second.m_amount_in = amount_sent;
9623 confirmed_tx->second.m_amount_out = amount_sent;
9624 confirmed_tx->second.m_change = 0;
9625 }
9626 }
9627 }
9628 }
9629 }
9630 // TODO: purge old unconfirmed_txs
9631 remove_obsolete_pool_txs(pool_txs);
9632
9633 // Calculate wallet balance
9634 m_light_wallet_balance = ires.total_received-wallet_total_sent;
9635 // MyMonero doesn't send unlocked balance
9636 if(ires.total_received_unlocked > 0)
9637 m_light_wallet_unlocked_balance = ires.total_received_unlocked-wallet_total_sent;
9638 else
9639 m_light_wallet_unlocked_balance = m_light_wallet_balance;
9640}
void remove_obsolete_pool_txs(const std::vector< crypto::hash > &tx_hashes)
Definition wallet2.cpp:3136
bool light_wallet_key_image_is_ours(const crypto::key_image &key_image, const crypto::public_key &tx_public_key, uint64_t out_index)
Definition wallet2.cpp:9667
bool hex_to_pod(const std::string &hex_str, t_pod_type &s)
bool validate_hex(uint64_t length, const std::string &str)
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ light_wallet_get_outs()

void tools::wallet2::light_wallet_get_outs ( std::vector< std::vector< get_outs_entry > > & outs,
const std::vector< size_t > & selected_transfers,
size_t fake_outputs_count )

Definition at line 8268 of file wallet2.cpp.

8268 {
8269
8270 MDEBUG("LIGHTWALLET - Getting random outs");
8271
8274
8275 size_t light_wallet_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
8276
8277 // Amounts to ask for
8278 // MyMonero api handle amounts and fees as strings
8279 for(size_t idx: selected_transfers) {
8280 const uint64_t ask_amount = m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount();
8281 std::ostringstream amount_ss;
8282 amount_ss << ask_amount;
8283 oreq.amounts.push_back(amount_ss.str());
8284 }
8285
8286 oreq.count = light_wallet_requested_outputs_count;
8287 m_daemon_rpc_mutex.lock();
8288 bool r = invoke_http_json("/get_random_outs", oreq, ores, rpc_timeout, "POST");
8289 m_daemon_rpc_mutex.unlock();
8290 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
8291 THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
8292
8293 // Check if we got enough outputs for each amount
8294 for(auto& out: ores.amount_outs) {
8295 const uint64_t out_amount = boost::lexical_cast<uint64_t>(out.amount);
8296 THROW_WALLET_EXCEPTION_IF(out.outputs.size() < light_wallet_requested_outputs_count , error::wallet_internal_error, "Not enough outputs for amount: " + boost::lexical_cast<std::string>(out.amount));
8297 MDEBUG(out.outputs.size() << " outputs for amount "+ boost::lexical_cast<std::string>(out.amount) + " received from light wallet node");
8298 }
8299
8300 MDEBUG("selected transfers size: " << selected_transfers.size());
8301
8302 for(size_t idx: selected_transfers)
8303 {
8304 // Create new index
8305 outs.push_back(std::vector<get_outs_entry>());
8306 outs.back().reserve(fake_outputs_count + 1);
8307
8308 // add real output first
8309 const transfer_details &td = m_transfers[idx];
8310 const uint64_t amount = td.is_rct() ? 0 : td.amount();
8311 outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), rct::commit(td.amount(), td.m_mask)));
8312 MDEBUG("added real output " << string_tools::pod_to_hex(td.get_public_key()));
8313
8314 // Even if the lightwallet server returns random outputs, we pick them randomly.
8315 std::vector<size_t> order;
8316 order.resize(light_wallet_requested_outputs_count);
8317 for (size_t n = 0; n < order.size(); ++n)
8318 order[n] = n;
8319 std::shuffle(order.begin(), order.end(), std::default_random_engine(crypto::rand<unsigned>()));
8320
8321
8322 LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs with amounts " << print_etn(td.is_rct() ? 0 : td.amount()));
8323 MDEBUG("OUTS SIZE: " << outs.back().size());
8324 for (size_t o = 0; o < light_wallet_requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
8325 {
8326 // Random pick
8327 size_t i = order[o];
8328
8329 // Find which random output key to use
8330 bool found_amount = false;
8331 size_t amount_key;
8332 for(amount_key = 0; amount_key < ores.amount_outs.size(); ++amount_key)
8333 {
8334 if(boost::lexical_cast<uint64_t>(ores.amount_outs[amount_key].amount) == amount) {
8335 found_amount = true;
8336 break;
8337 }
8338 }
8339 THROW_WALLET_EXCEPTION_IF(!found_amount , error::wallet_internal_error, "Outputs for amount " + boost::lexical_cast<std::string>(ores.amount_outs[amount_key].amount) + " not found" );
8340
8341 LOG_PRINT_L2("Index " << i << "/" << light_wallet_requested_outputs_count << ": idx " << ores.amount_outs[amount_key].outputs[i].global_index << " (real " << td.m_global_output_index << "), unlocked " << "(always in light)" << ", key " << ores.amount_outs[0].outputs[i].public_key);
8342
8343 // Convert light wallet string data to proper data structures
8344 crypto::public_key tx_public_key;
8345 rct::key mask = AUTO_VAL_INIT(mask); // decrypted mask - not used here
8346 rct::key rct_commit = AUTO_VAL_INIT(rct_commit);
8347 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, ores.amount_outs[amount_key].outputs[i].public_key), error::wallet_internal_error, "Invalid public_key");
8348 string_tools::hex_to_pod(ores.amount_outs[amount_key].outputs[i].public_key, tx_public_key);
8349 const uint64_t global_index = ores.amount_outs[amount_key].outputs[i].global_index;
8350 if(!light_wallet_parse_rct_str(ores.amount_outs[amount_key].outputs[i].rct, tx_public_key, 0, mask, rct_commit, false))
8351 rct_commit = rct::zeroCommit(td.amount());
8352
8353 if (tx_add_fake_output(outs, global_index, tx_public_key, rct_commit, td.m_global_output_index, true)) {
8354 MDEBUG("added fake output " << ores.amount_outs[amount_key].outputs[i].public_key);
8355 MDEBUG("index " << global_index);
8356 }
8357 }
8358
8359 THROW_WALLET_EXCEPTION_IF(outs.back().size() < fake_outputs_count + 1 , error::wallet_internal_error, "Not enough fake outputs found" );
8360
8361 // Real output is the first. Shuffle outputs
8362 MTRACE(outs.back().size() << " outputs added. Sorting outputs by index:");
8363 std::sort(outs.back().begin(), outs.back().end(), [](const get_outs_entry &a, const get_outs_entry &b) { return std::get<0>(a) < std::get<0>(b); });
8364
8365 // Print output order
8366 for(auto added_out: outs.back())
8367 MTRACE(std::get<0>(added_out));
8368
8369 }
8370}
std::tuple< uint64_t, crypto::public_key, rct::key > get_outs_entry
Definition wallet2.h:562
bool light_wallet_parse_rct_str(const std::string &rct_string, const crypto::public_key &tx_pub_key, uint64_t internal_output_index, rct::key &decrypted_mask, rct::key &rct_commit, bool decrypt) const
Definition wallet2.cpp:9642
key zeroCommit(etn_amount amount)
Definition rctOps.cpp:322
key commit(etn_amount amount, const key &mask)
Definition rctOps.cpp:336
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
Here is the call graph for this function:
Here is the caller graph for this function:

◆ light_wallet_get_unspent_outs()

void tools::wallet2::light_wallet_get_unspent_outs ( )

Definition at line 9284 of file wallet2.cpp.

9285{
9286 MDEBUG("Getting unspent outs");
9287
9290
9291 oreq.amount = "0";
9292 oreq.address = get_account().get_public_address_str(m_nettype);
9293 oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9294 // openMonero specific
9295 oreq.dust_threshold = boost::lexical_cast<std::string>(::config::DEFAULT_DUST_THRESHOLD);
9296 // below are required by openMonero api - but are not used.
9297 oreq.mixin = 0;
9298 oreq.use_dust = true;
9299
9300
9301 m_daemon_rpc_mutex.lock();
9302 bool r = invoke_http_json("/get_unspent_outs", oreq, ores, rpc_timeout, "POST");
9303 m_daemon_rpc_mutex.unlock();
9304 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_unspent_outs");
9305 THROW_WALLET_EXCEPTION_IF(ores.status == "error", error::wallet_internal_error, ores.reason);
9306
9307 m_light_wallet_per_kb_fee = ores.per_kb_fee;
9308
9309 std::unordered_map<crypto::hash,bool> transfers_txs;
9310 for(const auto &t: m_transfers)
9311 transfers_txs.emplace(t.m_txid,t.m_spent);
9312
9313 MDEBUG("FOUND " << ores.outputs.size() <<" outputs");
9314
9315 // return if no outputs found
9316 if(ores.outputs.empty())
9317 return;
9318
9319 // Clear old outputs
9320 m_transfers.clear();
9321
9322 for (const auto &o: ores.outputs) {
9323 bool spent = false;
9324 bool add_transfer = true;
9325 crypto::key_image unspent_key_image;
9326 crypto::public_key tx_public_key = AUTO_VAL_INIT(tx_public_key);
9327 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.tx_pub_key), error::wallet_internal_error, "Invalid tx_pub_key field");
9328 string_tools::hex_to_pod(o.tx_pub_key, tx_public_key);
9329
9330 for (const std::string &ski: o.spend_key_images) {
9331 spent = false;
9332
9333 // Check if key image is ours
9334 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, ski), error::wallet_internal_error, "Invalid key image");
9335 string_tools::hex_to_pod(ski, unspent_key_image);
9336 if(light_wallet_key_image_is_ours(unspent_key_image, tx_public_key, o.index)){
9337 MTRACE("Output " << o.public_key << " is spent. Key image: " << ski);
9338 spent = true;
9339 break;
9340 } {
9341 MTRACE("Unspent output found. " << o.public_key);
9342 }
9343 }
9344
9345 // Check if tx already exists in m_transfers.
9346 crypto::hash txid;
9347 crypto::public_key tx_pub_key;
9349 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.tx_hash), error::wallet_internal_error, "Invalid tx_hash field");
9350 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.public_key), error::wallet_internal_error, "Invalid public_key field");
9351 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.tx_pub_key), error::wallet_internal_error, "Invalid tx_pub_key field");
9352 string_tools::hex_to_pod(o.tx_hash, txid);
9353 string_tools::hex_to_pod(o.public_key, public_key);
9354 string_tools::hex_to_pod(o.tx_pub_key, tx_pub_key);
9355
9356 for(auto &t: m_transfers){
9357 if(t.get_public_key() == public_key) {
9358 t.m_spent = spent;
9359 add_transfer = false;
9360 break;
9361 }
9362 }
9363
9364 if(!add_transfer)
9365 continue;
9366
9367 m_transfers.push_back(boost::value_initialized<transfer_details>());
9368 transfer_details& td = m_transfers.back();
9369
9370 td.m_block_height = o.height;
9371 td.m_global_output_index = o.global_index;
9372 td.m_txid = txid;
9373
9374 // Add to extra
9375 add_tx_pub_key_to_extra(td.m_tx, tx_pub_key);
9376
9377 td.m_key_image = unspent_key_image;
9378 td.m_key_image_known = !m_watch_only && !m_multisig;
9379 td.m_key_image_request = false;
9380 td.m_key_image_partial = m_multisig;
9381 td.m_amount = o.amount;
9382 td.m_pk_index = 0;
9383 td.m_internal_output_index = o.index;
9384 td.m_spent = spent;
9385 td.m_frozen = false;
9386
9387 tx_out txout;
9388 txout.target = txout_to_key(public_key);
9389 txout.amount = td.m_amount;
9390
9391 td.m_tx.vout.resize(td.m_internal_output_index + 1);
9392 td.m_tx.vout[td.m_internal_output_index] = txout;
9393
9394 // Add unlock time and coinbase bool got from get_address_txs api call
9395 std::unordered_map<crypto::hash,address_tx>::const_iterator found = m_light_wallet_address_txs.find(txid);
9396 THROW_WALLET_EXCEPTION_IF(found == m_light_wallet_address_txs.end(), error::wallet_internal_error, "Lightwallet: tx not found in m_light_wallet_address_txs");
9397 bool miner_tx = found->second.m_coinbase;
9398 td.m_tx.unlock_time = found->second.m_unlock_time;
9399
9400 if (!o.rct.empty())
9401 {
9402 // Coinbase tx's
9403 if(miner_tx)
9404 {
9405 td.m_mask = rct::identity();
9406 }
9407 else
9408 {
9409 // rct txs
9410 // decrypt rct mask, calculate commit hash and compare against blockchain commit hash
9411 rct::key rct_commit;
9412 light_wallet_parse_rct_str(o.rct, tx_pub_key, td.m_internal_output_index, td.m_mask, rct_commit, true);
9413 bool valid_commit = (rct_commit == rct::commit(td.amount(), td.m_mask));
9414 if(!valid_commit)
9415 {
9416 MDEBUG("output index: " << o.global_index);
9417 MDEBUG("mask: " + string_tools::pod_to_hex(td.m_mask));
9418 MDEBUG("calculated commit: " + string_tools::pod_to_hex(rct::commit(td.amount(), td.m_mask)));
9419 MDEBUG("expected commit: " + string_tools::pod_to_hex(rct_commit));
9420 MDEBUG("amount: " << td.amount());
9421 }
9422 THROW_WALLET_EXCEPTION_IF(!valid_commit, error::wallet_internal_error, "Lightwallet: rct commit hash mismatch!");
9423 }
9424 td.m_rct = true;
9425 }
9426 else
9427 {
9428 td.m_mask = rct::identity();
9429 td.m_rct = false;
9430 }
9431 if(!spent)
9432 set_unspent(m_transfers.size()-1);
9433 m_key_images[td.m_key_image] = m_transfers.size()-1;
9434 m_pub_keys[td.get_public_key()] = m_transfers.size()-1;
9435 }
9436}
bool add_tx_pub_key_to_extra(transaction &tx, const crypto::public_key &tx_pub_key)
txout_target_v target
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ light_wallet_import_wallet_request()

bool tools::wallet2::light_wallet_import_wallet_request ( tools::COMMAND_RPC_IMPORT_WALLET_REQUEST::response & response)

Definition at line 9269 of file wallet2.cpp.

9270{
9271 MDEBUG("Light wallet import wallet request");
9273 oreq.address = get_account().get_public_address_str(m_nettype);
9274 oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9275 m_daemon_rpc_mutex.lock();
9276 bool r = invoke_http_json("/import_wallet_request", oreq, response, rpc_timeout, "POST");
9277 m_daemon_rpc_mutex.unlock();
9278 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "import_wallet_request");
9279
9280
9281 return true;
9282}
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ light_wallet_key_image_is_ours()

bool tools::wallet2::light_wallet_key_image_is_ours ( const crypto::key_image & key_image,
const crypto::public_key & tx_public_key,
uint64_t out_index )

Definition at line 9667 of file wallet2.cpp.

9668{
9669 // Lookup key image from cache
9670 std::map<uint64_t, crypto::key_image> index_keyimage_map;
9671 std::unordered_map<crypto::public_key, std::map<uint64_t, crypto::key_image> >::const_iterator found_pub_key = m_key_image_cache.find(tx_public_key);
9672 if(found_pub_key != m_key_image_cache.end()) {
9673 // pub key found. key image for index cached?
9674 index_keyimage_map = found_pub_key->second;
9675 std::map<uint64_t,crypto::key_image>::const_iterator index_found = index_keyimage_map.find(out_index);
9676 if(index_found != index_keyimage_map.end())
9677 return key_image == index_found->second;
9678 }
9679
9680 // Not in cache - calculate key image
9681 crypto::key_image calculated_key_image;
9682 cryptonote::keypair in_ephemeral;
9683
9684 // Subaddresses aren't supported in mymonero/openmonero yet. Roll out the original scheme:
9685 // compute D = a*R
9686 // compute P = Hs(D || i)*G + B
9687 // compute x = Hs(D || i) + b (and check if P==x*G)
9688 // compute I = x*Hp(P)
9689 const account_keys& ack = get_account().get_keys();
9690 crypto::key_derivation derivation;
9691 bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, derivation);
9692 CHECK_AND_ASSERT_MES(r, false, "failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
9693
9694 r = crypto::derive_public_key(derivation, out_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub);
9695 CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key (" << derivation << ", " << out_index << ", " << ack.m_account_address.m_spend_public_key << ")");
9696
9697 crypto::derive_secret_key(derivation, out_index, ack.m_spend_secret_key, in_ephemeral.sec);
9698 crypto::public_key out_pkey_test;
9699 r = crypto::secret_key_to_public_key(in_ephemeral.sec, out_pkey_test);
9700 CHECK_AND_ASSERT_MES(r, false, "failed to secret_key_to_public_key(" << in_ephemeral.sec << ")");
9701 CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_pkey_test, false, "derived secret key doesn't match derived public key");
9702
9703 crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, calculated_key_image);
9704
9705 index_keyimage_map.emplace(out_index, calculated_key_image);
9706 m_key_image_cache.emplace(tx_public_key, index_keyimage_map);
9707 return key_image == calculated_key_image;
9708}
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
void derive_secret_key(const key_derivation &derivation, std::size_t output_index, const secret_key &base, secret_key &derived_key)
Definition crypto.h:282
void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image)
Definition crypto.h:324
Here is the call graph for this function:
Here is the caller graph for this function:

◆ light_wallet_login()

bool tools::wallet2::light_wallet_login ( bool & new_address)

Definition at line 9240 of file wallet2.cpp.

9241{
9242 MDEBUG("Light wallet login request");
9243 m_light_wallet_connected = false;
9246 request.address = get_account().get_public_address_str(m_nettype);
9247 request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9248 // Always create account if it doesn't exist.
9249 request.create_account = true;
9250 m_daemon_rpc_mutex.lock();
9251 bool connected = invoke_http_json("/login", request, response, rpc_timeout, "POST");
9252 m_daemon_rpc_mutex.unlock();
9253 // MyMonero doesn't send any status message. OpenMonero does.
9254 m_light_wallet_connected = connected && (response.status.empty() || response.status == "success");
9255 new_address = response.new_address;
9256 MDEBUG("Status: " << response.status);
9257 MDEBUG("Reason: " << response.reason);
9258 MDEBUG("New wallet: " << response.new_address);
9259 if(m_light_wallet_connected)
9260 {
9261 // Clear old data on successful login.
9262 // m_transfers.clear();
9263 // m_payments.clear();
9264 // m_unconfirmed_payments.clear();
9265 }
9266 return m_light_wallet_connected;
9267}
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
Here is the call graph for this function:
Here is the caller graph for this function:

◆ light_wallet_parse_rct_str()

bool tools::wallet2::light_wallet_parse_rct_str ( const std::string & rct_string,
const crypto::public_key & tx_pub_key,
uint64_t internal_output_index,
rct::key & decrypted_mask,
rct::key & rct_commit,
bool decrypt ) const

Definition at line 9642 of file wallet2.cpp.

9643{
9644 // rct string is empty if output is non RCT
9645 if (rct_string.empty())
9646 return false;
9647 // rct_string is a string with length 64+64+64 (<rct commit> + <encrypted mask> + <rct amount>)
9648 rct::key encrypted_mask;
9649 std::string rct_commit_str = rct_string.substr(0,64);
9650 std::string encrypted_mask_str = rct_string.substr(64,64);
9651 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, rct_commit_str), error::wallet_internal_error, "Invalid rct commit hash: " + rct_commit_str);
9652 THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, encrypted_mask_str), error::wallet_internal_error, "Invalid rct mask: " + encrypted_mask_str);
9653 string_tools::hex_to_pod(rct_commit_str, rct_commit);
9654 string_tools::hex_to_pod(encrypted_mask_str, encrypted_mask);
9655 if (decrypt) {
9656 // Decrypt the mask
9657 crypto::key_derivation derivation;
9658 bool r = generate_key_derivation(tx_pub_key, get_account().get_keys().m_view_secret_key, derivation);
9659 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
9660 crypto::secret_key scalar;
9661 crypto::derivation_to_scalar(derivation, internal_output_index, scalar);
9662 sc_sub(decrypted_mask.bytes,encrypted_mask.bytes,rct::hash_to_scalar(rct::sk2rct(scalar)).bytes);
9663 }
9664 return true;
9665}
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *)
void hash_to_scalar(key &hash, const void *data, const std::size_t l)
Definition rctOps.cpp:536
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load()

void tools::wallet2::load ( const std::string & wallet,
const epee::wipeable_string & password )

Definition at line 5833 of file wallet2.cpp.

5834{
5835 clear();
5836 prepare_file_names(wallet_);
5837
5838 boost::system::error_code e;
5839 bool exists = boost::filesystem::exists(m_keys_file, e);
5840 THROW_WALLET_EXCEPTION_IF(e || !exists, error::file_not_found, m_keys_file);
5842 THROW_WALLET_EXCEPTION_IF(!is_keys_file_locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program");
5843
5844 // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
5846 if (!load_keys(m_keys_file, password))
5847 {
5849 }
5850 LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype));
5852
5853 wallet_keys_unlocker unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, password);
5854
5855 //keys loaded ok!
5856 //try to load wallet file. but even if we failed, it is not big problem
5857 if(!boost::filesystem::exists(m_wallet_file, e) || e)
5858 {
5859 LOG_PRINT_L0("file not found: " << m_wallet_file << ", starting with empty blockchain");
5860 m_account_public_address = m_account.get_keys().m_account_address;
5861 }
5862 else
5863 {
5864 wallet2::cache_file_data cache_file_data;
5865 std::string buf;
5866 bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf, std::numeric_limits<size_t>::max());
5868
5869 // try to read it as an encrypted cache
5870 try
5871 {
5872 LOG_PRINT_L1("Trying to decrypt cache data");
5873
5875 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + '\"');
5876 std::string cache_data;
5877 cache_data.resize(cache_file_data.cache_data.size());
5878 crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cache_data[0]);
5879
5880 try {
5881 std::stringstream iss;
5882 iss << cache_data;
5883 boost::archive::portable_binary_iarchive ar(iss);
5884 ar >> *this;
5885 }
5886 catch(...)
5887 {
5888 // try with previous scheme: direct from keys
5889 crypto::chacha_key key;
5890 generate_chacha_key_from_secret_keys(key);
5891 crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]);
5892 try {
5893 std::stringstream iss;
5894 iss << cache_data;
5895 boost::archive::portable_binary_iarchive ar(iss);
5896 ar >> *this;
5897 }
5898 catch (...)
5899 {
5900 crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]);
5901 try
5902 {
5903 std::stringstream iss;
5904 iss << cache_data;
5905 boost::archive::portable_binary_iarchive ar(iss);
5906 ar >> *this;
5907 }
5908 catch (...)
5909 {
5910 LOG_PRINT_L0("Failed to open portable binary, trying unportable");
5911 boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_options::overwrite_existing);
5912 std::stringstream iss;
5913 iss.str("");
5914 iss << cache_data;
5915 boost::archive::binary_iarchive ar(iss);
5916 ar >> *this;
5917 }
5918 }
5919 }
5920 }
5921 catch (...)
5922 {
5923 LOG_PRINT_L1("Failed to load encrypted cache, trying unencrypted");
5924 try {
5925 std::stringstream iss;
5926 iss << buf;
5927 boost::archive::portable_binary_iarchive ar(iss);
5928 ar >> *this;
5929 }
5930 catch (...)
5931 {
5932 LOG_PRINT_L0("Failed to open portable binary, trying unportable");
5933 boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_options::overwrite_existing);
5934 std::stringstream iss;
5935 iss.str("");
5936 iss << buf;
5937 boost::archive::binary_iarchive ar(iss);
5938 ar >> *this;
5939 }
5940 }
5942 m_account_public_address.m_spend_public_key != m_account.get_keys().m_account_address.m_spend_public_key ||
5943 m_account_public_address.m_view_public_key != m_account.get_keys().m_account_address.m_view_public_key,
5944 error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file);
5945 }
5946
5947 cryptonote::block genesis;
5948 generate_genesis(genesis);
5949 crypto::hash genesis_hash = get_block_hash(genesis);
5950
5951 if (m_blockchain.empty())
5952 {
5953 m_blockchain.push_back(genesis_hash);
5954 m_last_block_reward = cryptonote::get_outs_etn_amount(genesis.miner_tx);
5955 }
5956 else
5957 {
5958 check_genesis(genesis_hash);
5959 }
5960
5961 trim_hashchain();
5962
5963 if (get_num_subaddress_accounts() == 0)
5964 add_subaddress_account(tr("Primary account"));
5965
5966 try
5967 {
5968 find_and_save_rings(false);
5969 }
5970 catch (const std::exception &e)
5971 {
5972 MERROR("Failed to save rings, will try again next time");
5973 }
5974
5975 try
5976 {
5977 m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file);
5978 }
5979 catch (const std::exception &e)
5980 {
5981 MERROR("Failed to initialize MMS, it will be unusable");
5982 }
5983}
bool is_keys_file_locked() const
Definition wallet2.cpp:8236
bool lock_keys_file()
Definition wallet2.cpp:8214
mms::multisig_wallet_state get_multisig_wallet_state() const
friend class wallet_keys_unlocker
Definition wallet2.h:213
bool find_and_save_rings(bool force=true)
Definition wallet2.cpp:8109
bool parse_binary(const std::string &blob, T &v)
file_error_base< file_not_found_message_index > file_not_found
file_error_base< file_read_error_message_index > file_read_error
const char * buf
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_multisig_tx()

bool tools::wallet2::load_multisig_tx ( cryptonote::blobdata blob,
multisig_tx_set & exported_txs,
std::function< bool(const multisig_tx_set &)> accept_func = NULL )

Definition at line 7549 of file wallet2.cpp.

7550{
7551 if(!parse_multisig_tx_from_str(s, exported_txs))
7552 {
7553 LOG_PRINT_L0("Failed to parse multisig transaction from string");
7554 return false;
7555 }
7556
7557 LOG_PRINT_L1("Loaded multisig tx unsigned data from binary: " << exported_txs.m_ptx.size() << " transactions");
7558 for (auto &ptx: exported_txs.m_ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(ptx.tx));
7559
7560 if (accept_func && !accept_func(exported_txs))
7561 {
7562 LOG_PRINT_L1("Transactions rejected by callback");
7563 return false;
7564 }
7565
7566 const bool is_signed = exported_txs.m_signers.size() >= m_multisig_threshold;
7567 if (is_signed)
7568 {
7569 for (const auto &ptx: exported_txs.m_ptx)
7570 {
7571 const crypto::hash txid = get_transaction_hash(ptx.tx);
7572 if (store_tx_info())
7573 {
7574 m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
7575 m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
7576 }
7577 }
7578 }
7579
7580 return true;
7581}
bool parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const
Definition wallet2.cpp:7505
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_multisig_tx_from_file()

bool tools::wallet2::load_multisig_tx_from_file ( const std::string & filename,
multisig_tx_set & exported_txs,
std::function< bool(const multisig_tx_set &)> accept_func = NULL )

Definition at line 7583 of file wallet2.cpp.

7584{
7585 std::string s;
7586 boost::system::error_code errcode;
7587
7588 if (!boost::filesystem::exists(filename, errcode))
7589 {
7590 LOG_PRINT_L0("File " << filename << " does not exist: " << errcode);
7591 return false;
7592 }
7593 if (!epee::file_io_utils::load_file_to_string(filename.c_str(), s))
7594 {
7595 LOG_PRINT_L0("Failed to load from " << filename);
7596 return false;
7597 }
7598
7599 if (!load_multisig_tx(s, exported_txs, accept_func))
7600 {
7601 LOG_PRINT_L0("Failed to parse multisig tx data from " << filename);
7602 return false;
7603 }
7604 return true;
7605}
bool load_multisig_tx(cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function< bool(const multisig_tx_set &)> accept_func=NULL)
Definition wallet2.cpp:7549
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_tx()

bool tools::wallet2::load_tx ( const std::string & signed_filename,
std::vector< tools::wallet2::pending_tx > & ptx,
std::function< bool(const signed_tx_set &)> accept_func = NULL )

Definition at line 7321 of file wallet2.cpp.

7322{
7323 std::string s;
7324 boost::system::error_code errcode;
7325 signed_tx_set signed_txs;
7326
7327 if (!boost::filesystem::exists(signed_filename, errcode))
7328 {
7329 LOG_PRINT_L0("File " << signed_filename << " does not exist: " << errcode);
7330 return false;
7331 }
7332
7333 if (!epee::file_io_utils::load_file_to_string(signed_filename.c_str(), s))
7334 {
7335 LOG_PRINT_L0("Failed to load from " << signed_filename);
7336 return false;
7337 }
7338
7339 return parse_tx_from_str(s, ptx, accept_func);
7340}
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector< tools::wallet2::pending_tx > &ptx, std::function< bool(const signed_tx_set &)> accept_func)
Definition wallet2.cpp:7342
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_unsigned_tx()

bool tools::wallet2::load_unsigned_tx ( const std::string & unsigned_filename,
unsigned_tx_set & exported_txs ) const

Definition at line 7014 of file wallet2.cpp.

7015{
7016 std::string s;
7017 boost::system::error_code errcode;
7018
7019 if (!boost::filesystem::exists(unsigned_filename, errcode))
7020 {
7021 LOG_PRINT_L0("File " << unsigned_filename << " does not exist: " << errcode);
7022 return false;
7023 }
7024 if (!epee::file_io_utils::load_file_to_string(unsigned_filename.c_str(), s))
7025 {
7026 LOG_PRINT_L0("Failed to load from " << unsigned_filename);
7027 return false;
7028 }
7029
7030 return parse_unsigned_tx_from_str(s, exported_txs);
7031}
bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const
Definition wallet2.cpp:7033
Here is the call graph for this function:
Here is the caller graph for this function:

◆ lock_keys_file()

bool tools::wallet2::lock_keys_file ( )

Definition at line 8214 of file wallet2.cpp.

8215{
8216 if (m_keys_file_locker)
8217 {
8218 MDEBUG(m_keys_file << " is already locked.");
8219 return false;
8220 }
8221 m_keys_file_locker.reset(new tools::file_locker(m_keys_file));
8222 return true;
8223}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_dummy()

std::unique_ptr< wallet2 > tools::wallet2::make_dummy ( const boost::program_options::variables_map & vm,
bool unattended,
const std::function< boost::optional< password_container >(const char *, bool)> & password_prompter )
static

Just parses variables.

Definition at line 1261 of file wallet2.cpp.

1262{
1263 const options opts{};
1264 return make_basic(vm, unattended, opts, password_prompter);
1265}

◆ make_from_file()

std::pair< std::unique_ptr< wallet2 >, password_container > tools::wallet2::make_from_file ( const boost::program_options::variables_map & vm,
bool unattended,
const std::string & wallet_file,
const std::function< boost::optional< password_container >(const char *, bool)> & password_prompter )
static

Uses stdin and stdout. Returns a wallet2 and password for wallet_file if no errors.

Definition at line 1233 of file wallet2.cpp.

1235{
1236 const options opts{};
1237 auto pwd = get_password(vm, opts, password_prompter, false);
1238 if (!pwd)
1239 {
1240 return {nullptr, password_container{}};
1241 }
1242 auto wallet = make_basic(vm, unattended, opts, password_prompter);
1243 if (wallet && !wallet_file.empty())
1244 {
1245 wallet->load(wallet_file, pwd->password());
1246 }
1247 return {std::move(wallet), std::move(*pwd)};
1248}
Here is the caller graph for this function:

◆ make_from_json()

std::pair< std::unique_ptr< wallet2 >, tools::password_container > tools::wallet2::make_from_json ( const boost::program_options::variables_map & vm,
bool unattended,
const std::string & json_file,
const std::function< boost::optional< password_container >(const char *, bool)> & password_prompter )
static

Uses stdin and stdout. Returns a wallet2 if no errors.

Definition at line 1227 of file wallet2.cpp.

1228{
1229 const options opts{};
1230 return generate_from_json(json_file, vm, unattended, opts, password_prompter);
1231}
Here is the caller graph for this function:

◆ make_multisig() [1/2]

std::string tools::wallet2::make_multisig ( const epee::wipeable_string & password,
const std::vector< crypto::secret_key > & view_keys,
const std::vector< crypto::public_key > & spend_keys,
uint32_t threshold )

Creates a multisig wallet.

Returns
empty if done, non empty if we need to send another string to other participants

Definition at line 5145 of file wallet2.cpp.

5149{
5150 CHECK_AND_ASSERT_THROW_MES(!view_keys.empty(), "empty view keys");
5151 CHECK_AND_ASSERT_THROW_MES(view_keys.size() == spend_keys.size(), "Mismatched view/spend key sizes");
5152 CHECK_AND_ASSERT_THROW_MES(threshold > 1 && threshold <= spend_keys.size() + 1, "Invalid threshold");
5153
5154 std::string extra_multisig_info;
5155 std::vector<crypto::secret_key> multisig_keys;
5156 rct::key spend_pkey = rct::identity();
5157 rct::key spend_skey;
5158 std::vector<crypto::public_key> multisig_signers;
5159
5160 // decrypt keys
5162 if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
5163 {
5164 crypto::chacha_key chacha_key;
5165 crypto::generate_chacha_key(password.data(), password.size(), chacha_key, m_kdf_rounds);
5166 m_account.encrypt_viewkey(chacha_key);
5167 m_account.decrypt_keys(chacha_key);
5168 keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this, chacha_key]() { m_account.encrypt_keys(chacha_key); m_account.decrypt_viewkey(chacha_key); });
5169 }
5170
5171 // In common multisig scheme there are 4 types of key exchange rounds:
5172 // 1. First round is exchange of view secret keys and public spend keys.
5173 // 2. Middle round is exchange of derivations: Ki = b * Mj, where b - spend secret key,
5174 // M - public multisig key (in first round it equals to public spend key), K - new public multisig key.
5175 // 3. Secret spend establishment round sets your secret multisig keys as follows: kl = H(Ml), where M - is *your* public multisig key,
5176 // k - secret multisig key used to sign transactions. k and M are sets of keys, of course.
5177 // And secret spend key as the sum of all participant's secret multisig keys
5178 // 4. Last round establishes multisig wallet's public spend key. Participants exchange their public multisig keys
5179 // and calculate common spend public key as sum of all unique participants' public multisig keys.
5180 // Note that N/N scheme has only first round. N-1/N has 2 rounds: first and last. Common M/N has all 4 rounds.
5181
5182 // IMPORTANT: wallet's public spend key is not equal to secret_spend_key * G!
5183 // Wallet's public spend key is the sum of unique public multisig keys of all participants.
5184 // secret_spend_key * G = public signer key
5185
5186 if (threshold == spend_keys.size() + 1)
5187 {
5188 // In N / N case we only need to do one round and calculate secret multisig keys and new secret spend key
5189 MINFO("Creating spend key...");
5190
5191 // Calculates all multisig keys and spend key
5192 cryptonote::generate_multisig_N_N(get_account().get_keys(), spend_keys, multisig_keys, spend_skey, spend_pkey);
5193
5194 // Our signer key is b * G, where b is secret spend key.
5195 multisig_signers = spend_keys;
5196 multisig_signers.push_back(get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key));
5197 }
5198 else
5199 {
5200 // We just got public spend keys of all participants and deriving multisig keys (set of Mi = b * Bi).
5201 // note that derivations are public keys as DH exchange suppose it to be
5202 auto derivations = cryptonote::generate_multisig_derivations(get_account().get_keys(), spend_keys);
5203
5204 spend_pkey = rct::identity();
5205 multisig_signers = std::vector<crypto::public_key>(spend_keys.size() + 1, crypto::null_pkey);
5206
5207 if (threshold == spend_keys.size())
5208 {
5209 // N - 1 / N case
5210
5211 // We need an extra step, so we package all the composite public keys
5212 // we know about, and make a signed string out of them
5213 MINFO("Creating spend key...");
5214
5215 // Calculating set of our secret multisig keys as follows: mi = H(Mi),
5216 // where mi - secret multisig key, Mi - others' participants public multisig key
5217 multisig_keys = cryptonote::calculate_multisig_keys(derivations);
5218
5219 // calculating current participant's spend secret key as sum of all secret multisig keys for current participant.
5220 // IMPORTANT: participant's secret spend key is not an entire wallet's secret spend!
5221 // Entire wallet's secret spend is sum of all unique secret multisig keys
5222 // among all of participants and is not held by anyone!
5223 spend_skey = rct::sk2rct(cryptonote::calculate_multisig_signer_key(multisig_keys));
5224
5225 // Preparing data for the last round to calculate common public spend key. The data contains public multisig keys.
5226 extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, secret_keys_to_public_keys(multisig_keys), rct::rct2sk(spend_skey));
5227 }
5228 else
5229 {
5230 // M / N case
5231 MINFO("Preparing keys for next exchange round...");
5232
5233 // Preparing data for middle round - packing new public multisig keys to exchage with others.
5234 extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, derivations, m_account.get_keys().m_spend_secret_key);
5235 spend_skey = rct::sk2rct(m_account.get_keys().m_spend_secret_key);
5236
5237 // Need to store middle keys to be able to proceed in case of wallet shutdown.
5238 m_multisig_derivations = derivations;
5239 }
5240 }
5241
5242 if (!m_original_keys_available)
5243 {
5244 // Save the original i.e. non-multisig keys so the MMS can continue to use them to encrypt and decrypt messages
5245 // (making a wallet multisig overwrites those keys, see account_base::make_multisig)
5246 m_original_address = m_account.get_keys().m_account_address;
5247 m_original_view_secret_key = m_account.get_keys().m_view_secret_key;
5248 m_original_keys_available = true;
5249 }
5250
5251 clear();
5252 MINFO("Creating view key...");
5253 crypto::secret_key view_skey = cryptonote::generate_multisig_view_secret_key(get_account().get_keys().m_view_secret_key, view_keys);
5254
5255 MINFO("Creating multisig address...");
5256 CHECK_AND_ASSERT_THROW_MES(m_account.make_multisig(view_skey, rct::rct2sk(spend_skey), rct::rct2pk(spend_pkey), multisig_keys),
5257 "Failed to create multisig wallet due to bad keys");
5258 memwipe(&spend_skey, sizeof(rct::key));
5259
5261 m_original_keys_available = true;
5262 m_multisig = true;
5263 m_multisig_threshold = threshold;
5264 m_multisig_signers = multisig_signers;
5265 ++m_multisig_rounds_passed;
5266
5267 // re-encrypt keys
5268 keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
5269
5270 create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
5271
5272 setup_new_blockchain();
5273
5274 if (!m_wallet_file.empty())
5275 store();
5276
5277 return extra_multisig_info;
5278}
void generate_multisig_N_N(const account_keys &keys, const std::vector< crypto::public_key > &spend_keys, std::vector< crypto::secret_key > &multisig_keys, rct::key &spend_skey, rct::key &spend_pkey)
Definition multisig.cpp:58
crypto::secret_key generate_multisig_view_secret_key(const crypto::secret_key &skey, const std::vector< crypto::secret_key > &skeys)
Definition multisig.cpp:124
Here is the call graph for this function:

◆ make_multisig() [2/2]

std::string tools::wallet2::make_multisig ( const epee::wipeable_string & password,
const std::vector< std::string > & info,
uint32_t threshold )

Creates a multisig wallet.

Returns
empty if done, non empty if we need to send another string to other participants

Definition at line 5466 of file wallet2.cpp.

5469{
5470 std::vector<crypto::secret_key> secret_keys(info.size());
5471 std::vector<crypto::public_key> public_keys(info.size());
5472 unpack_multisig_info(info, public_keys, secret_keys);
5473 return make_multisig(password, secret_keys, public_keys, threshold);
5474}
std::string make_multisig(const epee::wipeable_string &password, const std::vector< std::string > &info, uint32_t threshold)
Creates a multisig wallet.
Definition wallet2.cpp:5466
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_multisig_tx_set()

wallet2::multisig_tx_set tools::wallet2::make_multisig_tx_set ( const std::vector< pending_tx > & ptx_vector) const

Definition at line 7477 of file wallet2.cpp.

7478{
7479 multisig_tx_set txs;
7480 txs.m_ptx = ptx_vector;
7481
7482 for (const auto &msk: get_account().get_multisig_keys())
7483 {
7485 for (auto &ptx: txs.m_ptx) for (auto &sig: ptx.multisig_sigs) sig.signing_keys.insert(pkey);
7486 }
7487
7488 txs.m_signers.insert(get_multisig_signer_public_key());
7489 return txs;
7490}
std::vector< pending_tx > m_ptx
Definition wallet2.h:512
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_new()

std::pair< std::unique_ptr< wallet2 >, password_container > tools::wallet2::make_new ( const boost::program_options::variables_map & vm,
bool unattended,
const std::function< boost::optional< password_container >(const char *, bool)> & password_prompter )
static

Uses stdin and stdout. Returns a wallet2 and password for wallet with no file if no errors.

Definition at line 1250 of file wallet2.cpp.

1251{
1252 const options opts{};
1253 auto pwd = get_password(vm, opts, password_prompter, true);
1254 if (!pwd)
1255 {
1256 return {nullptr, password_container{}};
1257 }
1258 return {make_basic(vm, unattended, opts, password_prompter), std::move(*pwd)};
1259}

◆ make_uri()

std::string tools::wallet2::make_uri ( const std::string & address,
const std::string & payment_id,
uint64_t amount,
const std::string & tx_description,
const std::string & recipient_name,
std::string & error ) const

Definition at line 13255 of file wallet2.cpp.

13256{
13257 cryptonote::address_parse_info info;
13259 {
13260 error = std::string("wrong address: ") + address;
13261 return std::string();
13262 }
13263
13264 // we want only one payment id
13265 if (info.has_payment_id && !payment_id.empty())
13266 {
13267 error = "A single payment id is allowed";
13268 return std::string();
13269 }
13270
13271 if (!payment_id.empty())
13272 {
13273 crypto::hash pid32;
13274 crypto::hash8 pid8;
13275 if (!wallet2::parse_long_payment_id(payment_id, pid32) && !parse_short_payment_id(payment_id, pid8))
13276 {
13277 error = "Invalid payment id";
13278 return std::string();
13279 }
13280 }
13281
13282 std::string uri = "electroneum:" + address;
13283 unsigned int n_fields = 0;
13284
13285 if (!payment_id.empty())
13286 {
13287 uri += (n_fields++ ? "&" : "?") + std::string("tx_payment_id=") + payment_id;
13288 }
13289
13290 if (amount > 0)
13291 {
13292 // URI encoded amount is in decimal units, not atomic units
13293 uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + cryptonote::print_etn(amount);
13294 }
13295
13296 if (!recipient_name.empty())
13297 {
13298 uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + epee::net_utils::conver_to_url_format(recipient_name);
13299 }
13300
13301 if (!tx_description.empty())
13302 {
13303 uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::conver_to_url_format(tx_description);
13304 }
13305
13306 return uri;
13307}
static bool parse_long_payment_id(const std::string &payment_id_str, crypto::hash &payment_id)
Definition wallet2.cpp:5712
static bool parse_short_payment_id(const std::string &payment_id_str, crypto::hash8 &payment_id)
Definition wallet2.cpp:5725
POD_CLASS hash8
Definition hash.h:53
bool get_account_address_from_str(address_parse_info &info, network_type nettype, std::string const &str)
error
Tracks LMDB error codes.
Definition error.h:45
Here is the call graph for this function:
Here is the caller graph for this function:

◆ merge_destinations() [1/2]

bool tools::wallet2::merge_destinations ( ) const
inline

Definition at line 1086 of file wallet2.h.

1086{ return m_merge_destinations; }

◆ merge_destinations() [2/2]

void tools::wallet2::merge_destinations ( bool merge)
inline

Definition at line 1085 of file wallet2.h.

1085{ m_merge_destinations = merge; }
Here is the caller graph for this function:

◆ multisig()

bool tools::wallet2::multisig ( bool * ready = NULL,
uint32_t * threshold = NULL,
uint32_t * total = NULL ) const

Definition at line 5634 of file wallet2.cpp.

5635{
5636 if (!m_multisig)
5637 return false;
5638 if (threshold)
5639 *threshold = m_multisig_threshold;
5640 if (total)
5641 *total = m_multisig_signers.size();
5642 if (ready)
5643 *ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity()));
5644 return true;
5645}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ nettype()

cryptonote::network_type tools::wallet2::nettype ( ) const
inline

Definition at line 824 of file wallet2.h.

824{ return m_nettype; }
Here is the caller graph for this function:

◆ parse_long_payment_id()

bool tools::wallet2::parse_long_payment_id ( const std::string & payment_id_str,
crypto::hash & payment_id )
static

Definition at line 5712 of file wallet2.cpp.

5713{
5714 cryptonote::blobdata payment_id_data;
5715 if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data))
5716 return false;
5717
5718 if(sizeof(crypto::hash) != payment_id_data.size())
5719 return false;
5720
5721 payment_id = *reinterpret_cast<const crypto::hash*>(payment_id_data.data());
5722 return true;
5723}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_multisig_tx_from_str()

bool tools::wallet2::parse_multisig_tx_from_str ( std::string multisig_tx_st,
multisig_tx_set & exported_txs ) const

Definition at line 7505 of file wallet2.cpp.

7506{
7507 const size_t magiclen = strlen(MULTISIG_UNSIGNED_TX_PREFIX);
7508 if (strncmp(multisig_tx_st.c_str(), MULTISIG_UNSIGNED_TX_PREFIX, magiclen))
7509 {
7510 LOG_PRINT_L0("Bad magic from multisig tx data");
7511 return false;
7512 }
7513 try
7514 {
7515 multisig_tx_st = decrypt_with_view_secret_key(std::string(multisig_tx_st, magiclen));
7516 }
7517 catch (const std::exception &e)
7518 {
7519 LOG_PRINT_L0("Failed to decrypt multisig tx data: " << e.what());
7520 return false;
7521 }
7522 try
7523 {
7524 std::istringstream iss(multisig_tx_st);
7525 boost::archive::portable_binary_iarchive ar(iss);
7526 ar >> exported_txs;
7527 }
7528 catch (...)
7529 {
7530 LOG_PRINT_L0("Failed to parse multisig tx data");
7531 return false;
7532 }
7533
7534 // sanity checks
7535 for (const auto &ptx: exported_txs.m_ptx)
7536 {
7537 CHECK_AND_ASSERT_MES(ptx.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched selected_transfers/vin sizes");
7538 for (size_t idx: ptx.selected_transfers)
7539 CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range");
7540 CHECK_AND_ASSERT_MES(ptx.construction_data.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched cd selected_transfers/vin sizes");
7541 for (size_t idx: ptx.construction_data.selected_transfers)
7542 CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range");
7543 CHECK_AND_ASSERT_MES(ptx.construction_data.sources.size() == ptx.tx.vin.size(), false, "Mismatched sources/vin sizes");
7544 }
7545
7546 return true;
7547}
#define MULTISIG_UNSIGNED_TX_PREFIX
Definition wallet2.cpp:109
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_payment_id()

bool tools::wallet2::parse_payment_id ( const std::string & payment_id_str,
crypto::hash & payment_id )
static

Definition at line 5738 of file wallet2.cpp.

5739{
5740 if (parse_long_payment_id(payment_id_str, payment_id))
5741 return true;
5742 crypto::hash8 payment_id8;
5743 if (parse_short_payment_id(payment_id_str, payment_id8))
5744 {
5745 memcpy(payment_id.data, payment_id8.data, 8);
5746 memset(payment_id.data + 8, 0, 24);
5747 return true;
5748 }
5749 return false;
5750}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_short_payment_id()

bool tools::wallet2::parse_short_payment_id ( const std::string & payment_id_str,
crypto::hash8 & payment_id )
static

Definition at line 5725 of file wallet2.cpp.

5726{
5727 cryptonote::blobdata payment_id_data;
5728 if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data))
5729 return false;
5730
5731 if(sizeof(crypto::hash8) != payment_id_data.size())
5732 return false;
5733
5734 payment_id = *reinterpret_cast<const crypto::hash8*>(payment_id_data.data());
5735 return true;
5736}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_tx_from_str()

bool tools::wallet2::parse_tx_from_str ( const std::string & signed_tx_st,
std::vector< tools::wallet2::pending_tx > & ptx,
std::function< bool(const signed_tx_set &)> accept_func )

Definition at line 7342 of file wallet2.cpp.

7343{
7344 std::string s = signed_tx_st;
7345 boost::system::error_code errcode;
7346 signed_tx_set signed_txs;
7347
7348 const size_t magiclen = strlen(SIGNED_TX_PREFIX) - 1;
7349 if (strncmp(s.c_str(), SIGNED_TX_PREFIX, magiclen))
7350 {
7351 LOG_PRINT_L0("Bad magic from signed transaction");
7352 return false;
7353 }
7354 s = s.substr(magiclen);
7355 const char version = s[0];
7356 s = s.substr(1);
7357 if (version == '\003')
7358 {
7359 try
7360 {
7361 std::istringstream iss(s);
7362 boost::archive::portable_binary_iarchive ar(iss);
7363 ar >> signed_txs;
7364 }
7365 catch (const std::exception &e)
7366 {
7367 LOG_PRINT_L0("Failed to parse data from signed transaction: " << e.what());
7368 return false;
7369 }
7370 catch(...)
7371 {
7372 LOG_PRINT_L0("Failed to parse data from signed transaction");
7373 return false;
7374 }
7375 }
7376 else if (version == '\004')
7377 {
7378 try
7379 {
7381 try
7382 {
7383 std::istringstream iss(s);
7384 boost::archive::portable_binary_iarchive ar(iss);
7385 ar >> signed_txs;
7386 }
7387 catch (const std::exception &e)
7388 {
7389 LOG_PRINT_L0("Failed to parse decrypted data from signed transaction: " << e.what());
7390 return false;
7391 }
7392 }
7393 catch (const std::exception &e)
7394 {
7395 LOG_PRINT_L0("Failed to decrypt signed transaction: " << e.what());
7396 return false;
7397 }
7398 catch(...)
7399 {
7400 LOG_PRINT_L0("Failed to decrypt signed transaction");
7401 return false;
7402 }
7403 }
7404 else
7405 {
7406 LOG_PRINT_L0("Unsupported version in signed transaction");
7407 return false;
7408 }
7409 LOG_PRINT_L0("Loaded signed tx data from binary: " << signed_txs.ptx.size() << " transactions");
7410 for (auto &c_ptx: signed_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(c_ptx.tx));
7411
7412 if (accept_func && !accept_func(signed_txs))
7413 {
7414 LOG_PRINT_L1("Transactions rejected by callback");
7415 return false;
7416 }
7417
7418 // import key images
7419 bool r = import_key_images(signed_txs.key_images);
7420 if (!r) return false;
7421
7422 // remember key images for this tx, for when we get those txes from the blockchain
7423 for (const auto &e: signed_txs.tx_key_images)
7424 m_cold_key_images.insert(e);
7425
7426 ptx = signed_txs.ptx;
7427
7428 return true;
7429}
#define SIGNED_TX_PREFIX
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_unsigned_tx_from_str()

bool tools::wallet2::parse_unsigned_tx_from_str ( const std::string & unsigned_tx_st,
unsigned_tx_set & exported_txs ) const

Definition at line 7033 of file wallet2.cpp.

7034{
7035 std::string s = unsigned_tx_st;
7036 const size_t magiclen = strlen(UNSIGNED_TX_PREFIX) - 1;
7037 if (strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen))
7038 {
7039 LOG_PRINT_L0("Bad magic from unsigned tx");
7040 return false;
7041 }
7042 s = s.substr(magiclen);
7043 const char version = s[0];
7044 s = s.substr(1);
7045 if (version == '\003')
7046 {
7047 try
7048 {
7049 std::istringstream iss(s);
7050 boost::archive::portable_binary_iarchive ar(iss);
7051 ar >> exported_txs;
7052 }
7053 catch (const std::exception &e)
7054 {
7055 LOG_PRINT_L0("Failed to parse data from unsigned tx: " << e.what());
7056 return false;
7057 }
7058 catch (...)
7059 {
7060 LOG_PRINT_L0("Failed to parse data from unsigned tx");
7061 return false;
7062 }
7063 }
7064 else if (version == '\004')
7065 {
7066 try
7067 {
7069 try
7070 {
7071 std::istringstream iss(s);
7072 boost::archive::portable_binary_iarchive ar(iss);
7073 ar >> exported_txs;
7074 }
7075 catch (const std::exception &e)
7076 {
7077 LOG_PRINT_L0("Failed to parse decrypted data from unsigned tx: " << e.what());
7078 return false;
7079 }
7080 }
7081 catch (const std::exception &e)
7082 {
7083 LOG_PRINT_L0("Failed to decrypt unsigned tx: " << e.what());
7084 return false;
7085 }
7086 catch(...)
7087 {
7088 LOG_PRINT_L0("Failed to parse decrypted data from unsigned tx");
7089 return false;
7090 }
7091 }
7092 else
7093 {
7094 LOG_PRINT_L0("Unsupported version in unsigned tx");
7095 return false;
7096 }
7097 LOG_PRINT_L1("Loaded tx unsigned data from binary: " << exported_txs.txes.size() << " transactions");
7098
7099 return true;
7100}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_uri()

bool tools::wallet2::parse_uri ( const std::string & uri,
std::string & address,
std::string & payment_id,
uint64_t & amount,
std::string & tx_description,
std::string & recipient_name,
std::vector< std::string > & unknown_parameters,
std::string & error )

Definition at line 13309 of file wallet2.cpp.

13310{
13311 if (uri.substr(0, 12) != "electroneum:")
13312 {
13313 error = std::string("URI has wrong scheme (expected \"electroneum:\"): ") + uri;
13314 return false;
13315 }
13316
13317 std::string remainder = uri.substr(12);
13318 const char *ptr = strchr(remainder.c_str(), '?');
13319 address = ptr ? remainder.substr(0, ptr-remainder.c_str()) : remainder;
13320
13321 cryptonote::address_parse_info info;
13323 {
13324 error = std::string("URI has wrong address: ") + address;
13325 return false;
13326 }
13327 if (!strchr(remainder.c_str(), '?'))
13328 return true;
13329
13330 std::vector<std::string> arguments;
13331 std::string body = remainder.substr(address.size() + 1);
13332 if (body.empty())
13333 return true;
13334 boost::split(arguments, body, boost::is_any_of("&"));
13335 std::set<std::string> have_arg;
13336 for (const auto &arg: arguments)
13337 {
13338 std::vector<std::string> kv;
13339 boost::split(kv, arg, boost::is_any_of("="));
13340 if (kv.size() != 2)
13341 {
13342 error = std::string("URI has wrong parameter: ") + arg;
13343 return false;
13344 }
13345 if (have_arg.find(kv[0]) != have_arg.end())
13346 {
13347 error = std::string("URI has more than one instance of " + kv[0]);
13348 return false;
13349 }
13350 have_arg.insert(kv[0]);
13351
13352 if (kv[0] == "tx_amount")
13353 {
13354 amount = 0;
13355 if (!cryptonote::parse_amount(amount, kv[1]))
13356 {
13357 error = std::string("URI has invalid amount: ") + kv[1];
13358 return false;
13359 }
13360 }
13361 else if (kv[0] == "tx_payment_id")
13362 {
13363 if (info.has_payment_id)
13364 {
13365 error = "Separate payment id given with an integrated address";
13366 return false;
13367 }
13371 {
13372 error = "Invalid payment id: " + kv[1];
13373 return false;
13374 }
13375 payment_id = kv[1];
13376 }
13377 else if (kv[0] == "recipient_name")
13378 {
13379 recipient_name = epee::net_utils::convert_from_url_format(kv[1]);
13380 }
13381 else if (kv[0] == "tx_description")
13382 {
13383 tx_description = epee::net_utils::convert_from_url_format(kv[1]);
13384 }
13385 else
13386 {
13387 unknown_parameters.push_back(arg);
13388 }
13389 }
13390 return true;
13391}
bool parse_amount(uint64_t &amount, const std::string &str_amount_)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ path()

std::string tools::wallet2::path ( ) const

Definition at line 6027 of file wallet2.cpp.

6028{
6029 return m_wallet_file;
6030}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pop_best_value()

size_t tools::wallet2::pop_best_value ( std::vector< size_t > & unused_dust_indices,
const std::vector< size_t > & selected_transfers,
bool smallest = false ) const

Definition at line 6740 of file wallet2.cpp.

6741{
6742 return pop_best_value_from(m_transfers, unused_indices, selected_transfers, smallest);
6743}
size_t pop_best_value_from(const transfer_container &transfers, std::vector< size_t > &unused_dust_indices, const std::vector< size_t > &selected_transfers, bool smallest=false) const
Definition wallet2.cpp:6691
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pop_best_value_from()

size_t tools::wallet2::pop_best_value_from ( const transfer_container & transfers,
std::vector< size_t > & unused_dust_indices,
const std::vector< size_t > & selected_transfers,
bool smallest = false ) const

Definition at line 6691 of file wallet2.cpp.

6692{
6693 std::vector<size_t> candidates;
6694 float best_relatedness = 1.0f;
6695 for (size_t n = 0; n < unused_indices.size(); ++n)
6696 {
6697 const transfer_details &candidate = transfers[unused_indices[n]];
6698 float relatedness = 0.0f;
6699 for (std::vector<size_t>::const_iterator i = selected_transfers.begin(); i != selected_transfers.end(); ++i)
6700 {
6701 float r = get_output_relatedness(candidate, transfers[*i]);
6702 if (r > relatedness)
6703 {
6704 relatedness = r;
6705 if (relatedness == 1.0f)
6706 break;
6707 }
6708 }
6709
6710 if (relatedness < best_relatedness)
6711 {
6712 best_relatedness = relatedness;
6713 candidates.clear();
6714 }
6715
6716 if (relatedness == best_relatedness)
6717 candidates.push_back(n);
6718 }
6719
6720 // we have all the least related outputs in candidates, so we can pick either
6721 // the smallest, or a random one, depending on request
6722 size_t idx;
6723 if (smallest)
6724 {
6725 idx = 0;
6726 for (size_t n = 0; n < candidates.size(); ++n)
6727 {
6728 const transfer_details &td = transfers[unused_indices[candidates[n]]];
6729 if (td.amount() < transfers[unused_indices[candidates[idx]]].amount())
6730 idx = n;
6731 }
6732 }
6733 else
6734 {
6735 idx = crypto::rand_idx(candidates.size());
6736 }
6737 return pop_index (unused_indices, candidates[idx]);
6738}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ print_ring_members() [1/2]

bool tools::wallet2::print_ring_members ( ) const
inline

Definition at line 1067 of file wallet2.h.

1067{ return m_print_ring_members; }

◆ print_ring_members() [2/2]

void tools::wallet2::print_ring_members ( bool value)
inline

Definition at line 1068 of file wallet2.h.

1068{ m_print_ring_members = value; }

◆ public_transactions_required()

bool tools::wallet2::public_transactions_required ( ) const
inline

Definition at line 900 of file wallet2.h.

900{ return nettype() == cryptonote::network_type::MAINNET ? get_blockchain_current_height() >= (1175315 - CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS) : get_blockchain_current_height() >= (1086402 - CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);} // prepare v2 tx if the block height is one before the fork block (which contains v2+ tx only)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ query_device()

bool tools::wallet2::query_device ( hw::device::device_type & device_type,
const std::string & keys_file_name,
const epee::wipeable_string & password,
uint64_t kdf_rounds = 1 )
static

determine the key storage for the specified wallet file

Parameters
device_type(OUT) wallet backend as enumerated in hw::device::device_type
keys_file_nameKeys file to verify password for
passwordPassword to verify
Returns
true if password correct, else false

for verification only - determines key storage hardware

Definition at line 4807 of file wallet2.cpp.

4808{
4809 rapidjson::Document json;
4810 wallet2::keys_file_data keys_file_data;
4811 std::string buf;
4812 bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
4814
4815 // Decrypt the contents
4817 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
4818 crypto::chacha_key key;
4819 crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
4820 std::string account_data;
4821 account_data.resize(keys_file_data.account_data.size());
4822 crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4823 if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject())
4824 crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4825
4827 // The contents should be JSON if the wallet follows the new format.
4828 if (json.Parse(account_data.c_str()).HasParseError())
4829 {
4830 // old format before JSON wallet key file format
4831 }
4832 else
4833 {
4834 account_data = std::string(json["key_data"].GetString(), json["key_data"].GetString() +
4835 json["key_data"].GetStringLength());
4836
4837 if (json.HasMember("key_on_device"))
4838 {
4840 device_type = static_cast<hw::device::device_type>(field_key_on_device);
4841 }
4842 }
4843
4844 cryptonote::account_base account_data_check;
4845
4846 r = epee::serialization::load_t_from_binary(account_data_check, account_data);
4847 if (!r) return false;
4848 return true;
4849}
bool key_on_device() const
Definition wallet2.h:830
#define GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, name, type, jtype, mandatory, def)
Definition json_util.h:32
bool load_t_from_binary(t_struct &out, const epee::span< const uint8_t > binary_buff)
rapidjson::Document json
Definition transport.cpp:49
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reconnect_device()

bool tools::wallet2::reconnect_device ( )

Definition at line 1390 of file wallet2.cpp.

1391{
1392 bool r = true;
1393 hw::device &hwdev = lookup_device(m_device_name);
1394 hwdev.set_name(m_device_name);
1395 hwdev.set_network_type(m_nettype);
1396 hwdev.set_derivation_path(m_device_derivation_path);
1397 hwdev.set_callback(get_device_callback());
1398 r = hwdev.init();
1399 if (!r){
1400 MERROR("Could not init device");
1401 return false;
1402 }
1403
1404 r = hwdev.connect();
1405 if (!r){
1406 MERROR("Could not connect to the device");
1407 return false;
1408 }
1409
1410 m_account.set_device(hwdev);
1411 return true;
1412}
virtual bool connect(void)=0
virtual bool init(void)=0
virtual void set_network_type(cryptonote::network_type network_type)
Definition device.hpp:248
virtual void set_callback(i_device_callback *callback)
Definition device.hpp:136
virtual bool set_name(const std::string &name)=0
virtual void set_derivation_path(const std::string &derivation_path)
Definition device.hpp:137
Here is the call graph for this function:

◆ refresh() [1/4]

void tools::wallet2::refresh ( bool trusted_daemon)

Definition at line 3060 of file wallet2.cpp.

3061{
3062 uint64_t blocks_fetched = 0;
3063 refresh(trusted_daemon, 0, blocks_fetched);
3064}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ refresh() [2/4]

bool tools::wallet2::refresh ( bool trusted_daemon,
uint64_t & blocks_fetched,
bool & received_etn,
bool & ok )

Definition at line 3851 of file wallet2.cpp.

3852{
3853 try
3854 {
3855 refresh(trusted_daemon, 0, blocks_fetched, received_etn);
3856 ok = true;
3857 }
3858 catch (...)
3859 {
3860 ok = false;
3861 }
3862 return ok;
3863}
Here is the call graph for this function:

◆ refresh() [3/4]

void tools::wallet2::refresh ( bool trusted_daemon,
uint64_t start_height,
uint64_t & blocks_fetched )

Definition at line 3066 of file wallet2.cpp.

3067{
3068 bool received_etn = false;
3069 refresh(trusted_daemon, start_height, blocks_fetched, received_etn);
3070}
Here is the call graph for this function:

◆ refresh() [4/4]

void tools::wallet2::refresh ( bool trusted_daemon,
uint64_t start_height,
uint64_t & blocks_fetched,
bool & received_etn,
bool check_pool = true )

Definition at line 3493 of file wallet2.cpp.

3493 {
3494 if (m_offline) {
3495 blocks_fetched = 0;
3496 received_etn = 0;
3497 return;
3498 }
3499
3500 if (m_light_wallet) {
3501
3502 // MyMonero get_address_info needs to be called occasionally to trigger wallet sync.
3503 // This call is not really needed for other purposes and can be removed if mymonero changes their backend.
3505
3506 // Get basic info
3508 // Last stored block height
3509 uint64_t prev_height = m_light_wallet_blockchain_height;
3510 // Update lw heights
3511 m_light_wallet_scanned_block_height = res.scanned_block_height;
3512 m_light_wallet_blockchain_height = res.blockchain_height;
3513 // If new height - call new_block callback
3514 if (m_light_wallet_blockchain_height != prev_height) {
3515 MDEBUG("new block since last time!");
3516 m_callback->on_lw_new_block(m_light_wallet_blockchain_height - 1);
3517 }
3518 m_light_wallet_connected = true;
3519 MDEBUG("lw scanned block height: " << m_light_wallet_scanned_block_height);
3520 MDEBUG("lw blockchain height: " << m_light_wallet_blockchain_height);
3521 MDEBUG(m_light_wallet_blockchain_height - m_light_wallet_scanned_block_height << " blocks behind");
3522 // TODO: add wallet created block info
3523
3525 } else
3526 m_light_wallet_connected = false;
3527
3528 // Lighwallet refresh done
3529 return;
3530 }
3531 received_etn = false;
3532 blocks_fetched = 0;
3533 uint64_t added_blocks = 0;
3534 size_t try_count = 0;
3535 crypto::hash last_tx_hash_id = m_transfers.size() ? m_transfers.back().m_txid : null_hash;
3536 std::list<crypto::hash> short_chain_history;
3537 tools::threadpool &tpool = tools::threadpool::getInstance();
3538 tools::threadpool::waiter waiter;
3539 uint64_t blocks_start_height;
3540 std::vector<cryptonote::block_complete_entry> blocks;
3541 std::vector<parsed_block> parsed_blocks;
3542 bool refreshed = false;
3543 std::shared_ptr<std::pair<std::map<std::pair<uint64_t, uint64_t>, size_t>, std::map<std::pair<std::array<char, 32>, size_t>, size_t>>> output_tracker_cache; //this is where the only usage of output_tracker cache begins
3544 hw::device &hwdev = m_account.get_device();
3545
3546 // pull the first set of blocks
3547 get_short_chain_history(short_chain_history,
3548 (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
3549 m_run.store(true, std::memory_order_relaxed);
3550 if (start_height > m_blockchain.size() || m_refresh_from_block_height > m_blockchain.size()) {
3551 if (!start_height)
3552 start_height = m_refresh_from_block_height;
3553 // we can shortcut by only pulling hashes up to the start_height
3554 fast_refresh(start_height, blocks_start_height, short_chain_history);
3555 // regenerate the history now that we've got a full set of hashes
3556 short_chain_history.clear();
3557 get_short_chain_history(short_chain_history,
3558 (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
3559 start_height = 0;
3560 // and then fall through to regular refresh processing
3561 }
3562
3563 // If stop() is called during fast refresh we don't need to continue
3564 if (!m_run.load(std::memory_order_relaxed))
3565 return;
3566 // always reset start_height to 0 to force short_chain_ history to be used on
3567 // subsequent pulls in this refresh.
3568 start_height = 0;
3569
3570 auto keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this]() {
3571 if (m_encrypt_keys_after_refresh) {
3572 encrypt_keys(*m_encrypt_keys_after_refresh);
3573 m_encrypt_keys_after_refresh = boost::none;
3574 }
3575 });
3576
3577 auto scope_exit_handler_hwdev = epee::misc_utils::create_scope_leave_handler(
3578 [&]() { hwdev.computing_key_images(false); });
3579 bool first = true;
3580 while (m_run.load(std::memory_order_relaxed)) {
3581 uint64_t next_blocks_start_height;
3582 std::vector<cryptonote::block_complete_entry> next_blocks;
3583 std::vector<parsed_block> next_parsed_blocks;
3584 bool error;
3585 try {
3586 // pull the next set of blocks while we're processing the current one
3587 error = false;
3588 next_blocks.clear();
3589 next_parsed_blocks.clear();
3590 added_blocks = 0;
3591 if (!first && blocks.empty()) {
3592 refreshed = false;
3593 break;
3594 }
3595 tpool.submit(&waiter, [&] {
3596 pull_and_parse_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks,
3597 parsed_blocks, next_blocks, next_parsed_blocks, error);
3598 });
3599
3600 if (!first) {
3601 try {
3602 process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks,
3603 output_tracker_cache.get());
3604 }
3605 catch (const tools::error::out_of_hashchain_bounds_error &) {
3606 MINFO("Daemon claims next refresh block is out of hash chain bounds, resetting hash chain");
3607 uint64_t stop_height = m_blockchain.offset();
3608 std::vector<crypto::hash> tip(m_blockchain.size() - m_blockchain.offset());
3609 for (size_t i = m_blockchain.offset(); i < m_blockchain.size(); ++i)
3610 tip[i - m_blockchain.offset()] = m_blockchain[i];
3611 cryptonote::block b;
3612 generate_genesis(b);
3613 m_blockchain.clear();
3614 m_blockchain.push_back(get_block_hash(b));
3615 short_chain_history.clear();
3616 get_short_chain_history(short_chain_history);
3617 fast_refresh(stop_height, blocks_start_height, short_chain_history, true);
3619 (m_blockchain.size() == stop_height || (m_blockchain.size() == 1 && stop_height == 0)
3620 ? false : true), error::wallet_internal_error, "Unexpected hashchain size");
3621 THROW_WALLET_EXCEPTION_IF(m_blockchain.offset() != 0, error::wallet_internal_error,
3622 "Unexpected hashchain offset");
3623 for (const auto &h: tip)
3624 m_blockchain.push_back(h);
3625 short_chain_history.clear();
3626 get_short_chain_history(short_chain_history);
3627 start_height = stop_height;
3628 throw std::runtime_error(""); // loop again
3629 }
3630 catch (const std::exception &e) {
3631 MERROR("Error parsing blocks: " << e.what());
3632 error = true;
3633 }
3634 blocks_fetched += added_blocks;
3635 }
3636 waiter.wait(&tpool);
3637 if (!first && blocks_start_height == next_blocks_start_height) {
3638 m_node_rpc_proxy.set_height(m_blockchain.size());
3639 refreshed = true;
3640 break;
3641 }
3642
3643 first = false;
3644
3645 // handle error from async fetching thread
3646 if (error) {
3647 throw std::runtime_error("proxy exception in refresh thread");
3648 }
3649
3650 // if we've got at least 10 blocks to refresh, assume we're starting
3651 // a long refresh, and setup a tracking output cache if we need to
3652 // We hit create_output_tracker_cache before doing processing our blocks in process_parsed_blocks above( see 'first' variable)
3653 if (m_track_uses && (!output_tracker_cache ||
3654 (output_tracker_cache->first.empty() && output_tracker_cache->second.empty())) &&
3655 next_blocks.size() >= 10)
3656 output_tracker_cache = create_output_tracker_cache();
3657
3658 // switch to the new blocks from the daemon
3659 blocks_start_height = next_blocks_start_height;
3660 blocks = std::move(next_blocks);
3661 parsed_blocks = std::move(next_parsed_blocks);
3662 }
3663 catch (const tools::error::password_needed &) {
3664 blocks_fetched += added_blocks;
3665 waiter.wait(&tpool);
3666 throw;
3667 }
3668 catch (const std::exception &) {
3669 blocks_fetched += added_blocks;
3670 waiter.wait(&tpool);
3671 if (try_count < 3) {
3672 LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
3673 first = true;
3674 start_height = 0;
3675 blocks.clear();
3676 parsed_blocks.clear();
3677 short_chain_history.clear();
3678 get_short_chain_history(short_chain_history, 1);
3679 ++try_count;
3680 } else {
3681 LOG_ERROR("pull_blocks failed, try_count=" << try_count);
3682 throw;
3683 }
3684 }
3685 }
3686 if (last_tx_hash_id != (m_transfers.size() ? m_transfers.back().m_txid : null_hash))
3687 received_etn = true;
3688
3689 try {
3690 // If stop() is called we don't need to check pending transactions
3691 if (check_pool && m_run.load(std::memory_order_relaxed))
3692 update_pool_state(refreshed);
3693 }
3694 catch (...) {
3695 LOG_PRINT_L1("Failed to check pending transactions");
3696 }
3697
3698 m_first_refresh_done = true;
3699
3700 LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", pre v10 balance (all accounts): "
3701 << print_etn(balance_all(false)) << ", unlocked: "
3703 << ", post v10 balance (all accounts): "
3704 << print_etn(balance_all(true)) << ", unlocked: "
3706
3707 //get the testnet bridge address - should be same as mainnet because of our netbyte being erroneously set to the same thing when Electroneum was first created
3708 // cryptonote::account_public_address bridge_public_address;
3709 // std::string portal_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
3710 // std::string portal_address_spendkey_hex_str = "5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
3711 // epee::string_tools::hex_to_pod(portal_address_viewkey_hex_str, bridge_public_address.m_view_public_key);
3712 // epee::string_tools::hex_to_pod(portal_address_spendkey_hex_str, bridge_public_address.m_spend_public_key);
3713 // std::string bridge_address = cryptonote::get_account_address_as_str(this->nettype(), false, bridge_public_address); //OK
3714
3715 //generate the coinbase burn address. spendkey is "9511fabcb699b4f9dffc1779713d0dd7eb1ca56ba5b8ab8d3253a0a6ccf736b3", address "etnkCys4uGhSi9h48ajL9vBDJTcn2s2ttXtXq3SXWPAbiMHNhHitu5fJ8QgRfFWTzmJ8QgRfFWTzmJ8QgRfFWTzm4t51HTfCtK"
3716 //cryptonote::account_public_address coinbase_burn_address;
3717 //crypto::hash h;
3718 //crypto::ec_point point;
3719 //epee::string_tools::hex_to_pod("714c8d8eeee5243e7f266e5210f76f58b8b1d6330cedfbc4eda6d5947b212012", h); // genesis hash hex ---> hash type
3720 //crypto::hash_to_point(h, point); // generate curve point (burn address spendkey) deterministically in such a way that we can't recover the private key
3721 //crypto::public_key coinbase_burn_address_spendkey;
3722 //std::copy(std::begin(point.data), std::end(point.data), std::begin(coinbase_burn_address_spendkey.data)); // serialise point to pubkey type
3723 //std::string coinbase_burn_address_spendkey_hex_str = epee::string_tools::pod_to_hex(coinbase_burn_address_spendkey); // for testing only. pub spend =
3724 //std::string coinbase_burn_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
3725 //coinbase_burn_address.m_spend_public_key = coinbase_burn_address_spendkey;
3726 //epee::string_tools::hex_to_pod(coinbase_burn_address_viewkey_hex_str, coinbase_burn_address.m_view_public_key);
3727 //std::string coinbase_burn_address_str = cryptonote::get_account_address_as_str(this->nettype(), false, coinbase_burn_address); //OK
3728
3729
3730 try {
3731 // V9-->V10 PUBLIC MIGRATIONS
3732 // check that the local blockchain height is at least the v10 fork height + 5 blocks (so we know we don't need to scan for any more v1 outputs and they have all have 5 confs)
3733 //todo: write function for wallet that gets the b.major version for a given *local* blockchain height, to save hardcoding heights.
3734 uint64_t migration_minheight = this->nettype() == TESTNET ? 1086402 + 5 : 1175315 + 5;
3735 if (this->get_blockchain_current_height() > migration_minheight && this->unlocked_balance_all(false) != 0) {
3737 "You are now on the transparent version of Electroneum and so we're giving you the chance to migrate your funds via a sweep transaction back to your address.\n Don't worry, this migration is completely free of charge. Please follow the prompts to continue.");
3738 std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account; // map of: account index ----> (subaddress index, pair(u-balance, unlock time))
3739 // for each account, grab all of the subaddress info (index, (balance, unlock))
3740 for (uint32_t account_index = 0; account_index < this->get_num_subaddress_accounts(); ++account_index) {
3741 unlocked_balance_per_subaddress_per_account[account_index] = this->unlocked_balance_per_subaddress(
3742 account_index, false);
3743 }
3744 for (uint32_t i = 0; i < this->get_num_subaddress_accounts(); i++) {
3745 cryptonote::subaddress_index index;
3746 index.major = i;
3747 for (auto subaddress: unlocked_balance_per_subaddress_per_account[i]) {
3748 index.minor = subaddress.first;
3749
3750 if (subaddress.second.first != 0 &&
3751 subaddress.second.second == 0/*is there a fully unlocked nonzero balance /sanity check*/) {
3752 cryptonote::account_public_address address = get_subaddress(index); // BRIDGE PORTAL ADDRESS
3753 std::set<uint32_t> subaddress_source{index.minor};
3754 std::vector<wallet2::pending_tx> ptx_vector = this->create_transactions_all(0,
3755 address /*dest address*/,
3756 index.major !=
3757 0 ||
3758 index.minor !=
3759 0 /*is dest a subaddress*/,
3760 1 /*one output only*/,
3761 0 /* don't mix*/,
3762 0 /*default unlock time*/,
3763 4 /*highest priority*/,
3764 vector<uint8_t>() /*empty tx extra */,
3765 index.major /*account index*/,
3766 subaddress_source /*source subaddr index*/,
3767 true /*migrate*/);
3768 this->commit_tx(ptx_vector);
3769 }
3770 }
3771 }
3772 LOG_PRINT_L0("Migration to the public version of the blockchain has completed. Please use the command show_transfers (CLI Wallet) or get_transfers (RPC Wallet) to see the details of your migration transactions.");
3773 }
3774
3775 } catch(...) {
3776 THROW_WALLET_EXCEPTION(error::wallet_internal_error, "V9 (Privatised)-->V10 (Public) wallet migration failed.");
3777 }
3778
3779 try {
3780 // V10 Migration to Electroneum Smart Chain
3781 cryptonote::account_public_address portal_address;
3782 std::string portal_address_viewkey_hex_str;
3783 std::string portal_address_spendkey_hex_str;
3784 if(m_nettype == MAINNET){
3785 portal_address_viewkey_hex_str = "2b95a2eb2c62253c57e82b082b850bbf22a1a7829aaea09c7c1511c1cced4375";
3786 portal_address_spendkey_hex_str = "8ce0f34fd37c7f7d07c44024eb5b3cdf275d1b3e75c3464b808dce532e861137";
3787 }else{
3788 portal_address_viewkey_hex_str = "5866666666666666666666666666666666666666666666666666666666666666"; //private view is just 0100000000000000000000000000000000000000000000000000000000000000
3789 portal_address_spendkey_hex_str = "5bd0c0e25eee6133850edd2b255ed9e3d6bb99fd5f08b7b5cf7f2618ad6ff2a3"; //
3790 }
3791
3792 bool portal_wallet = //if the portal address wallet ever needs opening, don't allow it to sweep to itself
3793 epee::string_tools::pod_to_hex(get_address().m_spend_public_key) ==
3794 portal_address_spendkey_hex_str &&
3795 epee::string_tools::pod_to_hex(get_address().m_view_public_key) == portal_address_viewkey_hex_str;
3796
3797 epee::string_tools::hex_to_pod(portal_address_spendkey_hex_str, portal_address.m_spend_public_key);
3798 epee::string_tools::hex_to_pod(portal_address_viewkey_hex_str, portal_address.m_view_public_key);
3799
3800 // ONLY do migration transactions after the fork block
3801 uint64_t smartchain_migration_minheight = this->nettype() == MAINNET ? 1811310 : 1455270;
3802 if (this->get_blockchain_current_height() > smartchain_migration_minheight) {
3803 // check that unlocked balance = unlocked balance as a best-effort to ensure that we're not migrating the funds whilst more are in transit/confirming
3804 if ((!portal_wallet) && (this->balance_all(true) != 0) &&
3805 (this->unlocked_balance_all(true) == this->balance_all(true))) {
3806 std::cout << std::endl << "You are beginning your token migration over to the Electroneum Smart Chain." << std::endl;
3807 std::cout << "This transaction is feeless. For further information, please read our documentation over at https:///developer.electroneum.com/migration-to-smart-chain/overview" << std::endl;
3808 std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account; // map of: account index ----> (subaddress index, pair(u-balance, unlock time))
3809 // for each account, grab all of the subaddress info (index, (balance, unlock))
3810 for (uint32_t account_index = 0;
3811 account_index < this->get_num_subaddress_accounts(); ++account_index) {
3812 unlocked_balance_per_subaddress_per_account[account_index] = this->unlocked_balance_per_subaddress(
3813 account_index, true);
3814 }
3815 for (uint32_t i = 0; i < this->get_num_subaddress_accounts(); i++) {
3816 cryptonote::subaddress_index index;
3817 index.major = i;
3818 for (auto subaddress: unlocked_balance_per_subaddress_per_account[i]) {
3819 index.minor = subaddress.first;
3820
3821 if (subaddress.second.first != 0 &&
3822 subaddress.second.second ==
3823 0/*is there a fully unlocked nonzero balance /sanity check*/) {
3824 std::set<uint32_t> subaddress_source{index.minor};
3825 std::vector<wallet2::pending_tx> ptx_vector = this->create_transactions_all(0,
3826 portal_address /*dest address (portal address for bridge)*/,
3827 0 /*is dest a subaddress*/,
3828 1 /*one output only*/, //???????
3829 0 /* don't mix*/,
3830 0 /*default unlock time*/,
3831 1 /*priority - set low in case they don't have fees for high priority but do for low priority*/,
3832 vector<uint8_t>() /*empty tx extra */,
3833 index.major /*account index*/,
3834 subaddress_source /*source subaddr index*/,
3835 false /*migrate to transparent chain*/);
3836 this->commit_tx(ptx_vector);
3837 }
3838 }
3839 }
3840 std::cout << std::endl;
3841 std::cout << "Migration to Smart Chain portal address completed. Please use the command show_transfers (CLI Wallet) or get_transfers (RPC Wallet) to see the details of your Smart Chain migration transactions." << std::endl;
3842 std::cout << "Please note that the entire migration process is not instant and your funds may take some time to show up in the Smart Chain." << std::endl;
3843 std::cout << "You can find your SmartChain address using the \"spendkey\" command in the CLI wallet." << std::endl;
3844 }
3845 }
3846 } catch(...) {
3847 THROW_WALLET_EXCEPTION(error::wallet_internal_error, "V10 Smart Chain migration failed.");
3848 }
3849}
virtual void computing_key_images(bool started)
Definition device.hpp:247
void wait(threadpool *tpool)
void submit(waiter *waiter, std::function< void()> f, bool leaf=false)
static threadpool & getInstance()
Definition threadpool.h:46
void light_wallet_get_address_txs()
Definition wallet2.cpp:9454
void update_pool_state(bool refreshed=false)
Definition wallet2.cpp:3164
std::vector< wallet2::pending_tx > 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, const uint64_t unlock_time, uint32_t priority, const std::vector< uint8_t > &extra, uint32_t subaddr_account, std::set< uint32_t > subaddr_indices, const bool migrate=false)
bool light_wallet_get_address_info(tools::COMMAND_RPC_GET_ADDRESS_INFO::response &response)
Definition wallet2.cpp:9438
uint64_t unlocked_balance_all(bool public_blockchain, uint64_t *blocks_to_unlock=NULL) const
Definition wallet2.cpp:6300
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
epee::misc_utils::struct_init< response_t > response
#define FIRST_REFRESH_GRANULARITY
Definition wallet2.cpp:132
Here is the call graph for this function:

◆ remove_obsolete_pool_txs()

void tools::wallet2::remove_obsolete_pool_txs ( const std::vector< crypto::hash > & tx_hashes)

Definition at line 3136 of file wallet2.cpp.

3137{
3138 // remove pool txes to us that aren't in the pool anymore
3139 std::unordered_multimap<crypto::hash, wallet2::pool_payment_details>::iterator uit = m_unconfirmed_payments.begin();
3140 while (uit != m_unconfirmed_payments.end())
3141 {
3142 const crypto::hash &txid = uit->second.m_pd.m_tx_hash;
3143 bool found = false;
3144 for (const auto &it2: tx_hashes)
3145 {
3146 if (it2 == txid)
3147 {
3148 found = true;
3149 break;
3150 }
3151 }
3152 auto pit = uit++;
3153 if (!found)
3154 {
3155 MDEBUG("Removing " << txid << " from unconfirmed payments, not found in pool");
3156 m_unconfirmed_payments.erase(pit);
3157 if (0 != m_callback)
3158 m_callback->on_pool_tx_removed(txid);
3159 }
3160 }
3161}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ rescan_blockchain()

void tools::wallet2::rescan_blockchain ( bool hard,
bool refresh = true,
bool keep_key_images = false )

Definition at line 6540 of file wallet2.cpp.

6541{
6542 CHECK_AND_ASSERT_THROW_MES(!hard || !keep_key_images, "Cannot preserve key images on hard rescan");
6543 const size_t transfers_cnt = m_transfers.size();
6544 crypto::hash transfers_hash{};
6545
6546 if(hard)
6547 {
6548 clear();
6549 setup_new_blockchain();
6550 }
6551 else
6552 {
6553 if (keep_key_images && refresh)
6554 hash_m_transfers((int64_t) transfers_cnt, transfers_hash);
6555 clear_soft(keep_key_images);
6556 }
6557
6558 if (refresh)
6559 this->refresh(false);
6560
6561 if (refresh && keep_key_images)
6562 finish_rescan_bc_keep_key_images(transfers_cnt, transfers_hash);
6563}
void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ rescan_spent()

void tools::wallet2::rescan_spent ( )

Definition at line 6417 of file wallet2.cpp.

6418{
6419 // This is RPC call that can take a long time if there are many outputs,
6420 // so we call it several times, in stripes, so we don't time out spuriously
6421
6422 // M_TRANSFERS is a container of OUTPUTS and NOT a container of entire transfers!
6423
6424 // The logic for dealing with publicised (v8 hf) outputs is as follows:
6425 // 1. Check the output block height in m_transfers. If it's >= v8 hard fork height, the output must be a public one,
6426 // 2. m_transfers contains the tx hash and relative out index for each output which uniquely determine
6427 // 'chainstate UTXOs' in the blockchain database; if a chainstate UTXO is present in the DB, the output is truly
6428 // unspent. However nonexistence of the UTXO in the db doesn't mean it's spent, only that it doesn't exist. So we
6429 // must first check (by some means) that the output did exist. Use the tx input db.
6430 // 3. Call the daemon for this output and ask of the spent status.
6431 // 4. Set the correct spent status of the output in m_transfers
6432
6433 std::vector<int> spent_status;
6434 spent_status.reserve(m_transfers.size());
6435 const size_t chunk_size = 1000;
6436 for (size_t start_offset = 0; start_offset < m_transfers.size(); start_offset += chunk_size)
6437 {
6438 const size_t n_outputs = std::min<size_t>(chunk_size, m_transfers.size() - start_offset); // 1000 or less if we dont have 1000
6439 MDEBUG("Calling is_key_image_spent on " << start_offset << " - " << (start_offset + n_outputs - 1) << ", out of " << m_transfers.size());
6442 for (size_t n = start_offset; n < start_offset + n_outputs; ++n) //loop over key images for the outputs in m_transfers and put the key image in the request
6443 req.key_images.push_back(string_tools::pod_to_hex(m_transfers[n].m_key_image));
6444 m_daemon_rpc_mutex.lock();
6445 bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout); //fire off the check command
6446 m_daemon_rpc_mutex.unlock();
6447 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
6448 THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
6449 THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, get_rpc_status(daemon_resp.status));
6450 THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != n_outputs, error::wallet_internal_error,
6451 "daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
6452 std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(n_outputs));
6453 std::copy(daemon_resp.spent_status.begin(), daemon_resp.spent_status.end(), std::back_inserter(spent_status));
6454 }
6455
6456
6457 // urgent code update so just duplicate code above for public outputs
6458 uint64_t v8height = m_nettype == TESTNET ? 446674 : 589169;
6459 for (size_t start_offset = 0; start_offset < m_transfers.size(); start_offset += chunk_size)
6460 {
6461 const size_t n_outputs = std::min<size_t>(chunk_size, m_transfers.size() - start_offset);
6462 MDEBUG("Preparing is_public_output_spent request for outputs " << start_offset << " - " << (start_offset + n_outputs - 1) << ", out of " << m_transfers.size());
6463
6466
6467 // Prepare the request for public outputs only for m_transfers after v8 height
6468 for (size_t k = start_offset; k < start_offset + n_outputs; ++k) {
6469 if (m_transfers[k].m_block_height >= v8height) {
6470 public_output pub_out;
6471 pub_out.txid = epee::string_tools::pod_to_hex(m_transfers[k].m_txid);
6472 pub_out.relative_out_index = static_cast<uint64_t>(m_transfers[k].m_internal_output_index);
6473 req.public_outputs.push_back(pub_out);
6474 }
6475 }
6476
6477 if(req.public_outputs.size() == 0){
6478 MDEBUG("No public outs found in the range: " << start_offset << " - " << (start_offset + n_outputs - 1) << ", out of " << m_transfers.size() << ", skipping chunk");
6479 continue;
6480 }
6481 // We always call the daemon, but the request may be empty if no outputs meet the criteria
6482 m_daemon_rpc_mutex.lock();
6483 bool r = invoke_http_json("/is_public_output_spent", req, daemon_resp, rpc_timeout);
6484 m_daemon_rpc_mutex.unlock();
6485 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_public_output_spent");
6486 THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_public_output_spent");
6487 THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_public_output_spent_error, get_rpc_status(daemon_resp.status));
6488 THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != req.public_outputs.size(), error::wallet_internal_error,
6489 "daemon returned wrong response for is_public_output_spent, wrong amount count = " +
6490 std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(req.public_outputs.size()));
6491
6492 // Update spent_status only for outputs that were included in the request. do this by iterating through m_transfers and if it's >= v8 height
6493 // then set the corresponding spent status for the same index. use a request index like so because not always does n == request index
6494 // because not all outputs are public outputs
6495 size_t request_index = 0;
6496 for (size_t k = start_offset; k < start_offset + n_outputs; ++k) {
6497 if (m_transfers[k].m_block_height >= v8height) {
6498 spent_status[k] = daemon_resp.spent_status[request_index++];
6499 }
6500 }
6501 }
6502
6503 // update spent status in m_transfers
6504 // spent_status[i] guide:
6505 // UNSPENT = 0,
6506 // SPENT_IN_BLOCKCHAIN = 1,
6507 // SPENT_IN_POOL = 2,
6508 for (size_t i = 0; i < m_transfers.size(); ++i)
6509 {
6510 transfer_details& td = m_transfers[i];
6511 // a view wallet may not know about key images. only skip in this case IF it isn't a public output
6512 if (!(m_transfers[i].m_block_height >= v8height) && (!td.m_key_image_known || td.m_key_image_partial)) //we will hit this for all public outs, so modify here
6513 continue;
6514
6515 if (td.m_spent != (spent_status[i] != SPENT_STATUS::UNSPENT)) // if output in m_transfers is unspent and the daemon says spent or the other way round, handle either which way
6516 {
6517 if (td.m_spent) // given parent if statement, spent means we need to change to unspent
6518 {
6519 if(!(m_transfers[i].m_block_height >= v8height)){
6520 LOG_PRINT_L0("Marking output " << i << "(" << td.m_key_image << ") as unspent, it was marked as spent");
6521 } else{
6522 LOG_PRINT_L0("Marking public output " << i << " (txid: " << td.m_txid << ", index: " << td.m_internal_output_index << ") as unspent, it was marked as spent");
6523 }
6524 set_unspent(i);
6525 td.m_spent_height = 0;
6526 }
6527 else // given parent if statement, unspent means we need to change to spent
6528 {
6529 if (!(m_transfers[i].m_block_height >= v8height)) {
6530 LOG_PRINT_L0("Marking output " << i << " (key image: " << epee::string_tools::pod_to_hex(td.m_key_image) << ") as spent, it was marked as unspent");
6531 } else {
6532 LOG_PRINT_L0("Not marking output " << i << " (txid: " << epee::string_tools::pod_to_hex(td.m_txid) << ", index: " << td.m_internal_output_index << ") as spent since block height " << td.m_block_height << " is below the threshold of " << v8height);
6533 }
6534 set_spent(i, td.m_spent_height);
6535 }
6536 }
6537 }
6538}
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
Here is the call graph for this function:
Here is the caller graph for this function:

◆ restore()

void tools::wallet2::restore ( const std::string & wallet_,
const epee::wipeable_string & password,
const std::string & device_name,
bool create_address_file = false )

Restore a wallet hold by an HW.

Creates a wallet from a device.

Parameters
wallet_Name of wallet file
passwordPassword of wallet file
device_namename of HW to use
create_address_fileWhether to create an address file
wallet_Name of wallet file
passwordPassword of wallet file
device_namedevice string address

Definition at line 5110 of file wallet2.cpp.

5111{
5112 clear();
5113 prepare_file_names(wallet_);
5114
5115 boost::system::error_code ignored_ec;
5116 if (!wallet_.empty()) {
5117 THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
5118 THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
5119 }
5120
5121 auto &hwdev = lookup_device(device_name);
5122 hwdev.set_name(device_name);
5123 hwdev.set_network_type(m_nettype);
5124 hwdev.set_derivation_path(m_device_derivation_path);
5125 hwdev.set_callback(get_device_callback());
5126
5127 m_account.create_from_device(hwdev);
5128 init_type(m_account.get_device().get_type());
5129 setup_keys(password);
5130 m_device_name = device_name;
5131
5132 create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
5133 if (m_subaddress_lookahead_major == SUBADDRESS_LOOKAHEAD_MAJOR && m_subaddress_lookahead_minor == SUBADDRESS_LOOKAHEAD_MINOR)
5134 {
5135 // the default lookahead setting (50:200) is clearly too much for hardware wallet
5136 m_subaddress_lookahead_major = 5;
5137 m_subaddress_lookahead_minor = 20;
5138 }
5139 setup_new_blockchain();
5140 if (!wallet_.empty()) {
5141 store();
5142 }
5143}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ rewrite()

void tools::wallet2::rewrite ( const std::string & wallet_name,
const epee::wipeable_string & password )

Rewrites to the wallet file for wallet upgrade (doesn't generate key, assumes it's already there).

Parameters
wallet_nameName of wallet file (should exist)
passwordPassword for wallet file

Definition at line 5670 of file wallet2.cpp.

5671{
5672 if (wallet_name.empty())
5673 return;
5674 prepare_file_names(wallet_name);
5675 boost::system::error_code ignored_ec;
5676 THROW_WALLET_EXCEPTION_IF(!boost::filesystem::exists(m_keys_file, ignored_ec), error::file_not_found, m_keys_file);
5677 bool r = store_keys(m_keys_file, password, m_watch_only);
5679}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sanity_check()

bool tools::wallet2::sanity_check ( const std::vector< wallet2::pending_tx > & ptx_vector,
std::vector< cryptonote::tx_destination_entry > dsts ) const

Definition at line 10280 of file wallet2.cpp.

10281 {
10282 MDEBUG("sanity_check: " << ptx_vector.size() << " txes, " << dsts.size() << " destinations");
10283
10284 hw::device &hwdev = m_account.get_device();
10285
10286 THROW_WALLET_EXCEPTION_IF(ptx_vector.empty(), error::wallet_internal_error, "No transactions");
10287
10288 if (std::all_of(ptx_vector.begin(), ptx_vector.end(), [](const pending_tx &ptx) { return ptx.tx.version == 1; })) { // we only need do tx proofs for v1
10289 // check every party in there does receive at least the required amount
10290 std::unordered_map<account_public_address, std::pair<uint64_t, bool>> required;
10291 for (const auto &d: dsts) {
10292 required[d.addr].first += d.amount;
10293 required[d.addr].second = d.is_subaddress;
10294 }
10295
10296 // add change
10297 uint64_t change = 0;
10298 for (const auto &ptx: ptx_vector) {
10299 for (size_t idx: ptx.selected_transfers) //1:add the amount you're spending
10300 change += m_transfers[idx].amount();
10301 change -= ptx.fee; //2: take off the fee
10302 }
10303 for (const auto &r: required)
10304 change -= r.second.first; // 3: subtract the destination required amount
10305 MDEBUG("Adding " << cryptonote::print_etn(change) << " expected change");
10306
10307 // for all txes that have actual change, check change is coming back to the sending wallet
10308 for (const pending_tx &ptx: ptx_vector) {
10309 if (ptx.change_dts.amount == 0)
10310 continue;
10312 m_subaddresses.find(ptx.change_dts.addr.m_spend_public_key) == m_subaddresses.end(),
10313 error::wallet_internal_error, "Change address is not ours");
10314 required[ptx.change_dts.addr].first += ptx.change_dts.amount;
10315 required[ptx.change_dts.addr].second = ptx.change_dts.is_subaddress;
10316 }
10317
10318
10319 for (const auto &r: required) {
10320 const account_public_address &address = r.first;
10321 const crypto::public_key &view_pkey = address.m_view_public_key;
10322
10323 uint64_t total_received = 0;
10324
10325 for (const auto &ptx: ptx_vector) {
10326 uint64_t received = 0;
10327 try {
10328 std::string proof = get_tx_proof(ptx.tx, ptx.tx_key, ptx.additional_tx_keys, address,
10329 r.second.second,
10330 "automatic-sanity-check");
10331 check_tx_proof(ptx.tx, address, r.second.second, "automatic-sanity-check", proof, received);
10332 }
10333 catch (const std::exception &e) { received = 0; }
10334 total_received += received;
10335 }
10336
10337 std::stringstream ss;
10338 ss << "Total received by "
10339 << cryptonote::get_account_address_as_str(m_nettype, r.second.second, address)
10340 << ": "
10341 << cryptonote::print_etn(total_received) << ", expected " << cryptonote::print_etn(r.second.first);
10342 MDEBUG(ss.str());
10343 THROW_WALLET_EXCEPTION_IF(total_received < r.second.first, error::wallet_internal_error, ss.str());
10344 }
10345 } // end of v1 sanity check
10346 else {
10347 // for all txes that have actual change, check change is coming back to the sending wallet
10348 for (const pending_tx &ptx: ptx_vector) {
10349 if (ptx.change_dts.amount == 0)
10350 continue;
10352 m_subaddresses.find(ptx.change_dts.addr.m_spend_public_key) == m_subaddresses.end(),
10353 error::wallet_internal_error, "Change address is not ours");
10354 }
10355 }
10356 return true;
10357}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ save_multisig_tx() [1/4]

bool tools::wallet2::save_multisig_tx ( const multisig_tx_set & txs,
const std::string & filename )

Definition at line 7469 of file wallet2.cpp.

7470{
7471 std::string ciphertext = save_multisig_tx(txs);
7472 if (ciphertext.empty())
7473 return false;
7474 return epee::file_io_utils::save_string_to_file(filename, ciphertext);
7475}
std::string save_multisig_tx(multisig_tx_set txs)
Definition wallet2.cpp:7431
Here is the call graph for this function:

◆ save_multisig_tx() [2/4]

std::string tools::wallet2::save_multisig_tx ( const std::vector< pending_tx > & ptx_vector)

Definition at line 7492 of file wallet2.cpp.

7493{
7494 return save_multisig_tx(make_multisig_tx_set(ptx_vector));
7495}
multisig_tx_set make_multisig_tx_set(const std::vector< pending_tx > &ptx_vector) const
Definition wallet2.cpp:7477
Here is the call graph for this function:

◆ save_multisig_tx() [3/4]

bool tools::wallet2::save_multisig_tx ( const std::vector< pending_tx > & ptx_vector,
const std::string & filename )

Definition at line 7497 of file wallet2.cpp.

7498{
7499 std::string ciphertext = save_multisig_tx(ptx_vector);
7500 if (ciphertext.empty())
7501 return false;
7502 return epee::file_io_utils::save_string_to_file(filename, ciphertext);
7503}
Here is the call graph for this function:

◆ save_multisig_tx() [4/4]

std::string tools::wallet2::save_multisig_tx ( multisig_tx_set txs)

Definition at line 7431 of file wallet2.cpp.

7432{
7433 LOG_PRINT_L0("saving " << txs.m_ptx.size() << " multisig transactions");
7434
7435 // txes generated, get rid of used k values
7436 for (size_t n = 0; n < txs.m_ptx.size(); ++n)
7437 for (size_t idx: txs.m_ptx[n].construction_data.selected_transfers)
7438 m_transfers[idx].m_multisig_k.clear();
7439
7440 // zero out some data we don't want to share
7441 for (auto &ptx: txs.m_ptx)
7442 {
7443 for (auto &e: ptx.construction_data.sources)
7444 e.multisig_kLRki.k = rct::zero();
7445 }
7446
7447 for (auto &ptx: txs.m_ptx)
7448 {
7449 // Get decrypted payment id from pending_tx
7450 ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx, m_account.get_device());
7451 }
7452
7453 // save as binary
7454 std::ostringstream oss;
7455 boost::archive::portable_binary_oarchive ar(oss);
7456 try
7457 {
7458 ar << txs;
7459 }
7460 catch (...)
7461 {
7462 return std::string();
7463 }
7464 LOG_PRINT_L2("Saving multisig unsigned tx data: " << oss.str());
7465 std::string ciphertext = encrypt_with_view_secret_key(oss.str());
7466 return std::string(MULTISIG_UNSIGNED_TX_PREFIX) + ciphertext;
7467}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ save_tx()

bool tools::wallet2::save_tx ( const std::vector< pending_tx > & ptx_vector,
const std::string & filename ) const

Definition at line 6975 of file wallet2.cpp.

6976{
6977 LOG_PRINT_L0("saving " << ptx_vector.size() << " transactions");
6978 std::string ciphertext = dump_tx_to_str(ptx_vector);
6979 if (ciphertext.empty())
6980 return false;
6981 return epee::file_io_utils::save_string_to_file(filename, ciphertext);
6982}
std::string dump_tx_to_str(const std::vector< pending_tx > &ptx_vector) const
Definition wallet2.cpp:6984
Here is the call graph for this function:
Here is the caller graph for this function:

◆ segregate_pre_fork_outputs() [1/2]

bool tools::wallet2::segregate_pre_fork_outputs ( ) const
inline

Definition at line 1095 of file wallet2.h.

1095{ return m_segregate_pre_fork_outputs; }

◆ segregate_pre_fork_outputs() [2/2]

void tools::wallet2::segregate_pre_fork_outputs ( bool value)
inline

Definition at line 1096 of file wallet2.h.

1096{ m_segregate_pre_fork_outputs = value; }

◆ segregation_height() [1/2]

uint64_t tools::wallet2::segregation_height ( ) const
inline

Definition at line 1099 of file wallet2.h.

1099{ return m_segregation_height; }

◆ segregation_height() [2/2]

void tools::wallet2::segregation_height ( uint64_t height)
inline

Definition at line 1100 of file wallet2.h.

1100{ m_segregation_height = height; }

◆ select_available_mixable_outputs()

std::vector< size_t > tools::wallet2::select_available_mixable_outputs ( )

Definition at line 10864 of file wallet2.cpp.

10865{
10866 // request all outputs with at least as many instances as the min ring size
10868}
std::vector< size_t > select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_available_outputs()

std::vector< size_t > tools::wallet2::select_available_outputs ( const std::function< bool(const transfer_details &td)> & f) const

Definition at line 10755 of file wallet2.cpp.

10756{
10757 std::vector<size_t> outputs;
10758 size_t n = 0;
10759 for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i, ++n)
10760 {
10761 if (i->m_spent)
10762 continue;
10763 if (i->m_frozen)
10764 continue;
10765 if (i->m_key_image_partial)
10766 continue;
10767 if (!is_transfer_unlocked(*i))
10768 continue;
10769 if (f(*i))
10770 outputs.push_back(n);
10771 }
10772 return outputs;
10773}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_available_outputs_from_histogram()

std::vector< size_t > tools::wallet2::select_available_outputs_from_histogram ( uint64_t count,
bool atleast,
bool unlocked,
bool allow_rct )

Definition at line 10792 of file wallet2.cpp.

10793{
10796 m_daemon_rpc_mutex.lock();
10797 if (is_trusted_daemon())
10798 req_t.amounts = get_unspent_amounts_vector();
10799 req_t.min_count = count;
10800 req_t.max_count = 0;
10801 req_t.unlocked = unlocked;
10802 req_t.recent_cutoff = 0;
10803 bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
10804 m_daemon_rpc_mutex.unlock();
10805 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_outputs_from_histogram");
10806 THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
10807 THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status);
10808
10809 std::set<uint64_t> mixable;
10810 for (const auto &i: resp_t.histogram)
10811 {
10812 mixable.insert(i.amount);
10813 }
10814
10815 return select_available_outputs([mixable, atleast, allow_rct](const transfer_details &td) {
10816 if (!allow_rct && td.is_rct())
10817 return false;
10818 const uint64_t amount = td.is_rct() ? 0 : td.amount();
10819 if (atleast) {
10820 if (mixable.find(amount) != mixable.end())
10821 return true;
10822 }
10823 else {
10824 if (mixable.find(amount) == mixable.end())
10825 return true;
10826 }
10827 return false;
10828 });
10829}
std::vector< size_t > select_available_outputs(const std::function< bool(const transfer_details &td)> &f) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_available_unmixable_outputs()

std::vector< size_t > tools::wallet2::select_available_unmixable_outputs ( )

Definition at line 10858 of file wallet2.cpp.

10859{
10860 // request all outputs with less instances than the min ring size
10861 return select_available_outputs_from_histogram(get_min_ring_size(), false, true, false);
10862}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ serialize()

template<class t_archive>
void tools::wallet2::serialize ( t_archive & a,
const unsigned int ver )
inline

Definition at line 910 of file wallet2.h.

911 {
912 uint64_t dummy_refresh_height = 0; // moved to keys file
913 if(ver < 5)
914 return;
915 if (ver < 19)
916 {
917 std::vector<crypto::hash> blockchain;
918 a & blockchain;
919 for (const auto &b: blockchain)
920 {
921 m_blockchain.push_back(b);
922 }
923 }
924 else
925 {
926 a & m_blockchain;
927 }
928 a & m_transfers;
929 a & m_account_public_address;
930 a & m_key_images;
931 if(ver < 6)
932 return;
933 a & m_unconfirmed_txs;
934 if(ver < 7)
935 return;
936 a & m_payments;
937 if(ver < 8)
938 return;
939 a & m_tx_keys;
940 if(ver < 9)
941 return;
942 a & m_confirmed_txs;
943 if(ver < 11)
944 return;
945 a & dummy_refresh_height;
946 if(ver < 12)
947 return;
948 a & m_tx_notes;
949 if(ver < 13)
950 return;
951 if (ver < 17)
952 {
953 // we're loading an old version, where m_unconfirmed_payments was a std::map
954 std::unordered_map<crypto::hash, payment_details> m;
955 a & m;
956 for (std::unordered_map<crypto::hash, payment_details>::const_iterator i = m.begin(); i != m.end(); ++i)
957 m_unconfirmed_payments.insert(std::make_pair(i->first, pool_payment_details{i->second, false}));
958 }
959 if(ver < 14)
960 return;
961 if(ver < 15)
962 {
963 // we're loading an older wallet without a pubkey map, rebuild it
964 for (size_t i = 0; i < m_transfers.size(); ++i)
965 {
966 const transfer_details &td = m_transfers[i];
967 const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index];
968 const cryptonote::txout_to_key &o = boost::get<const cryptonote::txout_to_key>(out.target);
969 m_pub_keys.emplace(o.key, i);
970 }
971 return;
972 }
973 a & m_pub_keys;
974 if(ver < 16)
975 return;
976 a & m_address_book;
977 if(ver < 17)
978 return;
979 if (ver < 22)
980 {
981 // we're loading an old version, where m_unconfirmed_payments payload was payment_details
982 std::unordered_multimap<crypto::hash, payment_details> m;
983 a & m;
984 for (const auto &i: m)
985 m_unconfirmed_payments.insert(std::make_pair(i.first, pool_payment_details{i.second, false}));
986 }
987 if(ver < 18)
988 return;
989 a & m_scanned_pool_txs[0];
990 a & m_scanned_pool_txs[1];
991 if (ver < 20)
992 return;
993 a & m_subaddresses;
994 std::unordered_map<cryptonote::subaddress_index, crypto::public_key> dummy_subaddresses_inv;
995 a & dummy_subaddresses_inv;
996 a & m_subaddress_labels;
997 a & m_additional_tx_keys;
998 if(ver < 21)
999 return;
1000 a & m_attributes;
1001 if(ver < 22)
1002 return;
1003 a & m_unconfirmed_payments;
1004 if(ver < 23)
1005 return;
1006 a & m_account_tags;
1007 if(ver < 24)
1008 return;
1009 a & m_ring_history_saved;
1010 if(ver < 25)
1011 return;
1012 a & m_last_block_reward;
1013 if(ver < 26)
1014 return;
1015 a & m_tx_device;
1016 if(ver < 27)
1017 return;
1018 a & m_device_last_key_image_sync;
1019 if(ver < 28)
1020 return;
1021 a & m_cold_key_images;
1022 if(ver < 29)
1023 return;
1024 a & m_chainstate_indexes;
1025 }

◆ set_account_tag()

void tools::wallet2::set_account_tag ( const std::set< uint32_t > & account_indices,
const std::string & tag )

Set a tag to the given accounts.

Parameters
account_indicesIndices of accounts.
tagTag's name. If empty, the accounts become untagged.

Definition at line 12056 of file wallet2.cpp.

12057{
12058 for (uint32_t account_index : account_indices)
12059 {
12060 THROW_WALLET_EXCEPTION_IF(account_index >= get_num_subaddress_accounts(), error::wallet_internal_error, "Account index out of bound");
12061 if (m_account_tags.second[account_index] == tag)
12062 MDEBUG("This tag is already assigned to this account");
12063 else
12064 m_account_tags.second[account_index] = tag;
12065 }
12067}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_account_tag_description()

void tools::wallet2::set_account_tag_description ( const std::string & tag,
const std::string & description )

Set the label of the given tag.

Parameters
tagTag's name (which must be non-empty).
descriptionTag's description.

Definition at line 12069 of file wallet2.cpp.

12070{
12071 THROW_WALLET_EXCEPTION_IF(tag.empty(), error::wallet_internal_error, "Tag must not be empty");
12072 THROW_WALLET_EXCEPTION_IF(m_account_tags.first.count(tag) == 0, error::wallet_internal_error, "Tag is unregistered");
12073 m_account_tags.first[tag] = description;
12074}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_attribute()

void tools::wallet2::set_attribute ( const std::string & key,
const std::string & value )

Definition at line 12013 of file wallet2.cpp.

12014{
12015 m_attributes[key] = value;
12016}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_blackballed_outputs()

bool tools::wallet2::set_blackballed_outputs ( const std::vector< std::pair< uint64_t, uint64_t > > & outputs,
bool add = false )

Definition at line 8183 of file wallet2.cpp.

8184{
8185 if (!m_ringdb)
8186 return false;
8187 try
8188 {
8189 bool ret = true;
8190 if (!add)
8191 ret &= m_ringdb->clear_blackballs();
8192 ret &= m_ringdb->blackball(outputs);
8193 return ret;
8194 }
8195 catch (const std::exception &e) { return false; }
8196}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_confirm_backlog_threshold()

void tools::wallet2::set_confirm_backlog_threshold ( uint32_t threshold)
inline

Definition at line 1089 of file wallet2.h.

1089{ m_confirm_backlog_threshold = threshold; };

◆ set_daemon()

bool tools::wallet2::set_daemon ( std::string daemon_address = "http://localhost:8080",
boost::optional< epee::net_utils::http::login > daemon_login = boost::none,
bool trusted_daemon = true,
epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect )

Definition at line 1268 of file wallet2.cpp.

1269{
1270 boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1271
1272 if(m_http_client.is_connected())
1273 m_http_client.disconnect();
1274 m_daemon_address = std::move(daemon_address);
1275 m_daemon_login = std::move(daemon_login);
1276 m_trusted_daemon = trusted_daemon;
1277
1278 MINFO("setting daemon to " << get_daemon_address());
1279 return m_http_client.set_server(get_daemon_address(), get_daemon_login(), std::move(ssl_options));
1280}
const boost::optional< epee::net_utils::http::login > & get_daemon_login() const
Definition wallet2.h:1165
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_default_priority()

void tools::wallet2::set_default_priority ( uint32_t p)
inline

Definition at line 1074 of file wallet2.h.

1074{ m_default_priority = p; }

◆ set_description()

void tools::wallet2::set_description ( const std::string & description)

Definition at line 12026 of file wallet2.cpp.

12027{
12029}
void set_attribute(const std::string &key, const std::string &value)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_light_wallet()

void tools::wallet2::set_light_wallet ( bool light_wallet)
inline

Definition at line 778 of file wallet2.h.

778{ m_light_wallet = light_wallet; }
bool light_wallet() const
Checks if light wallet. A light wallet sends view key to a server where the blockchain is scanned.
Definition wallet2.h:777
Here is the call graph for this function:

◆ set_min_output_count()

void tools::wallet2::set_min_output_count ( uint32_t count)
inline

Definition at line 1081 of file wallet2.h.

1081{ m_min_output_count = count; }

◆ set_min_output_value()

void tools::wallet2::set_min_output_value ( uint64_t value)
inline

Definition at line 1083 of file wallet2.h.

1083{ m_min_output_value = value; }

◆ set_offline()

void tools::wallet2::set_offline ( bool offline = true)

Definition at line 5810 of file wallet2.cpp.

5811{
5812 m_offline = offline;
5813 m_http_client.set_auto_connect(!offline);
5814 if (offline)
5815 {
5816 boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
5817 if(m_http_client.is_connected())
5818 m_http_client.disconnect();
5819 }
5820}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_refresh_from_block_height()

void tools::wallet2::set_refresh_from_block_height ( uint64_t height)
inline

Definition at line 742 of file wallet2.h.

742{m_refresh_from_block_height = height;}

◆ set_refresh_type()

void tools::wallet2::set_refresh_type ( RefreshType refresh_type)
inline

Definition at line 821 of file wallet2.h.

821{ m_refresh_type = refresh_type; }

◆ set_ring()

bool tools::wallet2::set_ring ( const crypto::key_image & key_image,
const std::vector< uint64_t > & outs,
bool relative )

Definition at line 8063 of file wallet2.cpp.

8064{
8065 if (!m_ringdb)
8066 return false;
8067
8068 try { return m_ringdb->set_ring(get_ringdb_key(), key_image, outs, relative); }
8069 catch (const std::exception &e) { return false; }
8070}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_ring_database()

bool tools::wallet2::set_ring_database ( const std::string & filename)

Definition at line 7956 of file wallet2.cpp.

7957{
7958 m_ring_database = filename;
7959 MINFO("ringdb path set to " << filename);
7960 m_ringdb.reset();
7961 if (!m_ring_database.empty())
7962 {
7963 try
7964 {
7965 cryptonote::block b;
7966 generate_genesis(b);
7967 m_ringdb.reset(new tools::ringdb(m_ring_database, epee::string_tools::pod_to_hex(get_block_hash(b))));
7968 }
7969 catch (const std::exception &e)
7970 {
7971 MERROR("Failed to initialize ringdb: " << e.what());
7972 m_ring_database = "";
7973 return false;
7974 }
7975 }
7976 return true;
7977}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_seed_language()

void tools::wallet2::set_seed_language ( const std::string & language)

Sets the seed language.

Parameters
languageSeed language to set to

Definition at line 1425 of file wallet2.cpp.

1426{
1427 seed_language = language;
1428}

◆ set_subaddress_label()

void tools::wallet2::set_subaddress_label ( const cryptonote::subaddress_index & index,
const std::string & label )

Definition at line 1528 of file wallet2.cpp.

1529{
1530 THROW_WALLET_EXCEPTION_IF(index.major >= m_subaddress_labels.size(), error::account_index_outofbound);
1531 THROW_WALLET_EXCEPTION_IF(index.minor >= m_subaddress_labels[index.major].size(), error::address_index_outofbound);
1532 m_subaddress_labels[index.major][index.minor] = label;
1533}

◆ set_subaddress_lookahead()

void tools::wallet2::set_subaddress_lookahead ( size_t major,
size_t minor )

Definition at line 1535 of file wallet2.cpp.

1536{
1537 THROW_WALLET_EXCEPTION_IF(major > 0xffffffff, error::wallet_internal_error, "Subaddress major lookahead is too large");
1538 THROW_WALLET_EXCEPTION_IF(minor > 0xffffffff, error::wallet_internal_error, "Subaddress minor lookahead is too large");
1539 m_subaddress_lookahead_major = major;
1540 m_subaddress_lookahead_minor = minor;
1541}

◆ set_trusted_daemon()

void tools::wallet2::set_trusted_daemon ( bool trusted)
inline

Definition at line 766 of file wallet2.h.

766{ m_trusted_daemon = trusted; }

◆ set_tx_device_aux()

void tools::wallet2::set_tx_device_aux ( const crypto::hash & txid,
const std::string & aux )

Definition at line 12000 of file wallet2.cpp.

12001{
12002 m_tx_device[txid] = aux;
12003}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_tx_key()

void tools::wallet2::set_tx_key ( const crypto::hash & txid,
const crypto::secret_key & tx_key,
const std::vector< crypto::secret_key > & additional_tx_keys )

Definition at line 11000 of file wallet2.cpp.

11001{
11002 // fetch tx from daemon and check if secret keys agree with corresponding public keys
11004 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11005 req.decode_as_json = false;
11006 req.prune = true;
11008 bool r;
11009 {
11010 const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
11011 r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11012 }
11013 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
11014 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
11015 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
11016 THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
11017 "daemon returned wrong response for gettransactions, wrong txs count = " +
11018 std::to_string(res.txs.size()) + ", expected 1");
11019 cryptonote::transaction tx;
11020 crypto::hash tx_hash;
11021 THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(res.txs[0], tx, tx_hash), error::wallet_internal_error,
11022 "Failed to get transaction from daemon");
11023 THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "txid mismatch");
11024 std::vector<tx_extra_field> tx_extra_fields;
11025 THROW_WALLET_EXCEPTION_IF(!parse_tx_extra(tx.extra, tx_extra_fields), error::wallet_internal_error, "Transaction extra has unsupported format");
11026 tx_extra_pub_key pub_key_field;
11027 bool found = false;
11028 size_t index = 0;
11029 while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, index++))
11030 {
11031 crypto::public_key calculated_pub_key;
11032 crypto::secret_key_to_public_key(tx_key, calculated_pub_key);
11033 if (calculated_pub_key == pub_key_field.pub_key)
11034 {
11035 found = true;
11036 break;
11037 }
11038 }
11039 THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error, "Given tx secret key doesn't agree with the tx public key in the blockchain");
11040 tx_extra_additional_pub_keys additional_tx_pub_keys;
11041 find_tx_extra_field_by_type(tx_extra_fields, additional_tx_pub_keys);
11042 THROW_WALLET_EXCEPTION_IF(additional_tx_keys.size() != additional_tx_pub_keys.data.size(), error::wallet_internal_error, "The number of additional tx secret keys doesn't agree with the number of additional tx public keys in the blockchain" );
11043 m_tx_keys.insert(std::make_pair(txid, tx_key));
11044 m_additional_tx_keys.insert(std::make_pair(txid, additional_tx_keys));
11045}
std::vector< crypto::public_key > data
Definition tx_extra.h:170
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_tx_note()

void tools::wallet2::set_tx_note ( const crypto::hash & txid,
const std::string & note )

Definition at line 11987 of file wallet2.cpp.

11988{
11989 m_tx_notes[txid] = note;
11990}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_tx_notify()

void tools::wallet2::set_tx_notify ( const std::shared_ptr< tools::Notify > & notify)
inline

Definition at line 1377 of file wallet2.h.

1377{ m_tx_notify = notify; }

◆ setup_background_mining() [1/2]

BackgroundMiningSetupType tools::wallet2::setup_background_mining ( ) const
inline

Definition at line 1107 of file wallet2.h.

1107{ return m_setup_background_mining; }

◆ setup_background_mining() [2/2]

void tools::wallet2::setup_background_mining ( BackgroundMiningSetupType value)
inline

Definition at line 1108 of file wallet2.h.

1108{ m_setup_background_mining = value; }

◆ sign()

std::string tools::wallet2::sign ( const std::string & data) const

Definition at line 12076 of file wallet2.cpp.

12077{
12079 crypto::cn_fast_hash(data.data(), data.size(), hash);
12080 const cryptonote::account_keys &keys = m_account.get_keys();
12083 return std::string("SigV1") + tools::base58::encode(std::string((const char *)&signature, sizeof(signature)));
12084}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sign_multisig_participant()

std::string tools::wallet2::sign_multisig_participant ( const std::string & data) const

sign_multisig_participant signs given message with the multisig public signer key

Parameters
datamessage to sign
Exceptions
ifwallet is not multisig
Returns
signature

Definition at line 12109 of file wallet2.cpp.

12110{
12111 CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12112
12114 crypto::cn_fast_hash(data.data(), data.size(), hash);
12115 const cryptonote::account_keys &keys = m_account.get_keys();
12118 return MULTISIG_SIGNATURE_MAGIC + tools::base58::encode(std::string((const char *)&signature, sizeof(signature)));
12119}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sign_multisig_tx()

bool tools::wallet2::sign_multisig_tx ( multisig_tx_set & exported_txs,
std::vector< crypto::hash > & txids )

Definition at line 7607 of file wallet2.cpp.

7608{
7609 THROW_WALLET_EXCEPTION_IF(exported_txs.m_ptx.empty(), error::wallet_internal_error, "No tx found");
7610
7612
7613 THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.find(local_signer) != exported_txs.m_signers.end(),
7614 error::wallet_internal_error, "Transaction already signed by this private key");
7615 THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.size() > m_multisig_threshold,
7616 error::wallet_internal_error, "Transaction was signed by too many signers");
7617 THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.size() == m_multisig_threshold,
7618 error::wallet_internal_error, "Transaction is already fully signed");
7619
7620 txids.clear();
7621
7622 // sign the transactions
7623 for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
7624 {
7625 tools::wallet2::pending_tx &ptx = exported_txs.m_ptx[n];
7626 THROW_WALLET_EXCEPTION_IF(ptx.multisig_sigs.empty(), error::wallet_internal_error, "No signatures found in multisig tx");
7627 tools::wallet2::tx_construction_data &sd = ptx.construction_data;
7628 LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, mixin " << (sd.sources[0].outputs.size()-1) <<
7629 ", signed by " << exported_txs.m_signers.size() << "/" << m_multisig_threshold);
7630 cryptonote::transaction tx;
7631 rct::multisig_out msout = ptx.multisig_sigs.front().msout;
7632 auto sources = sd.sources;
7633 rct::RCTConfig rct_config = sd.rct_config;
7634 bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, rct_config, &msout, false, 0 /*===default value*/, this->m_nettype);
7635 THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
7636
7638 error::wallet_internal_error, "Transaction prefix does not match data");
7639
7640 // Tests passed, sign
7641 std::vector<unsigned int> indices;
7642 for (const auto &source: sources)
7643 indices.push_back(source.real_output);
7644
7645 for (auto &sig: ptx.multisig_sigs)
7646 {
7647 if (sig.ignore.find(local_signer) == sig.ignore.end())
7648 {
7649 ptx.tx.rct_signatures = sig.sigs;
7650
7651 rct::keyV k;
7652 for (size_t idx: sd.selected_transfers)
7653 k.push_back(get_multisig_k(idx, sig.used_L));
7654
7655 rct::key skey = rct::zero();
7656 for (const auto &msk: get_account().get_multisig_keys())
7657 {
7659
7660 if (sig.signing_keys.find(pmsk) == sig.signing_keys.end())
7661 {
7662 sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes);
7663 sig.signing_keys.insert(pmsk);
7664 }
7665 }
7666 THROW_WALLET_EXCEPTION_IF(!rct::signMultisig(ptx.tx.rct_signatures, indices, k, sig.msout, skey),
7667 error::wallet_internal_error, "Failed signing, transaction likely malformed");
7668
7669 sig.sigs = ptx.tx.rct_signatures;
7670 }
7671 }
7672
7673 const bool is_last = exported_txs.m_signers.size() + 1 >= m_multisig_threshold;
7674 if (is_last)
7675 {
7676 // when the last signature on a multisig tx is made, we select the right
7677 // signature to plug into the final tx
7678 bool found = false;
7679 for (const auto &sig: ptx.multisig_sigs)
7680 {
7681 if (sig.ignore.find(local_signer) == sig.ignore.end() && !keys_intersect(sig.ignore, exported_txs.m_signers))
7682 {
7683 THROW_WALLET_EXCEPTION_IF(found, error::wallet_internal_error, "More than one transaction is final");
7684 ptx.tx.rct_signatures = sig.sigs;
7685 found = true;
7686 }
7687 }
7688 THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error,
7689 "Final signed transaction not found: this transaction was likely made without our export data, so we cannot sign it");
7690 const crypto::hash txid = get_transaction_hash(ptx.tx);
7691 if (store_tx_info())
7692 {
7693 m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
7694 m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
7695 }
7696 txids.push_back(txid);
7697 }
7698 }
7699
7700 // txes generated, get rid of used k values
7701 for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
7702 for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers)
7703 m_transfers[idx].m_multisig_k.clear();
7704
7705 exported_txs.m_signers.insert(get_multisig_signer_public_key());
7706
7707 return true;
7708}
bool construct_tx_with_tx_key(const account_keys &sender_account_keys, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, std::vector< tx_source_entry > &sources, std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr, const std::vector< uint8_t > &extra, transaction &tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector< crypto::secret_key > &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, bool shuffle_outs, const uint32_t account_major_offset, const cryptonote::network_type nettype)
std::vector< key > keyV
Definition rctTypes.h:88
bool signMultisig(rctSig &rv, const std::vector< unsigned int > &indices, const keyV &k, const multisig_out &msout, const key &secret_key)
Definition rctSigs.cpp:1210
const CharType(& source)[N]
Definition pointer.h:1147
tx_construction_data construction_data
Definition wallet2.h:477
crypto::secret_key tx_key
Definition wallet2.h:472
std::vector< multisig_sig > multisig_sigs
Definition wallet2.h:475
cryptonote::transaction tx
Definition wallet2.h:466
std::vector< crypto::secret_key > additional_tx_keys
Definition wallet2.h:473
cryptonote::tx_destination_entry change_dts
Definition wallet2.h:469
std::vector< uint8_t > extra
Definition wallet2.h:426
std::vector< cryptonote::tx_source_entry > sources
Definition wallet2.h:422
std::vector< cryptonote::tx_destination_entry > splitted_dsts
Definition wallet2.h:424
std::vector< size_t > selected_transfers
Definition wallet2.h:425
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sign_multisig_tx_from_file()

bool tools::wallet2::sign_multisig_tx_from_file ( const std::string & filename,
std::vector< crypto::hash > & txids,
std::function< bool(const multisig_tx_set &)> accept_func )

Definition at line 7718 of file wallet2.cpp.

7719{
7720 multisig_tx_set exported_txs;
7721 if(!load_multisig_tx_from_file(filename, exported_txs))
7722 return false;
7723
7724 if (accept_func && !accept_func(exported_txs))
7725 {
7726 LOG_PRINT_L1("Transactions rejected by callback");
7727 return false;
7728 }
7729 return sign_multisig_tx_to_file(exported_txs, filename, txids);
7730}
bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector< crypto::hash > &txids)
Definition wallet2.cpp:7710
bool load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function< bool(const multisig_tx_set &)> accept_func=NULL)
Definition wallet2.cpp:7583
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sign_multisig_tx_to_file()

bool tools::wallet2::sign_multisig_tx_to_file ( multisig_tx_set & exported_txs,
const std::string & filename,
std::vector< crypto::hash > & txids )

Definition at line 7710 of file wallet2.cpp.

7711{
7712 bool r = sign_multisig_tx(exported_txs, txids);
7713 if (!r)
7714 return false;
7715 return save_multisig_tx(exported_txs, filename);
7716}
bool sign_multisig_tx(multisig_tx_set &exported_txs, std::vector< crypto::hash > &txids)
Definition wallet2.cpp:7607
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sign_tx() [1/3]

bool tools::wallet2::sign_tx ( const std::string & unsigned_filename,
const std::string & signed_filename,
std::vector< wallet2::pending_tx > & ptx,
std::function< bool(const unsigned_tx_set &)> accept_func = NULL,
bool export_raw = false )
Here is the caller graph for this function:

◆ sign_tx() [2/3]

bool tools::wallet2::sign_tx ( unsigned_tx_set & exported_txs,
const std::string & signed_filename,
std::vector< wallet2::pending_tx > & ptx,
bool export_raw = false )
Here is the call graph for this function:

◆ sign_tx() [3/3]

bool tools::wallet2::sign_tx ( unsigned_tx_set & exported_txs,
std::vector< wallet2::pending_tx > & ptx,
signed_tx_set & signed_txs )

Definition at line 7116 of file wallet2.cpp.

7117{
7118 import_outputs(exported_txs.transfers);
7119
7120 // sign the transactions
7121 for (size_t n = 0; n < exported_txs.txes.size(); ++n)
7122 {
7123 tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
7124 THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources");
7125 LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
7126 signed_txes.ptx.push_back(pending_tx());
7127 tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
7128 rct::RCTConfig rct_config = sd.rct_config;
7129 crypto::secret_key tx_key;
7130 std::vector<crypto::secret_key> additional_tx_keys;
7131 rct::multisig_out msout;
7132
7133 // NB no early blocks this time for v3 transactions, as nobody should be sending v3 transactions before their v2 (migration) tx have confirmed. V2 confirmations always take place at, or after, the fork block.
7134 // todo: 4.0.0.0 Migrate vs send regular tx.
7136 bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, rct_config, m_multisig ? &msout : NULL, m_account_major_offset, this->m_nettype);
7137 THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
7138 // we don't test tx size, because we don't know the current limit, due to not having a blockchain,
7139 // and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
7140 // and if we really go over limit, the daemon will reject when it gets submitted. Chances are it's
7141 // OK anyway since it was generated in the first place, and rerolling should be within a few bytes.
7142
7143 // normally, the tx keys are saved in commit_tx, when the tx is actually sent to the daemon.
7144 // we can't do that here since the tx will be sent from the compromised wallet, which we don't want
7145 // to see that info, so we save it here
7146 if (store_tx_info())
7147 {
7148 const crypto::hash txid = get_transaction_hash(ptx.tx);
7149 m_tx_keys.insert(std::make_pair(txid, tx_key));
7150 m_additional_tx_keys.insert(std::make_pair(txid, additional_tx_keys));
7151 }
7152
7153 std::string key_images;
7154
7155 if(ptx.tx.version < 3) {
7156 bool all_are_txin_to_key = std::all_of(ptx.tx.vin.begin(), ptx.tx.vin.end(), [&](const txin_v &s_e) -> bool {
7157 CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false);
7158 key_images += boost::to_string(in.k_image) + " ";
7159 return true;
7160 });
7161 THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, ptx.tx);
7162 }else{
7163 bool all_are_txin_to_key_public = std::all_of(ptx.tx.vin.begin(), ptx.tx.vin.end(), [&](const txin_v &s_e) -> bool {
7164 CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key_public, in, false);
7165 return true;
7166 });
7167 THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key_public, error::unexpected_txin_type, ptx.tx);
7168 }
7169 if(ptx.tx.version > 1) {
7170 bool all_are_txout_to_key_public = std::all_of(ptx.tx.vout.begin(), ptx.tx.vout.end(), [&](const tx_out &s_e) -> bool {
7171 CHECKED_GET_SPECIFIC_VARIANT(s_e.target, const txout_to_key_public, in, false);
7172 return true;
7173 });
7174 THROW_WALLET_EXCEPTION_IF(!all_are_txout_to_key_public, error::unexpected_txout_type, ptx.tx);
7175 }
7176 ptx.key_images = key_images;
7177 ptx.fee = 0;
7178 for (const auto &i: sd.sources) ptx.fee += i.amount;
7179 for (const auto &i: sd.splitted_dsts) ptx.fee -= i.amount;
7180 ptx.dust = 0;
7181 ptx.dust_added_to_fee = false;
7182 ptx.change_dts = sd.change_dts;
7184 ptx.tx_key = rct::rct2sk(rct::identity()); // don't send it back to the untrusted view wallet
7185 ptx.dests = sd.dests;
7186 ptx.construction_data = sd;
7187
7188 txs.push_back(ptx);
7189
7190 // add tx keys only to ptx
7191 txs.back().tx_key = tx_key;
7192 txs.back().additional_tx_keys = additional_tx_keys;
7193 }
7194
7195 // add key image mapping for these txes
7196 const account_keys &keys = get_account().get_keys();
7197 hw::device &hwdev = m_account.get_device();
7198 for (size_t n = 0; n < exported_txs.txes.size(); ++n)
7199 {
7200 const cryptonote::transaction &tx = signed_txes.ptx[n].tx;
7201
7202 crypto::key_derivation derivation;
7203 std::vector<crypto::key_derivation> additional_derivations;
7204
7205 // compute public keys from out secret keys
7206 crypto::public_key tx_pub_key;
7207 crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key);
7208 std::vector<crypto::public_key> additional_tx_pub_keys;
7209 for (const crypto::secret_key &skey: txs[n].additional_tx_keys)
7210 {
7211 additional_tx_pub_keys.resize(additional_tx_pub_keys.size() + 1);
7212 crypto::secret_key_to_public_key(skey, additional_tx_pub_keys.back());
7213 }
7214
7215 // compute derivations
7217 if (!hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation))
7218 {
7219 MWARNING("Failed to generate key derivation from tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
7220 static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key");
7221 memcpy(&derivation, rct::identity().bytes, sizeof(derivation));
7222 }
7223 for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
7224 {
7225 additional_derivations.push_back({});
7226 if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
7227 {
7228 MWARNING("Failed to generate key derivation from additional tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
7229 memcpy(&additional_derivations.back(), rct::identity().bytes, sizeof(crypto::key_derivation));
7230 }
7231 }
7232
7233 for (size_t i = 0; i < tx.vout.size(); ++i)
7234 {
7235 if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
7236 continue;
7237 const cryptonote::txout_to_key &out = boost::get<cryptonote::txout_to_key>(tx.vout[i].target);
7238 // if this output is back to this wallet, we can calculate its key image already
7239 if (!is_out_to_acc_precomp(m_subaddresses, out.key, derivation, additional_derivations, i, hwdev))
7240 continue;
7242 cryptonote::keypair in_ephemeral;
7243 if (generate_key_image_helper(keys, m_subaddresses, out.key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev))
7244 signed_txes.tx_key_images[out.key] = ki;
7245 else
7246 MERROR("Failed to calculate key image");
7247 }
7248 }
7249
7250 // add key images
7251 signed_txes.key_images.resize(m_transfers.size());
7252 for (size_t i = 0; i < m_transfers.size(); ++i)
7253 {
7254 if (!m_transfers[i].m_key_image_known || m_transfers[i].m_key_image_partial)
7255 LOG_PRINT_L0("WARNING: key image not known in signing wallet at index " << i);
7256 signed_txes.key_images[i] = m_transfers[i].m_key_image;
7257 }
7258
7259 return true;
7260}
@ TRANSACTION_PARSE
Definition device.hpp:102
#define CURRENT_HARDFORK_VERSION
bool construct_tx_and_get_tx_key(const account_keys &sender_account_keys, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, std::vector< tx_source_entry > &sources, std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr, const std::vector< uint8_t > &extra, transaction &tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, const uint32_t account_major_offset, const cryptonote::network_type nettype)
boost::optional< subaddress_receive_info > is_out_to_acc_precomp(const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, const crypto::public_key &out_key, const crypto::key_derivation &derivation, const std::vector< crypto::key_derivation > &additional_derivations, size_t output_index, hw::device &hwdev)
hw::device & get_device() const
Definition account.cpp:59
std::vector< size_t > selected_transfers
Definition wallet2.h:470
std::vector< cryptonote::tx_destination_entry > dests
Definition wallet2.h:474
std::vector< cryptonote::tx_destination_entry > dests
Definition wallet2.h:430
cryptonote::tx_destination_entry change_dts
Definition wallet2.h:423
Here is the call graph for this function:

◆ sign_tx_dump_to_str()

std::string tools::wallet2::sign_tx_dump_to_str ( unsigned_tx_set & exported_txs,
std::vector< wallet2::pending_tx > & ptx,
signed_tx_set & signed_txes )

Definition at line 7295 of file wallet2.cpp.

7296{
7297 // sign the transactions
7298 bool r = sign_tx(exported_txs, ptx, signed_txes);
7299 if (!r)
7300 {
7301 LOG_PRINT_L0("Failed to sign unsigned_tx_set");
7302 return std::string();
7303 }
7304
7305 // save as binary
7306 std::ostringstream oss;
7307 boost::archive::portable_binary_oarchive ar(oss);
7308 try
7309 {
7310 ar << signed_txes;
7311 }
7312 catch(...)
7313 {
7314 return std::string();
7315 }
7316 LOG_PRINT_L3("Saving signed tx data (with encryption): " << oss.str());
7317 std::string ciphertext = encrypt_with_view_secret_key(oss.str());
7318 return std::string(SIGNED_TX_PREFIX) + ciphertext;
7319}
bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector< wallet2::pending_tx > &ptx, std::function< bool(const unsigned_tx_set &)> accept_func=NULL, bool export_raw=false)
#define LOG_PRINT_L3(x)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ stop()

void tools::wallet2::stop ( )
inline

Definition at line 760 of file wallet2.h.

760{ m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); }

◆ store()

void tools::wallet2::store ( )

Definition at line 6032 of file wallet2.cpp.

6033{
6034 if (!m_wallet_file.empty())
6035 store_to("", epee::wipeable_string());
6036}
void store_to(const std::string &path, const epee::wipeable_string &password)
store_to Stores wallet to another file(s), deleting old ones
Definition wallet2.cpp:6038
Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_to()

void tools::wallet2::store_to ( const std::string & path,
const epee::wipeable_string & password )

store_to Stores wallet to another file(s), deleting old ones

Parameters
pathPath to the wallet file (keys and address filenames will be generated based on this filename)
passwordPassword to protect new wallet (TODO: probably better save the password in the wallet object?)

Definition at line 6038 of file wallet2.cpp.

6039{
6040 trim_hashchain();
6041
6042 // if file is the same, we do:
6043 // 1. save wallet to the *.new file
6044 // 2. remove old wallet file
6045 // 3. rename *.new to wallet_name
6046
6047 // handle if we want just store wallet state to current files (ex store() replacement);
6048 bool same_file = true;
6049 if (!path.empty())
6050 {
6051 std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string();
6052 size_t pos = canonical_path.find(path);
6053 same_file = pos != std::string::npos;
6054 }
6055
6056
6057 if (!same_file)
6058 {
6059 // check if we want to store to directory which doesn't exists yet
6060 boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
6061
6062 // if path is not exists, try to create it
6063 if (!parent_path.empty() && !boost::filesystem::exists(parent_path))
6064 {
6065 boost::system::error_code ec;
6066 if (!boost::filesystem::create_directories(parent_path, ec))
6067 {
6068 throw std::logic_error(ec.message());
6069 }
6070 }
6071 }
6072 // preparing wallet data
6073 std::stringstream oss;
6074 boost::archive::portable_binary_oarchive ar(oss);
6075 ar << *this;
6076
6077 wallet2::cache_file_data cache_file_data = boost::value_initialized<wallet2::cache_file_data>();
6078 cache_file_data.cache_data = oss.str();
6079 std::string cipher;
6080 cipher.resize(cache_file_data.cache_data.size());
6082 crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cipher[0]);
6083 cache_file_data.cache_data = cipher;
6084
6085 const std::string new_file = same_file ? m_wallet_file + ".new" : path;
6086 const std::string old_file = m_wallet_file;
6087 const std::string old_keys_file = m_keys_file;
6088 const std::string old_address_file = m_wallet_file + ".address.txt";
6089 const std::string old_mms_file = m_mms_file;
6090
6091 // save keys to the new file
6092 // if we here, main wallet file is saved and we only need to save keys and address files
6093 if (!same_file) {
6094 prepare_file_names(path);
6095 bool r = store_keys(m_keys_file, password, false);
6097 if (boost::filesystem::exists(old_address_file))
6098 {
6099 // save address to the new file
6100 const std::string address_file = m_wallet_file + ".address.txt";
6101 r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_nettype));
6103 }
6104 // remove old wallet file
6105 r = boost::filesystem::remove(old_file);
6106 if (!r) {
6107 LOG_ERROR("error removing file: " << old_file);
6108 }
6109 // remove old keys file
6110 r = boost::filesystem::remove(old_keys_file);
6111 if (!r) {
6112 LOG_ERROR("error removing file: " << old_keys_file);
6113 }
6114 // remove old address file
6115 r = boost::filesystem::remove(old_address_file);
6116 if (!r) {
6117 LOG_ERROR("error removing file: " << old_address_file);
6118 }
6119 // remove old message store file
6120 if (boost::filesystem::exists(old_mms_file))
6121 {
6122 r = boost::filesystem::remove(old_mms_file);
6123 if (!r) {
6124 LOG_ERROR("error removing file: " << old_mms_file);
6125 }
6126 }
6127 } else {
6128 // save to new file
6129#ifdef WIN32
6130 // On Windows avoid using std::ofstream which does not work with UTF-8 filenames
6131 // The price to pay is temporary higher memory consumption for string stream + binary archive
6132 std::ostringstream oss;
6133 binary_archive<true> oar(oss);
6134 bool success = ::serialization::serialize(oar, cache_file_data);
6135 if (success) {
6136 success = epee::file_io_utils::save_string_to_file(new_file, oss.str());
6137 }
6139#else
6140 std::ofstream ostr;
6141 ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
6142 binary_archive<true> oar(ostr);
6143 bool success = ::serialization::serialize(oar, cache_file_data);
6144 ostr.close();
6145 THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
6146#endif
6147
6148 // here we have "*.new" file, we need to rename it to be without ".new"
6149 std::error_code e = tools::replace_file(new_file, m_wallet_file);
6151 }
6152
6153 if (m_message_store.get_active())
6154 {
6155 // While the "m_message_store" object of course always exist, a file for the message
6156 // store should only exist if the MMS is really active
6157 m_message_store.write_to_file(get_multisig_wallet_state(), m_mms_file);
6158 }
6159
6160}
std::string path() const
Definition wallet2.cpp:6027
bool serialize(Archive &ar, T &v)
std::error_code replace_file(const std::string &old_name, const std::string &new_name)
std::rename wrapper for nix and something strange for windows.
Definition util.cpp:648
Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_tx_info() [1/2]

bool tools::wallet2::store_tx_info ( ) const
inline

Definition at line 1069 of file wallet2.h.

1069{ return m_store_tx_info; }
Here is the caller graph for this function:

◆ store_tx_info() [2/2]

void tools::wallet2::store_tx_info ( bool store)
inline

Definition at line 1070 of file wallet2.h.

1070{ m_store_tx_info = store; }
Here is the call graph for this function:

◆ synced_to_v10()

bool tools::wallet2::synced_to_v10 ( ) const
inline

Definition at line 899 of file wallet2.h.

Here is the call graph for this function:

◆ thaw() [1/2]

void tools::wallet2::thaw ( const crypto::key_image & ki)

Definition at line 1610 of file wallet2.cpp.

1611{
1613}
void thaw(size_t idx)
Definition wallet2.cpp:1591
Here is the call graph for this function:

◆ thaw() [2/2]

void tools::wallet2::thaw ( size_t idx)

Definition at line 1591 of file wallet2.cpp.

1592{
1593 CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
1594 transfer_details &td = m_transfers[idx];
1595 td.m_frozen = false;
1596}
Here is the caller graph for this function:

◆ tr()

const char * tools::wallet2::tr ( const char * str)
static

Definition at line 994 of file wallet2.cpp.

994{ return i18n_translate(str, "tools::wallet2"); }
const char * i18n_translate(const char *s, const std::string &context)
Definition i18n.cpp:323
Here is the call graph for this function:

◆ track_uses() [1/2]

bool tools::wallet2::track_uses ( ) const
inline

Definition at line 1105 of file wallet2.h.

1105{ return m_track_uses; }

◆ track_uses() [2/2]

void tools::wallet2::track_uses ( bool value)
inline

Definition at line 1106 of file wallet2.h.

1106{ m_track_uses = value; }

◆ transfer_selected()

template<typename T>
void tools::wallet2::transfer_selected ( const std::vector< cryptonote::tx_destination_entry > & dsts,
const std::vector< size_t > & selected_transfers,
size_t fake_outputs_count,
std::vector< std::vector< tools::wallet2::get_outs_entry > > & outs,
uint64_t unlock_time,
uint64_t fee,
const std::vector< uint8_t > & extra,
T destination_split_strategy,
const tx_dust_policy & dust_policy,
cryptonote::transaction & tx,
pending_tx & ptx )

Definition at line 8952 of file wallet2.cpp.

8955{
8956 using namespace cryptonote;
8957 // throw if attempting a transaction with no destinations
8958 THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
8959
8960 THROW_WALLET_EXCEPTION_IF(m_multisig, error::wallet_internal_error, "Multisig wallets cannot spend non rct outputs");
8961
8962 uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit();
8963 uint64_t needed_etn = fee;
8964 LOG_PRINT_L2("transfer: starting with fee " << print_etn (needed_etn));
8965
8966 // calculate total amount being sent to all destinations
8967 // throw if total amount overflows uint64_t
8968 for(auto& dt: dsts)
8969 {
8970 THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination);
8971 needed_etn += dt.amount;
8972 LOG_PRINT_L2("transfer: adding " << print_etn(dt.amount) << ", for a total of " << print_etn (needed_etn));
8973 THROW_WALLET_EXCEPTION_IF(needed_etn < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype);
8974 }
8975
8976 uint64_t found_etn = 0;
8977 for(size_t idx: selected_transfers)
8978 {
8979 found_etn += m_transfers[idx].amount();
8980 }
8981
8982 LOG_PRINT_L2("wanted " << print_etn(needed_etn) << ", found " << print_etn(found_etn) << ", fee " << print_etn(fee));
8983 THROW_WALLET_EXCEPTION_IF(found_etn < needed_etn, error::not_enough_unlocked_etn, found_etn, needed_etn - fee, fee);
8984
8985 uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
8986 for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
8987 THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts");
8988
8989 if (outs.empty())
8990 get_outs(outs, selected_transfers, fake_outputs_count, tx.version); // may throw
8991
8992 //prepare inputs
8993 LOG_PRINT_L2("preparing outputs");
8994 typedef cryptonote::tx_source_entry::output_entry tx_output_entry;
8995 size_t i = 0, out_index = 0;
8996 std::vector<cryptonote::tx_source_entry> sources;
8997 for(size_t idx: selected_transfers)
8998 {
8999 sources.resize(sources.size()+1);
9000 cryptonote::tx_source_entry& src = sources.back();
9001 const transfer_details& td = m_transfers[idx];
9002 src.amount = td.amount();
9003 src.rct = td.is_rct();
9004 if(tx.version < 3) {
9005 //paste keys (fake and real)
9006 // adding pairs of global index & stealth address to our vector of source outs (needed forold ins only)
9007 for (size_t n = 0; n < fake_outputs_count + 1; ++n) {
9008 tx_output_entry oe;
9009 oe.first = std::get<0>(outs[out_index][n]);
9010 oe.second.dest = rct::pk2rct(std::get<1>(outs[out_index][n]));
9011 oe.second.mask = std::get<2>(outs[out_index][n]);
9012
9013 src.outputs.push_back(oe);
9014 ++i;
9015 }
9016
9017 //paste real transaction to the random index
9018 auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry &a) {
9019 return a.first == td.m_global_output_index;
9020 });
9021 THROW_WALLET_EXCEPTION_IF(it_to_replace == src.outputs.end(), error::wallet_internal_error,
9022 "real output not found");
9023
9024 tx_output_entry real_oe;
9025 real_oe.first = td.m_global_output_index;
9026 real_oe.second.dest = rct::pk2rct(
9027 boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
9028 real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
9029 *it_to_replace = real_oe;
9030 src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
9032 src.real_output = it_to_replace - src.outputs.begin();
9033 src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()});
9034 }
9035 src.real_output_in_tx_index = td.m_internal_output_index; // these two are all we really need for v3 sources
9036 src.tx_hash = td.m_txid;
9037 src.subaddr_index = td.m_subaddr_index;
9039 ++out_index;
9040 }
9041 LOG_PRINT_L2("outputs prepared");
9042
9043 cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
9044 if (needed_etn < found_etn)
9045 {
9046 // send change to the first input's address for v3+ tx
9047 uint32_t change_subaddress_minor = tx.version > 2 ? sources.front().subaddr_index.minor : 0;
9048 change_dts.addr = get_subaddress({subaddr_account, change_subaddress_minor});
9049 change_dts.is_subaddress = (subaddr_account != 0 || change_subaddress_minor != 0);
9050 change_dts.amount = found_etn - needed_etn;
9051 }
9052
9053 std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts;
9054 uint64_t dust = 0;
9055 destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts);
9056 for(auto& d: dust_dsts) {
9057 THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " +
9058 std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold));
9059 }
9060 for(auto& d: dust_dsts) {
9061 if (!dust_policy.add_to_fee)
9062 splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust, d.is_subaddress));
9063 dust += d.amount;
9064 }
9065
9066 crypto::secret_key tx_key;
9067 std::vector<crypto::secret_key> additional_tx_keys;
9068 rct::multisig_out msout;
9069
9070 LOG_PRINT_L2("constructing tx");
9071 bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, {}, m_multisig ? &msout : NULL, m_account_major_offset, this->m_nettype);
9072 LOG_PRINT_L2("constructed tx, r="<<r);
9073 THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype);
9074 THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
9075
9076 std::string key_images;
9077 bool are_ins_correct_type = tx.version >= 3 ?
9078 std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
9079 {
9080 CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key_public, in, false);
9081 return true;
9082 })
9083 :
9084 std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
9085 {
9086 CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false);
9087 key_images += boost::to_string(in.k_image) + " ";
9088 return true;
9089 });
9090
9091 THROW_WALLET_EXCEPTION_IF(!are_ins_correct_type, error::unexpected_txin_type, tx);
9092
9093
9094 bool dust_sent_elsewhere = (dust_policy.addr_for_dust.m_view_public_key != change_dts.addr.m_view_public_key
9095 || dust_policy.addr_for_dust.m_spend_public_key != change_dts.addr.m_spend_public_key);
9096
9097 if (dust_policy.add_to_fee || dust_sent_elsewhere) change_dts.amount -= dust;
9098
9099 ptx.key_images = key_images;
9100 ptx.fee = (dust_policy.add_to_fee ? fee+dust : fee);
9101 ptx.dust = ((dust_policy.add_to_fee || dust_sent_elsewhere) ? dust : 0);
9102 ptx.dust_added_to_fee = dust_policy.add_to_fee;
9103 ptx.tx = tx;
9104 ptx.change_dts = change_dts;
9105 ptx.selected_transfers = selected_transfers;
9106 ptx.tx_key = tx_key;
9107 ptx.additional_tx_keys = additional_tx_keys;
9108 ptx.dests = dsts;
9109 ptx.construction_data.sources = sources;
9110 ptx.construction_data.change_dts = change_dts;
9111 ptx.construction_data.splitted_dsts = splitted_dsts;
9112 ptx.construction_data.selected_transfers = selected_transfers;
9113 ptx.construction_data.extra = tx.extra;
9114 ptx.construction_data.unlock_time = unlock_time;
9115 ptx.construction_data.use_rct = false;
9116 ptx.construction_data.rct_config = { rct::RangeProofBorromean, 0 };
9117 ptx.construction_data.dests = dsts;
9118 // record which subaddress indices are being used as inputs
9119 ptx.construction_data.subaddr_account = subaddr_account;
9120 ptx.construction_data.subaddr_indices.clear();
9121 for (size_t idx: selected_transfers)
9122 ptx.construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor);
9123 LOG_PRINT_L2("transfer_selected done");
9124}
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val)
int bool
Definition hash.h:37
void print_source_entry(const cryptonote::tx_source_entry &src)
Definition wallet2.h:2137
bool is_subaddress
uint64_t amount
std::vector< crypto::public_key > real_out_additional_tx_keys
crypto::public_key real_out_tx_key
uint64_t amount
rct::multisig_kLRki multisig_kLRki
bool rct
size_t real_output
crypto::hash tx_hash
subaddress_index subaddr_index
std::vector< output_entry > outputs
std::pair< uint64_t, rct::ctkey > output_entry
size_t real_output_in_tx_index
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unblackball_output()

bool tools::wallet2::unblackball_output ( const std::pair< uint64_t, uint64_t > & output)

Definition at line 8198 of file wallet2.cpp.

8199{
8200 if (!m_ringdb)
8201 return false;
8202 try { return m_ringdb->unblackball(output); }
8203 catch (const std::exception &e) { return false; }
8204}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unlock_keys_file()

bool tools::wallet2::unlock_keys_file ( )

Definition at line 8225 of file wallet2.cpp.

8226{
8227 if (!m_keys_file_locker)
8228 {
8229 MDEBUG(m_keys_file << " is already unlocked.");
8230 return false;
8231 }
8232 m_keys_file_locker.reset();
8233 return true;
8234}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unlocked_balance()

uint64_t tools::wallet2::unlocked_balance ( uint32_t subaddr_index_major,
bool public_blockchain,
uint64_t * blocks_to_unlock = NULL ) const

Definition at line 6172 of file wallet2.cpp.

6173{
6174 uint64_t amount = 0;
6175 if (blocks_to_unlock)
6176 *blocks_to_unlock = 0;
6177 if(m_light_wallet)
6178 return m_light_wallet_balance;
6179 for (const auto& i : unlocked_balance_per_subaddress(index_major, public_blockchain))
6180 {
6181 amount += i.second.first;
6182 if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
6183 *blocks_to_unlock = i.second.second;
6184 }
6185 return amount;
6186}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unlocked_balance_all()

uint64_t tools::wallet2::unlocked_balance_all ( bool public_blockchain,
uint64_t * blocks_to_unlock = NULL ) const

Definition at line 6300 of file wallet2.cpp.

6301{
6302 uint64_t r = 0;
6303 if (blocks_to_unlock)
6304 *blocks_to_unlock = 0;
6305 for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
6306 {
6307 uint64_t local_blocks_to_unlock;
6308 r += unlocked_balance(index_major, public_blockchain ,blocks_to_unlock ? &local_blocks_to_unlock : NULL);
6309 if (blocks_to_unlock)
6310 *blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
6311 }
6312 return r;
6313}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unlocked_balance_per_subaddress()

std::map< uint32_t, std::pair< uint64_t, uint64_t > > tools::wallet2::unlocked_balance_per_subaddress ( uint32_t subaddr_index_major,
bool public_blockchain = false ) const

Definition at line 6249 of file wallet2.cpp.

6250{
6251 std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr; //map of subaddr minor index : <amount,unlock t>
6252 const uint64_t blockchain_height = get_blockchain_current_height();
6253 //Figure out amount & blocks_to_unlock for the major subaddress index for each transfer
6254 for(const transfer_details& td: m_transfers)
6255 {
6256 if((public_blockchain && td.m_tx.version == 1) || (!public_blockchain && td.m_tx.version > 1))
6257 continue;
6258
6259 if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
6260 {
6261 uint64_t amount = 0, blocks_to_unlock = 0;
6262 if (is_transfer_unlocked(td))
6263 {
6264 amount = td.amount();
6265 blocks_to_unlock = 0;
6266 }
6267 else
6268 {
6269
6270 uint64_t v8height = m_nettype == TESTNET ? 446674 : 589169;
6271 uint16_t UNLOCK_WINDOW = td.m_block_height > v8height ? ETN_DEFAULT_TX_SPENDABLE_AGE_V8 : CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
6272 uint64_t unlock_height = td.m_block_height + std::max<uint64_t>(UNLOCK_WINDOW, CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);
6273 if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > unlock_height)
6274 unlock_height = td.m_tx.unlock_time;
6275 blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 0;
6276 amount = 0;
6277 }
6278 auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
6279 // if we don't have this subaddress index (key) in our map, create a new entry, otherwise just add a new pair
6280 if (found == amount_per_subaddr.end())
6281 amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, blocks_to_unlock);
6282 else
6283 {
6284 found->second.first += amount;
6285 found->second.second = std::max(found->second.second, blocks_to_unlock);
6286 }
6287 }
6288 }
6289 return amount_per_subaddr;
6290}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unset_ring() [1/2]

bool tools::wallet2::unset_ring ( const crypto::hash & txid)

Definition at line 8081 of file wallet2.cpp.

8082{
8083 if (!m_ringdb)
8084 return false;
8085
8088 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
8089 req.decode_as_json = false;
8090 req.prune = true;
8091 m_daemon_rpc_mutex.lock();
8092 bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
8093 m_daemon_rpc_mutex.unlock();
8094 THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to get transaction from daemon");
8095 if (res.txs.empty())
8096 return false;
8097 THROW_WALLET_EXCEPTION_IF(res.txs.size(), error::wallet_internal_error, "Failed to get transaction from daemon");
8098
8099 cryptonote::transaction tx;
8100 crypto::hash tx_hash;
8101 if (!get_pruned_tx(res.txs.front(), tx, tx_hash))
8102 return false;
8103 THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
8104
8105 try { return m_ringdb->remove_rings(get_ringdb_key(), tx); }
8106 catch (const std::exception &e) { return false; }
8107}
Here is the call graph for this function:

◆ unset_ring() [2/2]

bool tools::wallet2::unset_ring ( const std::vector< crypto::key_image > & key_images)

Definition at line 8072 of file wallet2.cpp.

8073{
8074 if (!m_ringdb)
8075 return false;
8076
8077 try { return m_ringdb->remove_rings(get_ringdb_key(), key_images); }
8078 catch (const std::exception &e) { return false; }
8079}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_pool_state()

void tools::wallet2::update_pool_state ( bool refreshed = false)

Definition at line 3164 of file wallet2.cpp.

3165{
3166 MTRACE("update_pool_state start");
3167
3168 auto keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this]() {
3169 if (m_encrypt_keys_after_refresh)
3170 {
3171 encrypt_keys(*m_encrypt_keys_after_refresh);
3172 m_encrypt_keys_after_refresh = boost::none;
3173 }
3174 });
3175
3176 // get the pool state
3179 m_daemon_rpc_mutex.lock();
3180 bool r = invoke_http_json("/get_transaction_pool_hashes.bin", req, res, rpc_timeout);
3181 m_daemon_rpc_mutex.unlock();
3182 THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_transaction_pool_hashes.bin");
3183 THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_transaction_pool_hashes.bin");
3184 THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
3185 MTRACE("update_pool_state got pool");
3186
3187 // remove any pending tx that's not in the pool
3188 std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin();
3189 while (it != m_unconfirmed_txs.end())
3190 {
3191 const crypto::hash &txid = it->first;
3192 bool found = false;
3193 for (const auto &it2: res.tx_hashes)
3194 {
3195 if (it2 == txid)
3196 {
3197 found = true;
3198 break;
3199 }
3200 }
3201 auto pit = it++;
3202 if (!found)
3203 {
3204 // we want to avoid a false positive when we ask for the pool just after
3205 // a tx is removed from the pool due to being found in a new block, but
3206 // just before the block is visible by refresh. So we keep a boolean, so
3207 // that the first time we don't see the tx, we set that boolean, and only
3208 // delete it the second time it is checked (but only when refreshed, so
3209 // we're sure we've seen the blockchain state first)
3210 if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending)
3211 {
3212 LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as not in pool");
3214 }
3215 else if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending_not_in_pool && refreshed)
3216 {
3217 LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as failed");
3219
3220 // the inputs aren't spent anymore, since the tx failed
3221 remove_rings(pit->second.m_tx);
3222 for (size_t vini = 0; vini < pit->second.m_tx.vin.size(); ++vini)
3223 {
3224 if (pit->second.m_tx.vin[vini].type() == typeid(txin_to_key))
3225 {
3226 txin_to_key &tx_in_to_key = boost::get<txin_to_key>(pit->second.m_tx.vin[vini]);
3227 for (size_t i = 0; i < m_transfers.size(); ++i)
3228 {
3229 const transfer_details &td = m_transfers[i];
3230 if (td.m_key_image == tx_in_to_key.k_image)
3231 {
3232 LOG_PRINT_L1("Resetting spent status for output " << vini << ": " << td.m_key_image);
3233 set_unspent(i);
3234 break;
3235 }
3236 }
3237 }
3238 }
3239 }
3240 }
3241 }
3242 MTRACE("update_pool_state done first loop");
3243
3244 // remove pool txes to us that aren't in the pool anymore
3245 // but only if we just refreshed, so that the tx can go in
3246 // the in transfers list instead (or nowhere if it just
3247 // disappeared without being mined)
3248 if (refreshed)
3249 remove_obsolete_pool_txs(res.tx_hashes);
3250
3251 MTRACE("update_pool_state done second loop");
3252
3253 // gather txids of new pool txes to us
3254 std::vector<std::pair<crypto::hash, bool>> txids;
3255 for (const auto &txid: res.tx_hashes)
3256 {
3257 bool txid_found_in_up = false;
3258 for (const auto &up: m_unconfirmed_payments)
3259 {
3260 if (up.second.m_pd.m_tx_hash == txid)
3261 {
3262 txid_found_in_up = true;
3263 break;
3264 }
3265 }
3266 if (m_scanned_pool_txs[0].find(txid) != m_scanned_pool_txs[0].end() || m_scanned_pool_txs[1].find(txid) != m_scanned_pool_txs[1].end())
3267 {
3268 // if it's for us, we want to keep track of whether we saw a double spend, so don't bail out
3269 if (!txid_found_in_up)
3270 {
3271 LOG_PRINT_L2("Already seen " << txid << ", and not for us, skipped");
3272 continue;
3273 }
3274 }
3275 if (!txid_found_in_up)
3276 {
3277 LOG_PRINT_L1("Found new pool tx: " << txid);
3278 bool found = false;
3279 for (const auto &i: m_unconfirmed_txs)
3280 {
3281 if (i.first == txid)
3282 {
3283 found = true;
3284 // if this is a payment to yourself at a different subaddress account, don't skip it
3285 // so that you can see the incoming pool tx with 'show_transfers' on that receiving subaddress account
3286 const unconfirmed_transfer_details& utd = i.second;
3287 for (const auto& dst : utd.m_dests)
3288 {
3289 auto subaddr_index = m_subaddresses.find(dst.addr.m_spend_public_key);
3290 if (subaddr_index != m_subaddresses.end() && subaddr_index->second.major != utd.m_subaddr_account)
3291 {
3292 found = false;
3293 break;
3294 }
3295 }
3296 break;
3297 }
3298 }
3299 if (!found)
3300 {
3301 // not one of those we sent ourselves
3302 txids.push_back({txid, false});
3303 }
3304 else
3305 {
3306 LOG_PRINT_L1("We sent that one");
3307 }
3308 }
3309 else
3310 {
3311 LOG_PRINT_L1("Already saw that one, it's for us");
3312 txids.push_back({txid, true});
3313 }
3314 }
3315
3316 // get those txes
3317 if (!txids.empty())
3318 {
3321 for (const auto &p: txids)
3322 req.txs_hashes.push_back(epee::string_tools::pod_to_hex(p.first));
3323 MDEBUG("asking for " << txids.size() << " transactions");
3324 req.decode_as_json = false;
3325 req.prune = true;
3326 m_daemon_rpc_mutex.lock();
3327 bool r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
3328 m_daemon_rpc_mutex.unlock();
3329 MDEBUG("Got " << r << " and " << res.status);
3330 if (r && res.status == CORE_RPC_STATUS_OK)
3331 {
3332 if (res.txs.size() == txids.size())
3333 {
3334 for (const auto &tx_entry: res.txs)
3335 {
3336 if (tx_entry.in_pool)
3337 {
3338 cryptonote::transaction tx;
3340 crypto::hash tx_hash;
3341
3342 if (get_pruned_tx(tx_entry, tx, tx_hash))
3343 {
3344 const std::vector<std::pair<crypto::hash, bool>>::const_iterator i = std::find_if(txids.begin(), txids.end(),
3345 [tx_hash](const std::pair<crypto::hash, bool> &e) { return e.first == tx_hash; });
3346 if (i != txids.end())
3347 {
3348 process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, time(NULL), false, true, tx_entry.double_spend_seen, false, {});
3349 m_scanned_pool_txs[0].insert(tx_hash);
3350 if (m_scanned_pool_txs[0].size() > 5000)
3351 {
3352 std::swap(m_scanned_pool_txs[0], m_scanned_pool_txs[1]);
3353 m_scanned_pool_txs[0].clear();
3354 }
3355 }
3356 else
3357 {
3358 MERROR("Got txid " << tx_hash << " which we did not ask for");
3359 }
3360 }
3361 else
3362 {
3363 LOG_PRINT_L0("Failed to parse transaction from daemon");
3364 }
3365 }
3366 else
3367 {
3368 LOG_PRINT_L1("Transaction from daemon was in pool, but is no more");
3369 }
3370 }
3371 }
3372 else
3373 {
3374 LOG_PRINT_L0("Expected " << txids.size() << " tx(es), got " << res.txs.size());
3375 }
3376 }
3377 else
3378 {
3379 LOG_PRINT_L0("Error calling gettransactions daemon RPC: r " << r << ", status " << get_rpc_status(res.status));
3380 }
3381 }
3382 MTRACE("update_pool_state end");
3383}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ use_fork_rules()

bool tools::wallet2::use_fork_rules ( uint8_t version,
int64_t early_blocks = 0 ) const

Definition at line 10720 of file wallet2.cpp.

10721{
10722 // TODO: How to get fork rule info from light wallet node?
10723 if(m_light_wallet)
10724 return true;
10725 uint64_t height, earliest_height;
10726 boost::optional<std::string> result = m_node_rpc_proxy.get_height(height);
10727 throw_on_rpc_response_error(result, "get_info");
10728 result = m_node_rpc_proxy.get_earliest_height(version, earliest_height);
10729 throw_on_rpc_response_error(result, "get_hard_fork_info");
10730
10731 bool close_enough = (int64_t)height >= (int64_t)earliest_height - early_blocks && earliest_height != std::numeric_limits<uint64_t>::max() && version <= CURRENT_HARDFORK_VERSION; // start using the rules that many blocks beforehand
10732 if (close_enough)
10733 LOG_PRINT_L2("Using v" << (unsigned)version << " rules");
10734 else
10735 LOG_PRINT_L2("Not using v" << (unsigned)version << " rules");
10736 return close_enough;
10737}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify()

bool tools::wallet2::verify ( const std::string & data,
const cryptonote::account_public_address & address,
const std::string & signature ) const

Definition at line 12086 of file wallet2.cpp.

12087{
12088 const size_t header_len = strlen("SigV1");
12089 if (signature.size() < header_len || signature.substr(0, header_len) != "SigV1") {
12090 LOG_PRINT_L0("Signature header check error");
12091 return false;
12092 }
12094 crypto::cn_fast_hash(data.data(), data.size(), hash);
12095 std::string decoded;
12096 if (!tools::base58::decode(signature.substr(header_len), decoded)) {
12097 LOG_PRINT_L0("Signature decoding error");
12098 return false;
12099 }
12101 if (sizeof(s) != decoded.size()) {
12102 LOG_PRINT_L0("Signature decoding error");
12103 return false;
12104 }
12105 memcpy(&s, decoded.data(), sizeof(s));
12106 return crypto::check_signature(hash, address.m_spend_public_key, s);
12107}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify_extra_multisig_info()

bool tools::wallet2::verify_extra_multisig_info ( const std::string & data,
std::unordered_set< crypto::public_key > & pkeys,
crypto::public_key & signer )
static

Verifies and extracts keys from a packaged multisig information string

Definition at line 5586 of file wallet2.cpp.

5587{
5588 if (data.size() < MULTISIG_EXTRA_INFO_MAGIC.size() || data.substr(0, MULTISIG_EXTRA_INFO_MAGIC.size()) != MULTISIG_EXTRA_INFO_MAGIC)
5589 {
5590 MERROR("Multisig info header check error");
5591 return false;
5592 }
5593 std::string decoded;
5594 if (!tools::base58::decode(data.substr(MULTISIG_EXTRA_INFO_MAGIC.size()), decoded))
5595 {
5596 MERROR("Multisig info decoding error");
5597 return false;
5598 }
5599 if (decoded.size() < sizeof(crypto::public_key) + sizeof(crypto::signature))
5600 {
5601 MERROR("Multisig info is corrupt");
5602 return false;
5603 }
5604 if ((decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) % sizeof(crypto::public_key))
5605 {
5606 MERROR("Multisig info is corrupt");
5607 return false;
5608 }
5609
5610 const size_t n_keys = (decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) / sizeof(crypto::public_key);
5611 size_t offset = 0;
5612 signer = *(const crypto::public_key*)(decoded.data() + offset);
5613 offset += sizeof(signer);
5614 const crypto::signature &signature = *(const crypto::signature*)(decoded.data() + offset + n_keys * sizeof(crypto::public_key));
5615
5617 crypto::cn_fast_hash(decoded.data(), decoded.size() - sizeof(signature), hash);
5618 if (!crypto::check_signature(hash, signer, signature))
5619 {
5620 MERROR("Multisig info signature is invalid");
5621 return false;
5622 }
5623
5624 for (size_t n = 0; n < n_keys; ++n)
5625 {
5626 crypto::public_key mspk = *(const crypto::public_key*)(decoded.data() + offset);
5627 pkeys.insert(mspk);
5628 offset += sizeof(mspk);
5629 }
5630
5631 return true;
5632}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify_multisig_info()

bool tools::wallet2::verify_multisig_info ( const std::string & data,
crypto::secret_key & skey,
crypto::public_key & pkey )
static

Verifies and extracts keys from a packaged multisig information string

Definition at line 5548 of file wallet2.cpp.

5549{
5550 const size_t header_len = strlen("MultisigV1");
5551 if (data.size() < header_len || data.substr(0, header_len) != "MultisigV1")
5552 {
5553 MERROR("Multisig info header check error");
5554 return false;
5555 }
5556 std::string decoded;
5557 if (!tools::base58::decode(data.substr(header_len), decoded))
5558 {
5559 MERROR("Multisig info decoding error");
5560 return false;
5561 }
5562 if (decoded.size() != sizeof(crypto::secret_key) + sizeof(crypto::public_key) + sizeof(crypto::signature))
5563 {
5564 MERROR("Multisig info is corrupt");
5565 return false;
5566 }
5567
5568 size_t offset = 0;
5569 skey = *(const crypto::secret_key*)(decoded.data() + offset);
5570 offset += sizeof(skey);
5571 pkey = *(const crypto::public_key*)(decoded.data() + offset);
5572 offset += sizeof(pkey);
5573 const crypto::signature &signature = *(const crypto::signature*)(decoded.data() + offset);
5574
5576 crypto::cn_fast_hash(decoded.data(), decoded.size() - sizeof(signature), hash);
5578 {
5579 MERROR("Multisig info signature is invalid");
5580 return false;
5581 }
5582
5583 return true;
5584}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify_password() [1/2]

bool tools::wallet2::verify_password ( const epee::wipeable_string & password)

verifies given password is correct for default wallet keys file

verify password for default wallet keys file.

Parameters
passwordPassword to verify
Returns
true if password is correct

for verification only should not mutate state, unlike load_keys() can be used prior to rewriting wallet keys file, to ensure user has entered the correct password

Definition at line 4677 of file wallet2.cpp.

4678{
4679 // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
4681 bool r = verify_password(m_keys_file, password, m_account.get_device().device_protocol() == hw::device::PROTOCOL_COLD || m_watch_only || m_multisig, m_account.get_device(), m_kdf_rounds);
4683 return r;
4684}
static bool verify_password(const std::string &keys_file_name, const epee::wipeable_string &password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds)
verify password for specified wallet keys file.
Definition wallet2.cpp:4699
Here is the call graph for this function:

◆ verify_password() [2/2]

bool tools::wallet2::verify_password ( const std::string & keys_file_name,
const epee::wipeable_string & password,
bool no_spend_key,
hw::device & hwdev,
uint64_t kdf_rounds )
static

verify password for specified wallet keys file.

Parameters
keys_file_nameKeys file to verify password for
passwordPassword to verify
no_spend_keyIf set = only verify view keys, otherwise also spend keys
hwdevThe hardware device to use
Returns
true if password is correct

for verification only should not mutate state, unlike load_keys() can be used prior to rewriting wallet keys file, to ensure user has entered the correct password

Definition at line 4699 of file wallet2.cpp.

4700{
4701 rapidjson::Document json;
4702 wallet2::keys_file_data keys_file_data;
4703 std::string buf;
4704 bool encrypted_secret_keys = false;
4705 bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
4707
4708 // Decrypt the contents
4710 THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
4711 crypto::chacha_key key;
4712 crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
4713 std::string account_data;
4714 account_data.resize(keys_file_data.account_data.size());
4715 crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4716 if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject())
4717 crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4718
4719 // The contents should be JSON if the wallet follows the new format.
4720 if (json.Parse(account_data.c_str()).HasParseError())
4721 {
4722 // old format before JSON wallet key file format
4723 }
4724 else
4725 {
4726 account_data = std::string(json["key_data"].GetString(), json["key_data"].GetString() +
4727 json["key_data"].GetStringLength());
4728 GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, encrypted_secret_keys, uint32_t, Uint, false, false);
4729 encrypted_secret_keys = field_encrypted_secret_keys;
4730 }
4731
4732 cryptonote::account_base account_data_check;
4733
4734 r = epee::serialization::load_t_from_binary(account_data_check, account_data);
4735
4736 if (encrypted_secret_keys)
4737 account_data_check.decrypt_keys(key);
4738
4739 const cryptonote::account_keys& keys = account_data_check.get_keys();
4741 if(!no_spend_key)
4743 return r;
4744}
void decrypt_keys(const crypto::chacha_key &key)
Definition account.h:105
virtual bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key)=0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify_with_public_key()

bool tools::wallet2::verify_with_public_key ( const std::string & data,
const crypto::public_key & public_key,
const std::string & signature ) const

verify_with_public_key verifies message was signed with given public key

Parameters
datamessage
public_keypublic key to check signature
signaturesignature of the message
Returns
true if the signature is correct

Definition at line 12121 of file wallet2.cpp.

12122{
12123 if (signature.size() < MULTISIG_SIGNATURE_MAGIC.size() || signature.substr(0, MULTISIG_SIGNATURE_MAGIC.size()) != MULTISIG_SIGNATURE_MAGIC) {
12124 MERROR("Signature header check error");
12125 return false;
12126 }
12128 crypto::cn_fast_hash(data.data(), data.size(), hash);
12129 std::string decoded;
12130 if (!tools::base58::decode(signature.substr(MULTISIG_SIGNATURE_MAGIC.size()), decoded)) {
12131 MERROR("Signature decoding error");
12132 return false;
12133 }
12135 if (sizeof(s) != decoded.size()) {
12136 MERROR("Signature decoding error");
12137 return false;
12138 }
12139 memcpy(&s, decoded.data(), sizeof(s));
12141}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ wallet_exists()

void tools::wallet2::wallet_exists ( const std::string & file_path,
bool & keys_file_exists,
bool & wallet_file_exists )
static

Check if wallet keys and bin files exist.

Parameters
file_pathWallet file path
keys_file_existsWhether keys file exists
wallet_file_existsWhether bin file exists

Definition at line 5697 of file wallet2.cpp.

5698{
5699 std::string keys_file, wallet_file, mms_file;
5700 do_prepare_file_names(file_path, keys_file, wallet_file, mms_file);
5701
5702 boost::system::error_code ignore;
5703 keys_file_exists = boost::filesystem::exists(keys_file, ignore);
5704 wallet_file_exists = boost::filesystem::exists(wallet_file, ignore);
5705}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ wallet_valid_path_format()

bool tools::wallet2::wallet_valid_path_format ( const std::string & file_path)
static

Definition at line 5707 of file wallet2.cpp.

5708{
5709 return !file_path.empty();
5710}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ watch_only()

bool tools::wallet2::watch_only ( ) const
inline

Definition at line 825 of file wallet2.h.

825{ return m_watch_only; }

◆ write_watch_only_wallet()

void tools::wallet2::write_watch_only_wallet ( const std::string & wallet_name,
const epee::wipeable_string & password,
std::string & new_keys_filename )

Writes to a file named based on the normal wallet (doesn't generate key, assumes it's already there).

Parameters
wallet_nameBase name of wallet file
passwordPassword for wallet file
new_keys_filename[OUT] Name of new keys file

Definition at line 5686 of file wallet2.cpp.

5687{
5688 prepare_file_names(wallet_name);
5689 boost::system::error_code ignored_ec;
5690 new_keys_filename = m_wallet_file + "-watchonly.keys";
5691 bool watch_only_keys_file_exists = boost::filesystem::exists(new_keys_filename, ignored_ec);
5692 THROW_WALLET_EXCEPTION_IF(watch_only_keys_file_exists, error::file_save_error, new_keys_filename);
5693 bool r = store_keys(new_keys_filename, password, true);
5694 THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, new_keys_filename);
5695}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ::Serialization_portability_wallet_Test

friend class ::Serialization_portability_wallet_Test
friend

Definition at line 211 of file wallet2.h.

◆ ::wallet_accessor_test

friend class ::wallet_accessor_test
friend

Definition at line 212 of file wallet2.h.

◆ wallet_device_callback

friend class wallet_device_callback
friend

Definition at line 214 of file wallet2.h.

◆ wallet_keys_unlocker

friend class wallet_keys_unlocker
friend

Definition at line 213 of file wallet2.h.

Member Data Documentation

◆ ATTRIBUTE_DESCRIPTION

const char* const tools::wallet2::ATTRIBUTE_DESCRIPTION = "wallet2.description"

Definition at line 1309 of file wallet2.h.

◆ rpc_timeout

const std::chrono::seconds tools::wallet2::rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30)
staticconstexpr

Definition at line 216 of file wallet2.h.


The documentation for this class was generated from the following files:
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/wallet/wallet2.h
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/wallet/wallet2.cpp