Electroneum
tools::wallet2 Class Reference

#include <wallet2.h>

Classes

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

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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
std::string make_multisig (const epee::wipeable_string &password, const std::vector< std::string > &info, uint32_t threshold)
 Creates a multisig wallet. More...
 
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. More...
 
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. More...
 
bool finalize_multisig (const epee::wipeable_string &password, const std::vector< std::string > &info)
 Finalizes creation of a multisig wallet. More...
 
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. More...
 
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) More...
 
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) More...
 
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 More...
 
std::string path () const
 
bool verify_password (const epee::wipeable_string &password)
 verifies given password is correct for default wallet keys file More...
 
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. More...
 
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. More...
 
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. More...
 
void set_seed_language (const std::string &language)
 Sets the seed language. More...
 
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. More...
 
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_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. More...
 
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. More...
 
std::vector< address_book_rowget_address_book () const
 GUI Address book get/store. More...
 
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. More...
 
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. More...
 
void set_account_tag (const std::set< uint32_t > &account_indices, const std::string &tag)
 Set a tag to the given accounts. More...
 
void set_account_tag_description (const std::string &tag, const std::string &description)
 Set the label of the given tag. More...
 
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 More...
 
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 More...
 
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)
 

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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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 More...
 
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. More...
 
static std::string get_human_readable_timestamp (uint64_t ts)
 Check if wallet file path is valid format. More...
 
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 556 of file wallet2.h.

◆ payment_container

Definition at line 444 of file wallet2.h.

◆ transfer_container

Definition at line 443 of file wallet2.h.

Member Enumeration Documentation

◆ AskPasswordType

Enumerator
AskPasswordNever 
AskPasswordOnAction 
AskPasswordToDecrypt 

Definition at line 225 of file wallet2.h.

225  {
226  AskPasswordNever = 0,
229  };
@ AskPasswordToDecrypt
Definition: wallet2.h:228
@ AskPasswordOnAction
Definition: wallet2.h:227
@ AskPasswordNever
Definition: wallet2.h:226

◆ BackgroundMiningSetupType

Enumerator
BackgroundMiningMaybe 
BackgroundMiningYes 
BackgroundMiningNo 

Definition at line 231 of file wallet2.h.

231  {
234  BackgroundMiningNo = 2,
235  };
@ BackgroundMiningNo
Definition: wallet2.h:234
@ 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 1101 of file wallet2.cpp.

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

◆ ~wallet2()

tools::wallet2::~wallet2 ( )

Definition at line 1168 of file wallet2.cpp.

1169 {
1170 }

Member Function Documentation

◆ account_major_offset() [1/2]

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

Definition at line 805 of file wallet2.h.

805 {return m_account_major_offset;}

◆ account_major_offset() [2/2]

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

Definition at line 804 of file wallet2.h.

804 {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 3434 of file wallet2.cpp.

3435 {
3436  wallet2::address_book_row a;
3437  a.m_address = address;
3438  a.m_payment_id = payment_id;
3439  a.m_description = description;
3440  a.m_is_subaddress = is_subaddress;
3441 
3442  auto old_size = m_address_book.size();
3443  m_address_book.push_back(a);
3444  if(m_address_book.size() == old_size+1)
3445  return true;
3446  return false;
3447 }
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
const char * address
Definition: multisig.cpp:37

◆ add_checkpoint()

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

Definition at line 13546 of file wallet2.cpp.

13546  {
13547  m_checkpoints.add_checkpoint(height, hash);
13548 }
uint64_t height
Definition: blockchain.cpp:91
bool add_checkpoint(uint64_t height, const std::string &hash_str)
adds a checkpoint to the container
Definition: checkpoints.cpp:76
POD_CLASS hash
Definition: hash.h:50

◆ add_subaddress()

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

Definition at line 1469 of file wallet2.cpp.

1470 {
1471  THROW_WALLET_EXCEPTION_IF(index_major >= m_subaddress_labels.size(), error::account_index_outofbound);
1472  uint32_t index_minor = (uint32_t)get_num_subaddresses(index_major);
1473  expand_subaddresses({index_major, index_minor});
1474  m_subaddress_labels[index_major][index_minor] = label;
1475 }
void expand_subaddresses(const cryptonote::subaddress_index &index, const bool udpate_account_tags=true)
Definition: wallet2.cpp:1477
size_t get_num_subaddresses(uint32_t index_major) const
Definition: wallet2.h:796
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 1462 of file wallet2.cpp.

1463 {
1465  expand_subaddresses({index_major, 0}, update_account_tags);
1466  m_subaddress_labels[index_major][0] = label;
1467 }
size_t get_num_subaddress_accounts() const
Definition: wallet2.h:795
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 7653 of file wallet2.cpp.

7654 {
7655  const uint64_t min_ring_size = get_min_ring_size();
7656  if (mixin + 1 < min_ring_size)
7657  {
7658  MWARNING("Requested ring size " << (mixin + 1) << " too low, using " << min_ring_size);
7659  mixin = min_ring_size-1;
7660  }
7661  const uint64_t max_ring_size = get_max_ring_size();
7662  if (max_ring_size && mixin + 1 > max_ring_size)
7663  {
7664  MWARNING("Requested ring size " << (mixin + 1) << " too high, using " << max_ring_size);
7665  mixin = max_ring_size-1;
7666  }
7667  return mixin;
7668 }
uint64_t get_max_ring_size() const
Definition: wallet2.cpp:7644
uint64_t get_min_ring_size() const
Definition: wallet2.cpp:7629
#define MWARNING(x)
Definition: misc_log_ex.h:74
unsigned __int64 uint64_t
Definition: stdint.h:136

◆ adjust_priority()

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

Definition at line 7670 of file wallet2.cpp.

7671 {
7672  if (priority == 0 && m_default_priority == 0 && auto_low_priority())
7673  {
7674  try
7675  {
7676  // check if there's a backlog in the tx pool
7677  const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
7678  const uint64_t base_fee = get_base_fee();
7679  const uint64_t fee_multiplier = get_fee_multiplier(1);
7680  const double fee_level = fee_multiplier * base_fee * (use_per_byte_fee ? 1 : (12/(double)13 / (double)1024));
7681  const std::vector<std::pair<uint64_t, uint64_t>> blocks = estimate_backlog({std::make_pair(fee_level, fee_level)});
7682  if (blocks.size() != 1)
7683  {
7684  MERROR("Bad estimated backlog array size");
7685  return priority;
7686  }
7687  else if (blocks[0].first > 0)
7688  {
7689  MINFO("We don't use the low priority because there's a backlog in the tx pool.");
7690  return priority;
7691  }
7692 
7693  // get the current full reward zone
7694  uint64_t block_weight_limit = 0;
7695  const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
7696  throw_on_rpc_response_error(result, "get_info");
7697  const uint64_t full_reward_zone = block_weight_limit / 2;
7698 
7699  // get the last N block headers and sum the block sizes
7700  const size_t N = 10;
7701  if (m_blockchain.size() < N)
7702  {
7703  MERROR("The blockchain is too short");
7704  return priority;
7705  }
7708  m_daemon_rpc_mutex.lock();
7709  getbh_req.start_height = m_blockchain.size() - N;
7710  getbh_req.end_height = m_blockchain.size() - 1;
7711  bool r = invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, rpc_timeout);
7712  m_daemon_rpc_mutex.unlock();
7713  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange");
7714  THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange");
7715  THROW_WALLET_EXCEPTION_IF(getbh_res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, get_rpc_status(getbh_res.status));
7716  if (getbh_res.headers.size() != N)
7717  {
7718  MERROR("Bad blockheaders size");
7719  return priority;
7720  }
7721  size_t block_weight_sum = 0;
7722  for (const cryptonote::block_header_response &i : getbh_res.headers)
7723  {
7724  block_weight_sum += i.block_weight;
7725  }
7726 
7727  // estimate how 'full' the last N blocks are
7728  const size_t P = 100 * block_weight_sum / (N * full_reward_zone);
7729  MINFO((boost::format("The last %d blocks fill roughly %d%% of the full reward zone.") % N % P).str());
7730  if (P > 80)
7731  {
7732  MINFO("We don't use the low priority because recent blocks are quite full.");
7733  return priority;
7734  }
7735  MINFO("We'll use the low priority because probably it's safe to do so.");
7736  return 1;
7737  }
7738  catch (const std::exception &e)
7739  {
7740  MERROR(e.what());
7741  }
7742  }
7743  return priority;
7744 }
boost::optional< std::string > get_block_weight_limit(uint64_t &block_weight_limit) const
size_t size() const
Definition: wallet2.h:181
uint64_t get_base_fee() const
Definition: wallet2.cpp:7584
std::vector< std::pair< uint64_t, uint64_t > > estimate_backlog(const std::vector< std::pair< double, double >> &fee_levels)
Definition: wallet2.cpp:13269
uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm=-1) const
Definition: wallet2.cpp:7531
bool use_fork_rules(uint8_t version, int64_t early_blocks=0) const
Definition: wallet2.cpp:10510
bool auto_low_priority() const
Definition: wallet2.h:1085
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:1325
#define CORE_RPC_STATUS_OK
#define CORE_RPC_STATUS_BUSY
#define HF_VERSION_PER_BYTE_FEE
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
#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

◆ always_confirm_transfers() [1/2]

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

Definition at line 1057 of file wallet2.h.

1057 { return m_always_confirm_transfers; }

◆ always_confirm_transfers() [2/2]

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

Definition at line 1058 of file wallet2.h.

1058 { m_always_confirm_transfers = always; }

◆ ask_password() [1/2]

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

Definition at line 1071 of file wallet2.h.

1071 { return m_ask_password; }
Here is the caller graph for this function:

◆ ask_password() [2/2]

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

Definition at line 1072 of file wallet2.h.

1072 { m_ask_password = ask; }

◆ auto_low_priority() [1/2]

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

Definition at line 1085 of file wallet2.h.

1085 { return m_auto_low_priority; }

◆ auto_low_priority() [2/2]

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

Definition at line 1086 of file wallet2.h.

1086 { 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 1067 of file wallet2.h.

1067 { return m_auto_refresh; }

◆ auto_refresh() [2/2]

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

Definition at line 1068 of file wallet2.h.

1068 { m_auto_refresh = r; }

◆ balance()

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

Definition at line 6052 of file wallet2.cpp.

6053 {
6054  uint64_t amount = 0;
6055  if(m_light_wallet)
6056  return m_light_wallet_unlocked_balance;
6057  for (const auto& i : balance_per_subaddress(index_major, public_blockchain))
6058  amount += i.second;
6059  return amount;
6060 }
std::map< uint32_t, uint64_t > balance_per_subaddress(uint32_t subaddr_index_major, bool public_blockchain=false) const
Definition: wallet2.cpp:6078
Here is the caller graph for this function:

◆ balance_all()

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

Definition at line 6182 of file wallet2.cpp.

6183 {
6184  uint64_t r = 0;
6185  for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
6186  r += balance(index_major, public_blockchain);
6187  return r;
6188 }
uint64_t balance(uint32_t subaddr_index_major, bool public_blockchain) const
Definition: wallet2.cpp:6052

◆ 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 6078 of file wallet2.cpp.

6079 {
6080  std::map<uint32_t, uint64_t> amount_per_subaddr;
6081  for (const auto& td: m_transfers)
6082  {
6083  if((public_blockchain && td.m_tx.version == 1) || (!public_blockchain && td.m_tx.version > 1))
6084  continue;
6085 
6086  if (td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
6087  {
6088  auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
6089  if (found == amount_per_subaddr.end())
6090  amount_per_subaddr[td.m_subaddr_index.minor] = td.amount();
6091  else
6092  found->second += td.amount();
6093  }
6094  }
6095  for (const auto& utx: m_unconfirmed_txs) {
6096  if ((public_blockchain && utx.second.m_tx.version == 1) || (!public_blockchain && utx.second.m_tx.version > 1))
6097  continue;
6098 
6099  if (utx.second.m_state != wallet2::unconfirmed_transfer_details::failed) {
6100  //HANDLE LOOPBACK OUTS INCLUDING CHANGE
6101  if(utx.second.m_tx.version > 1){
6102  for (const cryptonote::tx_out &out : utx.second.m_tx.vout) {
6103  if (out.target.type() == typeid(txout_to_key_public)) {
6104  // check whether this out is to one of our subaddresses
6105  auto target = boost::get<cryptonote::txout_to_key_public>(out.target);
6106  auto subaddr_found = m_subaddresses.find(target.address.m_spend_public_key);
6107  // if this out is to us
6108  // and the view key part of the destination matches that of our our subaddress,
6109  // and the major index of this subaddress corresponds to the current account we're getting balance for,
6110  // then add amount to balance
6111  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) {
6112  auto found = amount_per_subaddr.find(subaddr_found->second.minor);
6113  if (found == amount_per_subaddr.end())
6114  amount_per_subaddr[subaddr_found->second.minor] = out.amount;
6115  else
6116  found->second += out.amount;
6117  } else {
6118  continue;
6119  }
6120  }
6121  }
6122  }
6123  // CHANGE HANDLING FOR V1 TX
6124  // (NB LOOPBACK OUTS APART FROM CHANGE AREN'T FACTORED INTO BAL WHILST TX IS UNCONFIRMED
6125  // and there is no need to fix this (monero) issue as we've migrated to a transparent chain)
6126  if (utx.second.m_tx.version == 1 && utx.second.m_subaddr_account == index_major) {
6127  // all changes go to 0-th subaddress (in the current subaddress account)
6128  auto found = amount_per_subaddr.find(0);
6129  if (found == amount_per_subaddr.end())
6130  amount_per_subaddr[0] = utx.second.m_change;
6131  else
6132  found->second += utx.second.m_change;
6133  }
6134  }
6135  }
6136  return amount_per_subaddr;
6137 }
cryptonote::account_public_address get_subaddress(const cryptonote::subaddress_index &index) const
Definition: wallet2.cpp:1429

◆ blackball_output()

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

Definition at line 7965 of file wallet2.cpp.

7966 {
7967  if (!m_ringdb)
7968  return false;
7969  try { return m_ringdb->blackball(output); }
7970  catch (const std::exception &e) { return false; }
7971 }

◆ callback() [1/2]

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

Definition at line 756 of file wallet2.h.

756 { return m_callback; }

◆ callback() [2/2]

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

Definition at line 757 of file wallet2.h.

757 { m_callback = callback; }
i_wallet2_callback * callback() const
Definition: wallet2.h:756
Here is the call graph for this function:
Here is the caller 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 4210 of file wallet2.cpp.

4211 {
4212  if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
4213  decrypt_keys(original_password);
4214  setup_keys(new_password);
4215  rewrite(filename, new_password);
4216  if (!filename.empty())
4217  store();
4218 }
void decrypt_keys(const crypto::chacha_key &key)
Definition: wallet2.cpp:4642
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:5560

◆ check_connection()

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

Definition at line 5648 of file wallet2.cpp.

5649 {
5650  THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
5651 
5652  if (m_offline)
5653  {
5654  if (version)
5655  *version = 0;
5656  if (ssl)
5657  *ssl = false;
5658  return false;
5659  }
5660 
5661  // TODO: Add light wallet version check.
5662  if(m_light_wallet) {
5663  if (version)
5664  *version = 0;
5665  if (ssl)
5666  *ssl = m_light_wallet_connected; // light wallet is always SSL
5667  return m_light_wallet_connected;
5668  }
5669 
5670  {
5671  boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
5672  if(!m_http_client.is_connected(ssl))
5673  {
5674  m_node_rpc_proxy.invalidate();
5675  if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
5676  return false;
5677  if(!m_http_client.is_connected(ssl))
5678  return false;
5679  }
5680  }
5681 
5682  if (version)
5683  {
5686  bool r = invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t);
5687  if(!r) {
5688  *version = 0;
5689  return false;
5690  }
5691  if (resp_t.status != CORE_RPC_STATUS_OK)
5692  *version = 0;
5693  else
5694  *version = resp_t.version;
5695  }
5696 
5697  return true;
5698 }
bool connect(std::chrono::milliseconds timeout)
Definition: http_client.h:333
version
Supported socks variants.
Definition: socks.h:58
Here is the call 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 11580 of file wallet2.cpp.

11581 {
11582  uint32_t rpc_version;
11583  THROW_WALLET_EXCEPTION_IF(!check_connection(&rpc_version), error::wallet_internal_error, "Failed to connect to daemon: " + get_daemon_address());
11584  THROW_WALLET_EXCEPTION_IF(rpc_version < MAKE_CORE_RPC_VERSION(1, 0), error::wallet_internal_error, "Daemon RPC version is too old");
11585 
11586  static constexpr char header[] = "ReserveProofV1";
11587  THROW_WALLET_EXCEPTION_IF(!boost::string_ref{sig_str}.starts_with(header), error::wallet_internal_error,
11588  "Signature header check error");
11589 
11590  std::string sig_decoded;
11591  THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(std::strlen(header)), sig_decoded), error::wallet_internal_error,
11592  "Signature decoding error");
11593 
11594  std::istringstream iss(sig_decoded);
11596  std::vector<reserve_proof_entry> proofs;
11597  std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
11598  ar >> proofs >> subaddr_spendkeys;
11599 
11600  THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(address.m_spend_public_key) == 0, error::wallet_internal_error,
11601  "The given address isn't found in the proof");
11602 
11603  // compute signature prefix hash
11604  std::string prefix_data = message;
11605  prefix_data.append((const char*)&address, sizeof(cryptonote::account_public_address));
11606  for (size_t i = 0; i < proofs.size(); ++i)
11607  {
11608  prefix_data.append((const char*)&proofs[i].key_image, sizeof(crypto::key_image));
11609  }
11610  crypto::hash prefix_hash;
11611  crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11612 
11613  // fetch txes from daemon
11616  for (size_t i = 0; i < proofs.size(); ++i)
11617  gettx_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(proofs[i].txid));
11618  gettx_req.decode_as_json = false;
11619  gettx_req.prune = true;
11620  m_daemon_rpc_mutex.lock();
11621  bool ok = invoke_http_json("/gettransactions", gettx_req, gettx_res, rpc_timeout);
11622  m_daemon_rpc_mutex.unlock();
11623  THROW_WALLET_EXCEPTION_IF(!ok || gettx_res.txs.size() != proofs.size(),
11624  error::wallet_internal_error, "Failed to get transaction from daemon");
11625 
11626  // check spent status
11629  for (size_t i = 0; i < proofs.size(); ++i)
11630  kispent_req.key_images.push_back(epee::string_tools::pod_to_hex(proofs[i].key_image));
11631  m_daemon_rpc_mutex.lock();
11632  ok = invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, rpc_timeout);
11633  m_daemon_rpc_mutex.unlock();
11634  THROW_WALLET_EXCEPTION_IF(!ok || kispent_res.spent_status.size() != proofs.size(),
11635  error::wallet_internal_error, "Failed to get key image spent status from daemon");
11636 
11637  total = spent = 0;
11638  for (size_t i = 0; i < proofs.size(); ++i)
11639  {
11640  const reserve_proof_entry& proof = proofs[i];
11641  THROW_WALLET_EXCEPTION_IF(gettx_res.txs[i].in_pool, error::wallet_internal_error, "Tx is unconfirmed");
11642 
11644  crypto::hash tx_hash;
11645  ok = get_pruned_tx(gettx_res.txs[i], tx, tx_hash);
11646  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11647 
11648  THROW_WALLET_EXCEPTION_IF(tx_hash != proof.txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
11649 
11650  THROW_WALLET_EXCEPTION_IF(proof.index_in_tx >= tx.vout.size(), error::wallet_internal_error, "index_in_tx is out of bound");
11651 
11652  const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[proof.index_in_tx].target));
11653  THROW_WALLET_EXCEPTION_IF(!out_key, error::wallet_internal_error, "Output key wasn't found")
11654 
11655  // get tx pub key
11656  const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
11657  THROW_WALLET_EXCEPTION_IF(tx_pub_key == crypto::null_pkey, error::wallet_internal_error, "The tx public key isn't found");
11658  const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
11659 
11660  // check singature for shared secret
11661  ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, proof.shared_secret, proof.shared_secret_sig);
11662  if (!ok && additional_tx_pub_keys.size() == tx.vout.size())
11663  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);
11664  if (!ok)
11665  return false;
11666 
11667  // check signature for key image
11668  const std::vector<const crypto::public_key*> pubs = { &out_key->key };
11669  ok = crypto::check_ring_signature(prefix_hash, proof.key_image, &pubs[0], 1, &proof.key_image_sig);
11670  if (!ok)
11671  return false;
11672 
11673  // check if the address really received the fund
11674  crypto::key_derivation derivation;
11675  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");
11676  crypto::public_key subaddr_spendkey;
11677  crypto::derive_subaddress_public_key(out_key->key, derivation, proof.index_in_tx, subaddr_spendkey);
11678  THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(subaddr_spendkey) == 0, error::wallet_internal_error,
11679  "The address doesn't seem to have received the fund");
11680 
11681  // check amount
11682  uint64_t amount = tx.vout[proof.index_in_tx].amount;
11683  if (amount == 0)
11684  {
11685  // decode rct
11686  crypto::secret_key shared_secret;
11687  crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
11688  rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
11689  rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2);
11690  amount = rct::h2d(ecdh_info.amount);
11691  }
11692  total += amount;
11693  if (kispent_res.spent_status[i])
11694  spent += amount;
11695  }
11696 
11697  // check signatures for all subaddress spend keys
11698  for (const auto &i : subaddr_spendkeys)
11699  {
11700  if (!crypto::check_signature(prefix_hash, i.first, i.second))
11701  return false;
11702  }
11703  return true;
11704 }
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:1311
bool check_connection(uint32_t *version=NULL, bool *ssl=NULL, uint32_t timeout=200000)
Definition: wallet2.cpp:5648
std::string get_daemon_address() const
Definition: wallet2.cpp:11716
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)
Definition: wallet2.cpp:11317
#define MAKE_CORE_RPC_VERSION(major, minor)
std::string message("Message requiring signing")
const char * key
Definition: hmac_keccak.cpp:39
crypto namespace.
Definition: crypto.cpp:58
void cn_fast_hash(const void *data, std::size_t length, hash &hash)
Definition: hash.h:69
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:284
POD_CLASS key_derivation
Definition: crypto.h:98
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
Definition: crypto.h:270
POD_CLASS public_key
Definition: crypto.h:76
POD_CLASS key_image
Definition: crypto.h:102
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig)
Definition: crypto.h:293
void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res)
Definition: crypto.h:277
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:331
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)
Definition: string_tools.h:317
error
Tracks LMDB error codes.
Definition: error.h:45
@ RCTTypeBulletproof2
Definition: rctTypes.h:233
etn_amount h2d(const key &test)
Definition: rctTypes.cpp:161
void ecdhDecode(ecdhTuple &masked, const key &sharedSec, bool v2)
Definition: rctOps.cpp:712
::std::string string
Definition: gtest-port.h:1097
bool decode(const std::string &enc, std::string &data)
Definition: base58.cpp:196
#define false
Definition: stdbool.h:38
crypto::public_key key
std::vector< ecdhTuple > ecdhInfo
Definition: rctTypes.h:246
uint8_t type
Definition: rctTypes.h:241
Here is the call 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 10953 of file wallet2.cpp.

10954 {
10955  const std::string header = "SpendProofV1";
10956  const size_t header_len = header.size();
10957  THROW_WALLET_EXCEPTION_IF(sig_str.size() < header_len || sig_str.substr(0, header_len) != header, error::wallet_internal_error,
10958  "Signature header check error");
10959 
10960  // fetch tx from daemon
10962  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
10963  req.decode_as_json = false;
10964  req.prune = true;
10966  bool r;
10967  {
10968  const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
10969  r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
10970  }
10971  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
10972  THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
10973  THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
10974  THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
10975  "daemon returned wrong response for gettransactions, wrong txs count = " +
10976  std::to_string(res.txs.size()) + ", expected 1");
10977 
10979  crypto::hash tx_hash;
10980  THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(res.txs[0], tx, tx_hash), error::wallet_internal_error, "failed to get tx from daemon");
10981 
10982  // check signature size
10983  size_t num_sigs = 0;
10984  for(size_t i = 0; i < tx.vin.size(); ++i)
10985  {
10986  const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
10987  if (in_key != nullptr)
10988  num_sigs += in_key->key_offsets.size();
10989  }
10990  std::vector<std::vector<crypto::signature>> signatures = { std::vector<crypto::signature>(1) };
10991  const size_t sig_len = tools::base58::encode(std::string((const char *)&signatures[0][0], sizeof(crypto::signature))).size();
10992  if( sig_str.size() != header_len + num_sigs * sig_len ) {
10993  return false;
10994  }
10995 
10996  // decode base58
10997  signatures.clear();
10998  size_t offset = header_len;
10999  for(size_t i = 0; i < tx.vin.size(); ++i)
11000  {
11001  const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
11002  if (in_key == nullptr)
11003  continue;
11004  signatures.resize(signatures.size() + 1);
11005  signatures.back().resize(in_key->key_offsets.size());
11006  for (size_t j = 0; j < in_key->key_offsets.size(); ++j)
11007  {
11008  std::string sig_decoded;
11009  THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(offset, sig_len), sig_decoded), error::wallet_internal_error, "Signature decoding error");
11010  THROW_WALLET_EXCEPTION_IF(sizeof(crypto::signature) != sig_decoded.size(), error::wallet_internal_error, "Signature decoding error");
11011  memcpy(&signatures.back()[j], sig_decoded.data(), sizeof(crypto::signature));
11012  offset += sig_len;
11013  }
11014  }
11015 
11016  // get signature prefix hash
11017  std::string sig_prefix_data((const char*)&txid, sizeof(crypto::hash));
11018  sig_prefix_data += message;
11019  crypto::hash sig_prefix_hash;
11020  crypto::cn_fast_hash(sig_prefix_data.data(), sig_prefix_data.size(), sig_prefix_hash);
11021 
11022  std::vector<std::vector<crypto::signature>>::const_iterator sig_iter = signatures.cbegin();
11023  for(size_t i = 0; i < tx.vin.size(); ++i)
11024  {
11025  const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
11026  if (in_key == nullptr)
11027  continue;
11028 
11029  // get output pubkeys in the ring
11031  const std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key->key_offsets);
11032  req.outputs.resize(absolute_offsets.size());
11033  for (size_t j = 0; j < absolute_offsets.size(); ++j)
11034  {
11035  req.outputs[j].amount = in_key->amount;
11036  req.outputs[j].index = absolute_offsets[j];
11037  }
11039  bool r;
11040  {
11041  const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
11042  r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
11043  }
11044  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
11045  THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
11046  THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "get_outs.bin");
11047  THROW_WALLET_EXCEPTION_IF(res.outs.size() != req.outputs.size(), error::wallet_internal_error,
11048  "daemon returned wrong response for get_outs.bin, wrong amounts count = " +
11049  std::to_string(res.outs.size()) + ", expected " + std::to_string(req.outputs.size()));
11050 
11051  // copy pointers
11052  std::vector<const crypto::public_key *> p_output_keys;
11053  for (const COMMAND_RPC_GET_OUTPUTS_BIN::outkey &out : res.outs)
11054  p_output_keys.push_back(&out.key);
11055 
11056  // check this ring
11057  if (!crypto::check_ring_signature(sig_prefix_hash, in_key->k_image, p_output_keys, sig_iter->data()))
11058  return false;
11059  ++sig_iter;
11060  }
11061  THROW_WALLET_EXCEPTION_IF(sig_iter != signatures.cend(), error::wallet_internal_error, "Signature iterator didn't reach the end");
11062  return true;
11063 }
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:1318
void * memcpy(void *a, const void *b, size_t c)
const char * res
Definition: hmac_keccak.cpp:41
POD_CLASS signature
Definition: crypto.h:108
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
std::string to_string(t_connection_type type)
std::string encode(const std::string &data)
Definition: base58.cpp:173
crypto::key_image k_image
std::vector< uint64_t > key_offsets
Here is the call 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 11066 of file wallet2.cpp.

11067 {
11068  crypto::key_derivation derivation;
11069  THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation), error::wallet_internal_error,
11070  "Failed to generate key derivation from supplied parameters");
11071 
11072  std::vector<crypto::key_derivation> additional_derivations;
11073  additional_derivations.resize(additional_tx_keys.size());
11074  for (size_t i = 0; i < additional_tx_keys.size(); ++i)
11075  THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i]), error::wallet_internal_error,
11076  "Failed to generate key derivation from supplied parameters");
11077 
11078  check_tx_key_helper(txid, derivation, additional_derivations, address, received, in_pool, confirmations);
11079 }
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)
Definition: wallet2.cpp:11113
Here is the call 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 11113 of file wallet2.cpp.

11114 {
11117  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11118  req.decode_as_json = false;
11119  req.prune = true;
11120  m_daemon_rpc_mutex.lock();
11121  bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11122  m_daemon_rpc_mutex.unlock();
11123  THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
11124  error::wallet_internal_error, "Failed to get transaction from daemon");
11125 
11127  crypto::hash tx_hash;
11128  if (res.txs.size() == 1)
11129  {
11130  ok = get_pruned_tx(res.txs.front(), tx, tx_hash);
11131  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11132  }
11133  else
11134  {
11135  cryptonote::blobdata tx_data;
11136  ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
11137  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11139  error::wallet_internal_error, "Failed to validate transaction from daemon");
11140  tx_hash = cryptonote::get_transaction_hash(tx);
11141  }
11142 
11143  THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error,
11144  "Failed to get the right transaction from daemon");
11145  THROW_WALLET_EXCEPTION_IF(!additional_derivations.empty() && additional_derivations.size() != tx.vout.size(), error::wallet_internal_error,
11146  "The size of additional derivations is wrong");
11147 
11148  check_tx_key_helper(tx, derivation, additional_derivations, address, received);
11149 
11150  in_pool = res.txs.front().in_pool;
11151  confirmations = 0;
11152  if (!in_pool)
11153  {
11154  std::string err;
11155  uint64_t bc_height = get_daemon_blockchain_height(err);
11156  if (err.empty())
11157  confirmations = bc_height - res.txs.front().block_height;
11158  }
11159 }
uint64_t get_daemon_blockchain_height(std::string &err) const
Definition: wallet2.cpp:11721
crypto::hash get_transaction_hash(const transaction &t)
std::string blobdata
Definition: blobdatatype.h:39
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)
Definition: string_tools.h:92
Here is the call 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 11081 of file wallet2.cpp.

11082 {
11083  received = 0;
11084 
11085  for (size_t n = 0; n < tx.vout.size(); ++n)
11086  {
11087  const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[n].target));
11088  if (!out_key)
11089  continue;
11090 
11091  crypto::public_key derived_out_key;
11092  bool r = crypto::derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key);
11093  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
11094  bool found = out_key->key == derived_out_key;
11095  crypto::key_derivation found_derivation = derivation;
11096  if (!found && !additional_derivations.empty())
11097  {
11098  r = crypto::derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key);
11099  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
11100  found = out_key->key == derived_out_key;
11101  found_derivation = additional_derivations[n];
11102  }
11103 
11104  if (found)
11105  {
11106  uint64_t amount;
11107  amount = tx.vout[n].amount;
11108  received += amount;
11109  }
11110  }
11111 }
bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key)
Definition: crypto.h:273
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 11317 of file wallet2.cpp.

11318 {
11319  // fetch tx pubkey from the daemon
11322  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11323  req.decode_as_json = false;
11324  req.prune = true;
11325  m_daemon_rpc_mutex.lock();
11326  bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11327  m_daemon_rpc_mutex.unlock();
11328  THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
11329  error::wallet_internal_error, "Failed to get transaction from daemon");
11330 
11332  crypto::hash tx_hash;
11333  if (res.txs.size() == 1)
11334  {
11335  ok = get_pruned_tx(res.txs.front(), tx, tx_hash);
11336  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11337  }
11338  else
11339  {
11340  cryptonote::blobdata tx_data;
11341  ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
11342  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11344  error::wallet_internal_error, "Failed to validate transaction from daemon");
11345  tx_hash = cryptonote::get_transaction_hash(tx);
11346  }
11347 
11348  THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
11349 
11350  if (!check_tx_proof(tx, address, is_subaddress, message, sig_str, received))
11351  return false;
11352 
11353  in_pool = res.txs.front().in_pool;
11354  confirmations = 0;
11355  if (!in_pool)
11356  {
11357  std::string err;
11358  uint64_t bc_height = get_daemon_blockchain_height(err);
11359  if (err.empty())
11360  confirmations = bc_height - res.txs.front().block_height;
11361  }
11362 
11363  return true;
11364 }
Here is the call 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 11366 of file wallet2.cpp.

11367 {
11368  CHECK_AND_ASSERT_THROW_MES(tx.version == 1, "Tx proofs are for v1 transactions only");
11369  const bool is_out = sig_str.substr(0, 3) == "Out";
11370  const std::string header = is_out ? "OutProofV1" : "InProofV1";
11371  const size_t header_len = header.size();
11372  THROW_WALLET_EXCEPTION_IF(sig_str.size() < header_len || sig_str.substr(0, header_len) != header, error::wallet_internal_error,
11373  "Signature header check error");
11374 
11375  // decode base58
11376  std::vector<crypto::public_key> shared_secret(1);
11377  std::vector<crypto::signature> sig(1);
11378  const size_t pk_len = tools::base58::encode(std::string((const char *)&shared_secret[0], sizeof(crypto::public_key))).size();
11379  const size_t sig_len = tools::base58::encode(std::string((const char *)&sig[0], sizeof(crypto::signature))).size();
11380  const size_t num_sigs = (sig_str.size() - header_len) / (pk_len + sig_len);
11381  THROW_WALLET_EXCEPTION_IF(sig_str.size() != header_len + num_sigs * (pk_len + sig_len), error::wallet_internal_error,
11382  "Wrong signature size");
11383  shared_secret.resize(num_sigs);
11384  sig.resize(num_sigs);
11385  for (size_t i = 0; i < num_sigs; ++i)
11386  {
11387  std::string pk_decoded;
11388  std::string sig_decoded;
11389  const size_t offset = header_len + i * (pk_len + sig_len);
11390  THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(offset, pk_len), pk_decoded), error::wallet_internal_error,
11391  "Signature decoding error");
11392  THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(offset + pk_len, sig_len), sig_decoded), error::wallet_internal_error,
11393  "Signature decoding error");
11394  THROW_WALLET_EXCEPTION_IF(sizeof(crypto::public_key) != pk_decoded.size() || sizeof(crypto::signature) != sig_decoded.size(), error::wallet_internal_error,
11395  "Signature decoding error");
11396  memcpy(&shared_secret[i], pk_decoded.data(), sizeof(crypto::public_key));
11397  memcpy(&sig[i], sig_decoded.data(), sizeof(crypto::signature));
11398  }
11399 
11401  THROW_WALLET_EXCEPTION_IF(tx_pub_key == null_pkey, error::wallet_internal_error, "Tx pubkey was not found");
11402 
11403  std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
11404  THROW_WALLET_EXCEPTION_IF(additional_tx_pub_keys.size() + 1 != num_sigs, error::wallet_internal_error, "Signature size mismatch with additional tx pubkeys");
11405 
11407  std::string prefix_data((const char*)&txid, sizeof(crypto::hash));
11408  prefix_data += message;
11409  crypto::hash prefix_hash;
11410  crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11411 
11412  // check signature
11413  std::vector<int> good_signature(num_sigs, 0);
11414  if (is_out)
11415  {
11416  good_signature[0] = is_subaddress ?
11417  crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], sig[0]) :
11418  crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], sig[0]);
11419 
11420  for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
11421  {
11422  good_signature[i + 1] = is_subaddress ?
11423  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]) :
11424  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]);
11425  }
11426  }
11427  else
11428  {
11429  good_signature[0] = is_subaddress ?
11430  crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], sig[0]) :
11431  crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], sig[0]);
11432 
11433  for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
11434  {
11435  good_signature[i + 1] = is_subaddress ?
11436  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]) :
11437  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]);
11438  }
11439  }
11440 
11441  if (std::any_of(good_signature.begin(), good_signature.end(), [](int i) { return i > 0; }))
11442  {
11443  // obtain key derivation by multiplying scalar 1 to the shared secret
11444  crypto::key_derivation derivation;
11445  if (good_signature[0])
11446  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");
11447 
11448  std::vector<crypto::key_derivation> additional_derivations(num_sigs - 1);
11449  for (size_t i = 1; i < num_sigs; ++i)
11450  if (good_signature[i])
11451  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");
11452 
11453  check_tx_key_helper(tx, derivation, additional_derivations, address, received);
11454  return true;
11455  }
11456  return false;
11457 }
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
Definition: misc_log_ex.h:173
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:312
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 10484 of file wallet2.cpp.

10484  {
10485  auto & hwdev = get_account().get_device();
10486  CHECK_AND_ASSERT_THROW_MES(hwdev.has_ki_cold_sync(), "Device does not support cold ki sync protocol");
10487 
10488  auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
10489  CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
10490 
10491  std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
10493  setup_shim(&wallet_shim, this);
10494 
10495  dev_cold->ki_sync(&wallet_shim, m_transfers, ski);
10496 
10497  // Call COMMAND_RPC_IS_KEY_IMAGE_SPENT only if daemon is trusted.
10498  uint64_t import_res = import_key_images(ski, 0, spent, unspent, is_trusted_daemon());
10499  m_device_last_key_image_sync = time(NULL);
10500 
10501  return import_res;
10502 }
time_t time
Definition: blockchain.cpp:93
hw::device & get_device() const
Definition: account.h:91
bool is_trusted_daemon() const
Definition: wallet2.h:759
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)
Definition: wallet2.cpp:12123
cryptonote::account_base & get_account()
Definition: wallet2.h:728
struct hw::wallet_shim wallet_shim
Here is the call 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 10455 of file wallet2.cpp.

10456 {
10457  auto & hwdev = get_account().get_device();
10458  if (!hwdev.has_tx_cold_sign()){
10459  throw std::invalid_argument("Device does not support cold sign protocol");
10460  }
10461 
10462  unsigned_tx_set txs;
10463  for (auto &tx: ptx_vector)
10464  {
10465  txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
10466  }
10467  txs.transfers = std::make_pair(0, m_transfers);
10468 
10469  auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
10470  CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
10471 
10472  hw::tx_aux_data aux_data;
10474  setup_shim(&wallet_shim, this);
10475  aux_data.tx_recipients = dsts_info;
10476  aux_data.bp_version = use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1;
10477  dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data);
10478  tx_device_aux = aux_data.tx_device_aux;
10479 
10480  MDEBUG("Signed tx data from hw: " << exported_txs.ptx.size() << " transactions");
10481  for (auto &c_ptx: exported_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(c_ptx.tx));
10482 }
std::vector< std::string > tx_device_aux
Definition: device_cold.hpp:46
boost::optional< int > bp_version
Definition: device_cold.hpp:48
std::vector< cryptonote::address_parse_info > tx_recipients
Definition: device_cold.hpp:47
#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:

◆ 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 10445 of file wallet2.cpp.

10446 {
10447  CHECK_AND_ASSERT_THROW_MES(ptx.size() == tx_device_aux.size(), "TX aux has invalid size");
10448  for (size_t i = 0; i < ptx.size(); ++i){
10449  crypto::hash txid;
10450  txid = get_transaction_hash(ptx[i].tx);
10451  set_tx_device_aux(txid, tx_device_aux[i]);
10452  }
10453 }
void set_tx_device_aux(const crypto::hash &txid, const std::string &aux)
Definition: wallet2.cpp:11790
Here is the call graph for this function:

◆ commit_tx() [1/2]

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

Definition at line 6686 of file wallet2.cpp.

6687 {
6688  using namespace cryptonote;
6689 
6690  if(m_light_wallet)
6691  {
6694  oreq.address = get_account().get_public_address_str(m_nettype);
6695  oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
6697  m_daemon_rpc_mutex.lock();
6698  bool r = invoke_http_json("/submit_raw_tx", oreq, ores, rpc_timeout, "POST");
6699  m_daemon_rpc_mutex.unlock();
6700  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "submit_raw_tx");
6701  // MyMonero and OpenMonero use different status strings
6702  THROW_WALLET_EXCEPTION_IF(ores.status != "OK" && ores.status != "success" , error::tx_rejected, ptx.tx, get_rpc_status(ores.status), ores.error);
6703  }
6704  else
6705  {
6706  // Normal submit
6708  req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
6709  req.do_not_relay = false;
6710  req.do_sanity_checks = true;
6711  COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
6712  m_daemon_rpc_mutex.lock();
6713  bool r = invoke_http_json("/sendrawtransaction", req, daemon_send_resp, rpc_timeout);
6714  m_daemon_rpc_mutex.unlock();
6715  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
6716  THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
6717  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));
6718  // sanity checks
6719  for (size_t idx: ptx.selected_transfers)
6720  {
6721  THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error,
6722  "Bad output index in selected transfers: " + boost::lexical_cast<std::string>(idx));
6723  }
6724  }
6725  crypto::hash txid;
6726 
6727  txid = get_transaction_hash(ptx.tx);
6728  crypto::hash payment_id = crypto::null_hash;
6729  std::vector<cryptonote::tx_destination_entry> dests;
6730  uint64_t amount_in = 0;
6731  if (store_tx_info())
6732  {
6733  payment_id = get_payment_id(ptx);
6734  dests = ptx.dests;
6735  for(size_t idx: ptx.selected_transfers)
6736  amount_in += m_transfers[idx].amount();
6737  }
6738  add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
6739  if (store_tx_info())
6740  {
6741  m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
6742  m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
6743  }
6744 
6745  LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]");
6746 
6747  for(size_t idx: ptx.selected_transfers)
6748  {
6749  set_spent(idx, 0);
6750  }
6751 
6752  // tx generated, get rid of used k values
6753  for (size_t idx: ptx.selected_transfers)
6754  m_transfers[idx].m_multisig_k.clear();
6755 
6756  //fee includes dust if dust policy specified it.
6757  LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
6758  << "Commission: " << print_etn(ptx.fee) << " (dust sent to dust addr: " << print_etn((ptx.dust_added_to_fee ? 0 : ptx.dust)) << ")" << ENDL
6759  << "Pre V10 Balance: " << print_etn(balance(ptx.construction_data.subaddr_account, false)) << ENDL
6760  << "Pre V10 Unlocked Balance: " << print_etn(unlocked_balance(ptx.construction_data.subaddr_account, false)) << ENDL
6761  << "Public Chain Balance: " << print_etn(balance(ptx.construction_data.subaddr_account, true)) << ENDL
6762  << "Public Chain Unlocked Balance: " << print_etn(unlocked_balance(ptx.construction_data.subaddr_account, true)) << ENDL
6763  << "Please, wait for confirmation for your balance to be unlocked.");
6764 }
std::string get_public_address_str(network_type nettype) const
Definition: account.cpp:269
bool store_tx_info() const
Definition: wallet2.h:1061
uint64_t unlocked_balance(uint32_t subaddr_index_major, bool public_blockchain, uint64_t *blocks_to_unlock=NULL) const
Definition: wallet2.cpp:6062
#define ENDL
Definition: misc_log_ex.h:149
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
#define LOG_PRINT_L2(x)
Definition: misc_log_ex.h:101
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
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)
Definition: string_tools.h:87
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 6766 of file wallet2.cpp.

6767 {
6768  for (auto & ptx : ptx_vector)
6769  {
6770  commit_tx(ptx);
6771  }
6772 }
void commit_tx(pending_tx &ptx_vector)
Definition: wallet2.cpp:6686

◆ confirm_backlog() [1/2]

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

Definition at line 1079 of file wallet2.h.

1079 { return m_confirm_backlog; }

◆ confirm_backlog() [2/2]

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

Definition at line 1080 of file wallet2.h.

1080 { m_confirm_backlog = always; }

◆ confirm_export_overwrite() [1/2]

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

Definition at line 1083 of file wallet2.h.

1083 { return m_confirm_export_overwrite; }

◆ confirm_export_overwrite() [2/2]

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

Definition at line 1084 of file wallet2.h.

1084 { m_confirm_export_overwrite = always; }

◆ confirm_missing_payment_id() [1/2]

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

Definition at line 1069 of file wallet2.h.

1069 { 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 1070 of file wallet2.h.

1070 { 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 1095 of file wallet2.h.

1095 { 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 1096 of file wallet2.h.

1096 { 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 9515 of file wallet2.cpp.

9516 {
9517  //ensure device is let in NONE mode in any case
9518  hw::device &hwdev = m_account.get_device();
9519  boost::unique_lock<hw::device> hwdev_lock (hwdev);
9520  hw::reset_mode rst(hwdev);
9521 
9522  //destinations in the full etn-address format
9523  auto original_dsts = dsts;
9524 
9525  if(m_light_wallet) {
9526  // Populate m_transfers
9528  }
9529 
9530  uint8_t tx_version = this->public_transactions_required() ? 3 : 1;
9531  //vector of pairs of <subaddr minor index : vector<transfer indexes for that subaddr index inside m_transfers>>
9532  std::vector<std::pair<uint32_t, std::vector<size_t>>> unused_transfers_indices_per_subaddr;
9533  std::vector<std::pair<uint32_t, std::vector<size_t>>> unused_dust_indices_per_subaddr;
9534  uint64_t needed_etn;
9535  uint64_t accumulated_fee, accumulated_outputs, accumulated_change;
9536  struct TX {
9537  std::vector<size_t> selected_transfers;
9538  std::vector<cryptonote::tx_destination_entry> dsts;
9540  pending_tx ptx;
9541  size_t weight;
9542  uint64_t needed_fee;
9543  std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
9544 
9545  TX() : weight(0), needed_fee(0) {}
9546 
9547  void add(const cryptonote::tx_destination_entry &de, uint64_t amount, unsigned int original_output_index, bool merge_destinations) {
9548  if (merge_destinations)
9549  {
9550  std::vector<cryptonote::tx_destination_entry>::iterator i;
9551  i = std::find_if(dsts.begin(), dsts.end(), [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &de.addr, sizeof(de.addr)); });
9552  if (i == dsts.end())
9553  {
9554  dsts.push_back(de);
9555  i = dsts.end() - 1;
9556  i->amount = 0;
9557  }
9558  i->amount += amount;
9559  }
9560  else
9561  {
9562  THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error,
9563  std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size()));
9564  if (original_output_index == dsts.size())
9565  {
9566  dsts.push_back(de);
9567  dsts.back().amount = 0;
9568  }
9569  THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &de.addr, sizeof(de.addr)), error::wallet_internal_error, "Mismatched destination address");
9570  dsts[original_output_index].amount += amount;
9571  }
9572  }
9573  };
9574  std::vector<TX> txes;
9575  bool adding_fee; // true if new outputs go towards fee, rather than destinations
9576 
9577  uint64_t needed_fee, available_for_fee = 0;
9578  uint64_t upper_transaction_weight_limit;
9579  uint64_t extra_bytes = extra.size();
9580  switch(hwdev.get_type()){
9581 
9582  // Normal Software Limit
9583  case 0 : upper_transaction_weight_limit = get_upper_transaction_weight_limit(); break;
9584 
9585  // Ledger NanoS: ~3.3kB of RAM for app variables. Give a bit of buffer (300) for other variables on device
9586  // and subtract the size of the extra.
9587  // because in the Ledger app this still lives on the stack at the same time the entire prefix does.
9588  // This is a rough rule of thumb estimate... The logic can be updated at a later stage.
9589  // Right now we just need to make we don't fail to build any tx (and split the tx to avoid this happening)
9590  case 1 : upper_transaction_weight_limit = 3000 - extra_bytes; break;
9591 
9592  //Trezor limit set at the same as Ledger for the time being.
9593  case 2 : upper_transaction_weight_limit = 3000 - extra_bytes; break;
9594  //Future hw devices
9595  }
9596  const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
9597  const bool use_rct = use_fork_rules(HF_VERSION_ENABLE_RCT, 0);
9598  const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
9599  const rct::RCTConfig rct_config {
9601  bulletproof ? (use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1) : 0
9602  };
9603 
9604  const uint64_t base_fee = get_base_fee();
9605  const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
9606  const uint64_t fee_quantization_mask = get_fee_quantization_mask();
9607 
9608  // throw if attempting a transaction with no destinations
9609  THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
9610 
9611  // calculate total amount being sent to all destinations
9612  // throw if total amount overflows uint64_t
9613  needed_etn = 0;
9614  for(auto& dt: dsts)
9615  {
9616  THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination);
9617  needed_etn += dt.amount;
9618  LOG_PRINT_L2("transfer: adding " << print_etn(dt.amount) << ", for a total of " << print_etn (needed_etn));
9619  THROW_WALLET_EXCEPTION_IF(needed_etn < dt.amount, error::tx_sum_overflow, dsts, 0, m_nettype);
9620  }
9621 
9622  // throw if attempting a transaction with no etn
9623  THROW_WALLET_EXCEPTION_IF(needed_etn == 0, error::zero_destination);
9624 
9625  std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, tx_version >= 3);
9626  std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, tx_version >= 3);
9627 
9628  if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
9629  {
9630  for (const auto& i : balance_per_subaddr)
9631  subaddr_indices.insert(i.first);
9632  }
9633 
9634  // early out if we know we can't make it anyway
9635  // we could also check for being within FEE_PER_KB, but if the fee calculation
9636  // ever changes, this might be missed, so let this go through
9637  uint64_t min_fee = (fee_multiplier * base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof));
9638  //Whilst we're still dealing with fee/kb:
9639  if (!use_per_byte_fee){
9640  min_fee /= 1000;
9641  if(min_fee == 0){min_fee += 10;}
9642  }
9643  uint64_t balance_subtotal = 0;
9644  uint64_t unlocked_balance_subtotal = 0;
9645  for (uint32_t index_minor : subaddr_indices)
9646  {
9647  balance_subtotal += balance_per_subaddr[index_minor];
9648  unlocked_balance_subtotal += unlocked_balance_per_subaddr[index_minor].first;
9649  }
9650  THROW_WALLET_EXCEPTION_IF(needed_etn + min_fee > balance_subtotal, error::not_enough_etn,
9651  balance_subtotal, needed_etn, 0);
9652  // first check overall balance is enough, then unlocked one, so we throw distinct exceptions
9653  THROW_WALLET_EXCEPTION_IF(needed_etn + min_fee > unlocked_balance_subtotal, error::not_enough_unlocked_etn,
9654  unlocked_balance_subtotal, needed_etn, 0);
9655 
9656  for (uint32_t i : subaddr_indices)
9657  LOG_PRINT_L2("Candidate subaddress index for spending: " << i);
9658 
9659  // determine threshold for fractional amount
9660  const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof);
9661  const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof);
9662  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!");
9663  const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
9664  const uint64_t fractional_threshold = (fee_multiplier * base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
9665 
9666  // gather all dust and non-dust outputs belonging to specified subaddresses
9667  size_t num_nondust_outputs = 0;
9668  size_t num_dust_outputs = 0;
9669  for (size_t i = 0; i < m_transfers.size(); ++i)
9670  {
9671  const transfer_details& td = m_transfers[i];
9672  if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
9673  {
9674  MDEBUG("Ignoring output " << i << " of amount " << print_etn(td.amount()) << " which is below threshold " << print_etn(fractional_threshold));
9675  continue;
9676  }
9677  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)
9678  {
9679  if((tx_version < 3 && td.m_tx.version > 1) || (tx_version >= 3 && td.m_tx.version == 1))
9680  continue;
9681 
9682  const uint32_t index_minor = td.m_subaddr_index.minor;
9683  auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; };
9684  if ((td.is_rct()) || is_valid_decomposed_amount(td.amount()))
9685  {
9686  auto found = std::find_if(unused_transfers_indices_per_subaddr.begin(), unused_transfers_indices_per_subaddr.end(), find_predicate);
9687  if (found == unused_transfers_indices_per_subaddr.end())
9688  {
9689  unused_transfers_indices_per_subaddr.push_back({index_minor, {i}});
9690  }
9691  else
9692  {
9693  found->second.push_back(i);
9694  }
9695  ++num_nondust_outputs;
9696  }
9697  else
9698  {
9699  auto found = std::find_if(unused_dust_indices_per_subaddr.begin(), unused_dust_indices_per_subaddr.end(), find_predicate);
9700  if (found == unused_dust_indices_per_subaddr.end())
9701  {
9702  unused_dust_indices_per_subaddr.push_back({index_minor, {i}});
9703  }
9704  else
9705  {
9706  found->second.push_back(i);
9707  }
9708  ++num_dust_outputs;
9709  }
9710  }
9711  }
9712 
9713  // sort output indices
9714  {
9715  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)
9716  {
9717  return unlocked_balance_per_subaddr[x.first].first > unlocked_balance_per_subaddr[y.first].first;
9718  };
9719  std::sort(unused_transfers_indices_per_subaddr.begin(), unused_transfers_indices_per_subaddr.end(), sort_predicate);
9720  std::sort(unused_dust_indices_per_subaddr.begin(), unused_dust_indices_per_subaddr.end(), sort_predicate);
9721  }
9722 
9723  LOG_PRINT_L2("Starting with " << num_nondust_outputs << " non-dust outputs and " << num_dust_outputs << " dust outputs");
9724 
9725  if (unused_dust_indices_per_subaddr.empty() && unused_transfers_indices_per_subaddr.empty())
9726  return std::vector<wallet2::pending_tx>();
9727 
9728  // if empty, put dummy entry so that the front can be referenced later in the loop
9729  if (unused_dust_indices_per_subaddr.empty())
9730  unused_dust_indices_per_subaddr.push_back({});
9731  if (unused_transfers_indices_per_subaddr.empty())
9732  unused_transfers_indices_per_subaddr.push_back({});
9733 
9734  // start with an empty tx
9735  txes.push_back(TX());
9736  accumulated_fee = 0;
9737  accumulated_outputs = 0;
9738  accumulated_change = 0;
9739  adding_fee = false;
9740  needed_fee = 0;
9741  std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
9742 
9743  // for rct, since we don't see the amounts, we will try to make all transactions
9744  // look the same, with 1 or 2 inputs, and 2 outputs. One input is preferable, as
9745  // this prevents linking to another by provenance analysis, but two is ok if we
9746  // try to pick outputs not from the same block. We will get two outputs, one for
9747  // the destination, and one for change.
9748  LOG_PRINT_L2("checking preferred");
9749  std::vector<size_t> preferred_inputs;
9750  uint64_t rct_outs_needed = 2 * (fake_outs_count + 1);
9751  rct_outs_needed += 100; // some fudge factor since we don't know how many are locked
9752  if (use_rct)
9753  {
9754  // this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
9755  // will get us a known fee.
9756  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);
9757  preferred_inputs = pick_preferred_rct_inputs(needed_etn + estimated_fee, subaddr_account, subaddr_indices);
9758  if (!preferred_inputs.empty())
9759  {
9760  string s;
9761  for (auto i: preferred_inputs) s += boost::lexical_cast<std::string>(i) + " (" + print_etn(m_transfers[i].amount()) + ") ";
9762  LOG_PRINT_L1("Found preferred rct inputs for rct tx: " << s);
9763 
9764  // bring the list of available outputs stored by the same subaddress index to the front of the list
9765  uint32_t index_minor = m_transfers[preferred_inputs[0]].m_subaddr_index.minor;
9766  for (size_t i = 1; i < unused_transfers_indices_per_subaddr.size(); ++i)
9767  {
9768  if (unused_transfers_indices_per_subaddr[i].first == index_minor)
9769  {
9770  std::swap(unused_transfers_indices_per_subaddr[0], unused_transfers_indices_per_subaddr[i]);
9771  break;
9772  }
9773  }
9774  for (size_t i = 1; i < unused_dust_indices_per_subaddr.size(); ++i)
9775  {
9776  if (unused_dust_indices_per_subaddr[i].first == index_minor)
9777  {
9778  std::swap(unused_dust_indices_per_subaddr[0], unused_dust_indices_per_subaddr[i]);
9779  break;
9780  }
9781  }
9782  }
9783  }
9784  LOG_PRINT_L2("done checking preferred");
9785 
9786  // while:
9787  // - we have something to send
9788  // - or we need to gather more fee
9789  // - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2)
9790  unsigned int original_output_index = 0;
9791  std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second;
9792  std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second;
9793 
9795  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)) {
9796  TX &tx = txes.back();
9797 
9798  LOG_PRINT_L2("Start of loop with " << unused_transfers_indices->size() << " " << unused_dust_indices->size() << ", tx.dsts.size() " << tx.dsts.size());
9799  LOG_PRINT_L2("unused_transfers_indices: " << strjoin(*unused_transfers_indices, " "));
9800  LOG_PRINT_L2("unused_dust_indices: " << strjoin(*unused_dust_indices, " "));
9801  LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? "-" : cryptonote::print_etn(dsts[0].amount)));
9802  LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct);
9803 
9804  // if we need to spend etn and don't have any left, we fail
9805  if (unused_dust_indices->empty() && unused_transfers_indices->empty()) {
9806  LOG_PRINT_L2("No more outputs to choose from");
9807  THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, tx_version >= 3), needed_etn, accumulated_fee + needed_fee);
9808  }
9809 
9810  // get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
9811  // This could be more clever, but maybe at the cost of making probabilistic inferences easier
9812  size_t idx;
9813  if (!preferred_inputs.empty()) {
9814  idx = pop_back(preferred_inputs);
9815  pop_if_present(*unused_transfers_indices, idx);
9816  pop_if_present(*unused_dust_indices, idx);
9817  } else if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee) {
9818  // the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too
9819  std::vector<size_t> indices = get_only_rct(*unused_dust_indices, *unused_transfers_indices);
9820  idx = pop_best_value(indices, tx.selected_transfers, true);
9821 
9822  // we might not want to add it if it's a large output and we don't have many left
9823  uint64_t min_output_value = m_min_output_value;
9824  uint32_t min_output_count = m_min_output_count;
9825  if (min_output_value == 0 && min_output_count == 0)
9826  {
9827  min_output_value = DEFAULT_MIN_OUTPUT_VALUE;
9828  min_output_count = DEFAULT_MIN_OUTPUT_COUNT;
9829  }
9830  if (m_transfers[idx].amount() >= min_output_value) {
9831  if (get_count_above(m_transfers, *unused_transfers_indices, min_output_value) < min_output_count) {
9832  LOG_PRINT_L2("Second output was not strictly needed, and we're running out of outputs above " << print_etn(min_output_value) << ", not adding");
9833  break;
9834  }
9835  }
9836 
9837  // since we're trying to add a second output which is not strictly needed,
9838  // we only add it if it's unrelated enough to the first one
9839  float relatedness = get_output_relatedness(m_transfers[idx], m_transfers[tx.selected_transfers.front()]);
9840  if (relatedness > SECOND_OUTPUT_RELATEDNESS_THRESHOLD)
9841  {
9842  LOG_PRINT_L2("Second output was not strictly needed, and relatedness " << relatedness << ", not adding");
9843  break;
9844  }
9845  pop_if_present(*unused_transfers_indices, idx);
9846  pop_if_present(*unused_dust_indices, idx);
9847  } else
9848  idx = pop_best_value(unused_transfers_indices->empty() ? *unused_dust_indices : *unused_transfers_indices, tx.selected_transfers);
9849 
9850  const transfer_details &td = m_transfers[idx];
9851  LOG_PRINT_L2("Picking output " << idx << ", amount " << print_etn(td.amount()) << ", ki " << td.m_key_image);
9852 
9853  // add this output to the list to spend
9854  tx.selected_transfers.push_back(idx);
9855  uint64_t available_amount = td.amount();
9856  accumulated_outputs += available_amount;
9857 
9858  // clear any fake outs we'd already gathered, since we'll need a new set
9859  outs.clear();
9860 
9861  if (adding_fee)
9862  {
9863  LOG_PRINT_L2("We need more fee, adding it to fee");
9864  available_for_fee += available_amount;
9865  }
9866  else
9867  {
9868  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))
9869  {
9870  // we can fully pay that destination
9871  LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) <<
9872  " for " << print_etn(dsts[0].amount));
9873  tx.add(dsts[0], dsts[0].amount, original_output_index, m_merge_destinations);
9874  available_amount -= dsts[0].amount;
9875  dsts[0].amount = 0;
9876  pop_index(dsts, 0);
9877  ++original_output_index;
9878  }
9879 
9880  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)) {
9881  // we can partially fill that destination
9882  LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) <<
9883  " for " << print_etn(available_amount) << "/" << print_etn(dsts[0].amount));
9884  tx.add(dsts[0], available_amount, original_output_index, m_merge_destinations);
9885  dsts[0].amount -= available_amount;
9886  available_amount = 0;
9887  }
9888  }
9889 
9890  // here, check if we need to sent tx and start a new one
9891  LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
9892  << upper_transaction_weight_limit);
9893  bool try_tx = false;
9894  // if we have preferred picks, but haven't yet used all of them, continue
9895  if (preferred_inputs.empty())
9896  {
9897  if (adding_fee)
9898  {
9899  /* might not actually be enough if adding this output bumps size to next kB, but we need to try */
9900  try_tx = available_for_fee >= needed_fee;
9901  }
9902  else
9903  {
9904  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);
9905  try_tx = dsts.empty() || (estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
9906  THROW_WALLET_EXCEPTION_IF(try_tx && tx.dsts.empty(), error::tx_too_big, estimated_rct_tx_weight, upper_transaction_weight_limit);
9907  }
9908  }
9909 
9910  if (try_tx) {
9911  cryptonote::transaction test_tx;
9912  test_tx.version = tx_version;
9913  pending_tx test_ptx;
9914 
9915  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);
9916 
9917  uint64_t inputs = 0, outputs = needed_fee;
9918  for (size_t idx: tx.selected_transfers) inputs += m_transfers[idx].amount();
9919  for (const auto &o: tx.dsts) outputs += o.amount;
9920 
9921  if (inputs < outputs)
9922  {
9923  LOG_PRINT_L2("We don't have enough for the basic fee, switching to adding_fee");
9924  adding_fee = true;
9925  goto skip_tx;
9926  }
9927 
9928  LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
9929  tx.selected_transfers.size() << " inputs");
9930 
9931  transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
9932  detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
9933  auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
9934  needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
9935  available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0);
9936  LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(available_for_fee) << " available for fee (" <<
9937  print_etn(needed_fee) << " needed)");
9938 
9939  if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0)
9940  {
9941  // we don't have enough for the fee, but we've only partially paid the current address,
9942  // so we can take the fee from the paid amount, since we'll have to make another tx anyway
9943  std::vector<cryptonote::tx_destination_entry>::iterator i;
9944  i = std::find_if(tx.dsts.begin(), tx.dsts.end(),
9945  [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &dsts[0].addr, sizeof(dsts[0].addr)); });
9946  THROW_WALLET_EXCEPTION_IF(i == tx.dsts.end(), error::wallet_internal_error, "paid address not found in outputs");
9947  if (i->amount > needed_fee)
9948  {
9949  uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_fee;
9950  LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_nettype, i->is_subaddress, i->addr) << " from " <<
9951  print_etn(i->amount) << " to " << print_etn(new_paid_amount) << " to accommodate " <<
9952  print_etn(needed_fee) << " fee");
9953  dsts[0].amount += i->amount - new_paid_amount;
9954  i->amount = new_paid_amount;
9955  test_ptx.fee = needed_fee;
9956  available_for_fee = needed_fee;
9957  }
9958  }
9959 
9960  if (needed_fee > available_for_fee)
9961  {
9962  LOG_PRINT_L2("We could not make a tx, switching to fee accumulation");
9963 
9964  adding_fee = true;
9965  }
9966  else
9967  {
9968  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));
9969  while (needed_fee > test_ptx.fee) {
9970  transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
9971  detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
9972  txBlob = t_serializable_object_to_blob(test_ptx.tx);
9973  needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
9974  LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
9975  " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
9976  }
9977 
9978  LOG_PRINT_L2("Made a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
9979  " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
9980 
9981  tx.tx = test_tx;
9982  tx.ptx = test_ptx;
9983  tx.weight = get_transaction_weight(test_tx, txBlob.size());
9984  tx.outs = outs;
9985  tx.needed_fee = test_ptx.fee;
9986  accumulated_fee += test_ptx.fee;
9987  accumulated_change += test_ptx.change_dts.amount;
9988  adding_fee = false;
9989  if (!dsts.empty())
9990  {
9991  LOG_PRINT_L2("We have more to pay, starting another tx");
9992  txes.push_back(TX());
9993  original_output_index = 0;
9994  }
9995  }
9996  }
9997 
9998 skip_tx:
9999  // if unused_*_indices is empty while unused_*_indices_per_subaddr has multiple elements, and if we still have something to pay,
10000  // pop front of unused_*_indices_per_subaddr and have unused_*_indices point to the front of unused_*_indices_per_subaddr
10001  if ((!dsts.empty() && dsts[0].amount > 0) || adding_fee)
10002  {
10003  if (unused_transfers_indices->empty() && unused_transfers_indices_per_subaddr.size() > 1)
10004  {
10005  unused_transfers_indices_per_subaddr.erase(unused_transfers_indices_per_subaddr.begin());
10006  unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second;
10007  }
10008  if (unused_dust_indices->empty() && unused_dust_indices_per_subaddr.size() > 1)
10009  {
10010  unused_dust_indices_per_subaddr.erase(unused_dust_indices_per_subaddr.begin());
10011  unused_dust_indices = &unused_dust_indices_per_subaddr[0].second;
10012  }
10013  }
10014  }
10015 
10016  if (adding_fee)
10017  {
10018  LOG_PRINT_L1("We ran out of outputs while trying to gather final fee");
10019  THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, tx_version >= 3), needed_etn, accumulated_fee + needed_fee);
10020  }
10021 
10022  LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_etn(accumulated_fee) <<
10023  " total fee, " << print_etn(accumulated_change) << " total change");
10024 
10026  for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10027  {
10028  TX &tx = *i;
10029  cryptonote::transaction test_tx;
10030  test_tx.version = tx_version;
10031  pending_tx test_ptx;
10032  transfer_selected(tx.dsts,
10033  tx.selected_transfers,
10034  fake_outs_count,
10035  tx.outs,
10036  unlock_time,
10037  tx.needed_fee,
10038  extra,
10040  tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD),
10041  test_tx,
10042  test_ptx);
10043 
10044  auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
10045  tx.tx = test_tx;
10046  tx.ptx = test_ptx;
10047  tx.weight = get_transaction_weight(test_tx, txBlob.size());
10048  }
10049 
10050  std::vector<wallet2::pending_tx> ptx_vector;
10051  for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10052  {
10053  TX &tx = *i;
10054  uint64_t tx_etn = 0;
10055  for (size_t idx: tx.selected_transfers)
10056  tx_etn += m_transfers[idx].amount();
10057  LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
10058  " " << get_transaction_hash(tx.ptx.tx) << ": " << get_weight_string(tx.weight) << ", sending " << print_etn(tx_etn) << " in " << tx.selected_transfers.size() <<
10059  " outputs to " << tx.dsts.size() << " destination(s), including " <<
10060  print_etn(tx.ptx.fee) << " fee, " << print_etn(tx.ptx.change_dts.amount) << " change");
10061  ptx_vector.push_back(tx.ptx);
10062  }
10063 
10064  THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, original_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
10065 
10066  // if we made it this far, we're OK to actually send the transactions
10067  return ptx_vector;
10068 }
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
Definition: wallet2.cpp:10070
bool merge_destinations() const
Definition: wallet2.h:1078
void light_wallet_get_unspent_outs()
Definition: wallet2.cpp:9074
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:8742
int get_fee_algorithm() const
Definition: wallet2.cpp:7617
uint64_t get_fee_quantization_mask() const
Definition: wallet2.cpp:7600
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:6139
bool public_transactions_required() const
Definition: wallet2.h:892
bool is_transfer_unlocked(const transfer_details &td) const
Definition: wallet2.cpp:6364
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:6539
#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:2087
unsigned char uint8_t
Definition: stdint.h:124
account_public_address addr
#define TX_WEIGHT_TARGET(bytes)
Definition: wallet2.cpp:99
#define DEFAULT_MIN_OUTPUT_VALUE
Definition: wallet2.cpp:137
#define SECOND_OUTPUT_RELATEDNESS_THRESHOLD
Definition: wallet2.cpp:117
#define DEFAULT_MIN_OUTPUT_COUNT
Definition: wallet2.cpp:136
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 10149 of file wallet2.cpp.

10150 {
10151  std::vector<size_t> unused_transfers_indices;
10152  std::vector<size_t> unused_dust_indices;
10153  const bool use_rct = use_fork_rules(4, 0);
10154  uint8_t tx_version = public_transactions_required() ? (migrate ? 2 : 3) : 1;
10155  THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, tx_version >=3) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet");
10156  std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr;
10157 
10158  // gather all dust ***and*** non-dust outputs of specified subaddress (if any) and below specified threshold (if any)
10159  bool fund_found = false;
10160  for (size_t i = 0; i < m_transfers.size(); ++i)
10161  {
10162  const transfer_details& td = m_transfers[i];
10163 
10164  if((tx_version < 3 && td.m_tx.version > 1) || (tx_version >= 3 && td.m_tx.version == 1))
10165  continue;
10166 
10167  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))
10168  {
10169  fund_found = true;
10170  if (below == 0 || td.amount() < below)
10171  {
10172  if ((td.is_rct()) || is_valid_decomposed_amount(td.amount()))
10173  unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].first.push_back(i);
10174  else
10175  unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].second.push_back(i);
10176  }
10177  }
10178  }
10179  THROW_WALLET_EXCEPTION_IF(!fund_found, error::wallet_internal_error, "No unlocked balance in the specified subaddress(es)");
10180  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");
10181 
10182  if (subaddr_indices.empty())
10183  {
10184  // in case subaddress index wasn't specified, choose non-empty subaddress randomly (with index=0 being chosen last)
10185  if (unused_transfer_dust_indices_per_subaddr.count(0) == 1 && unused_transfer_dust_indices_per_subaddr.size() > 1)
10186  unused_transfer_dust_indices_per_subaddr.erase(0);
10187  auto i = unused_transfer_dust_indices_per_subaddr.begin();
10188  std::advance(i, crypto::rand_idx(unused_transfer_dust_indices_per_subaddr.size()));
10189  unused_transfers_indices = i->second.first;
10190  unused_dust_indices = i->second.second;
10191  LOG_PRINT_L2("Spending from subaddress index " << i->first);
10192  }
10193  else
10194  {
10195  for (const auto& p : unused_transfer_dust_indices_per_subaddr)
10196  {
10197  unused_transfers_indices.insert(unused_transfers_indices.end(), p.second.first.begin(), p.second.first.end());
10198  unused_dust_indices.insert(unused_dust_indices.end(), p.second.second.begin(), p.second.second.end());
10199  LOG_PRINT_L2("Spending from subaddress index " << p.first);
10200  }
10201  }
10202 
10203  return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, tx_version);
10204 }
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)
Definition: wallet2.cpp:10229
std::enable_if< std::is_unsigned< T >::value, T >::type rand_idx(T sz)
Definition: crypto.h:242
Here is the call 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 10229 of file wallet2.cpp.

10230 {
10231  //ensure device is let in NONE mode in any case
10232  hw::device &hwdev = m_account.get_device();
10233  boost::unique_lock<hw::device> hwdev_lock (hwdev);
10234  hw::reset_mode rst(hwdev);
10235 
10236  uint64_t accumulated_fee, accumulated_outputs, accumulated_change;
10237  struct TX {
10238  std::vector<size_t> selected_transfers;
10239  std::vector<cryptonote::tx_destination_entry> dsts;
10241  pending_tx ptx;
10242  size_t weight;
10243  uint64_t needed_fee;
10244  std::vector<std::vector<get_outs_entry>> outs;
10245 
10246  TX() : weight(0), needed_fee(0) {}
10247  };
10248  std::vector<TX> txes;
10249  uint64_t needed_fee, available_for_fee = 0;
10250  uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit(); //max size of a tx - usually ~ half the block size
10251  std::vector<std::vector<get_outs_entry>> outs;
10252 
10253  const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE);
10254  const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
10255  const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
10256  const rct::RCTConfig rct_config {
10258  bulletproof ? (use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1) : 0,
10259  };
10260  const uint64_t base_fee = get_base_fee();
10261  const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
10262  const uint64_t fee_quantization_mask = get_fee_quantization_mask();
10263 
10264  LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs");
10265 
10266  if (unused_dust_indices.empty() && unused_transfers_indices.empty())
10267  return std::vector<wallet2::pending_tx>();
10268 
10269  // start with an empty tx
10270  txes.push_back(TX());
10271  accumulated_fee = 0;
10272  accumulated_outputs = 0;
10273  accumulated_change = 0;
10274  needed_fee = 0;
10275 
10276  // while we have something to send
10278  while (!unused_dust_indices.empty() || !unused_transfers_indices.empty()) {
10279  TX &tx = txes.back();
10280 
10281  // get a random unspent output and use it to pay next chunk. We try to alternate
10282  // dust and non dust to ensure we never get with only dust, from which we might
10283  // get a tx that can't pay for itself
10284  uint64_t fee_dust_threshold;
10286  {
10287  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);
10288  fee_dust_threshold = calculate_fee_from_weight(base_fee, estimated_tx_weight_with_one_extra_output, fee_multiplier, fee_quantization_mask);
10289  }
10290  else
10291  {
10292  fee_dust_threshold = base_fee * fee_multiplier * (upper_transaction_weight_limit + 1023) / 1024;
10293  }
10294 
10295  size_t idx =
10296  unused_transfers_indices.empty()
10297  ? pop_best_value(unused_dust_indices, tx.selected_transfers)
10298  : unused_dust_indices.empty()
10299  ? pop_best_value(unused_transfers_indices, tx.selected_transfers)
10300  : ((tx.selected_transfers.size() & 1) || accumulated_outputs > fee_dust_threshold)
10301  ? pop_best_value(unused_dust_indices, tx.selected_transfers)
10302  : pop_best_value(unused_transfers_indices, tx.selected_transfers);
10303 
10304  const transfer_details &td = m_transfers[idx];
10305  LOG_PRINT_L2("Picking output " << idx << ", amount " << print_etn(td.amount()));
10306 
10307  // add this output to the list to spend
10308  tx.selected_transfers.push_back(idx);
10309  uint64_t available_amount = td.amount();
10310  accumulated_outputs += available_amount;
10311 
10312  // clear any fake outs we'd already gathered, since we'll need a new set
10313  outs.clear();
10314 
10315  // here, check if we need to sent tx and start a new one
10316  LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
10317  << upper_transaction_weight_limit);
10318  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);
10319  bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
10320 
10321  if (try_tx) {
10322  cryptonote::transaction test_tx;
10323  test_tx.version = tx_version;
10324  pending_tx test_ptx;
10325 
10326  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);
10327 
10328  // add N - 1 outputs for correct initial fee estimation
10329  for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i)
10330  tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
10331 
10332  LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
10333  tx.selected_transfers.size() << " outputs");
10334 
10335  transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
10336  detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10337 
10338  auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
10339  needed_fee = tx_version == 2 ? 0 : calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
10340  available_for_fee = test_ptx.fee + test_ptx.change_dts.amount;
10341  for (auto &dt: test_ptx.dests)
10342  available_for_fee += dt.amount;
10343  LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(available_for_fee) << " available for fee (" <<
10344  print_etn(needed_fee) << " needed)");
10345 
10346  // add last output, missed for fee estimation
10347  if (outputs > 1)
10348  tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
10349 
10350  THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself");
10351 
10352  do {
10353  LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
10354  // distribute total transferred amount between outputs
10355  uint64_t amount_transferred = available_for_fee - needed_fee; //shouuld be zero for migration transactions
10356  uint64_t dt_amount = amount_transferred / outputs;
10357  // residue is distributed as one atomic unit per output until it reaches zero
10358  uint64_t residue = amount_transferred % outputs;
10359  for (auto &dt: tx.dsts)
10360  {
10361  uint64_t dt_residue = 0;
10362  if (residue > 0)
10363  {
10364  dt_residue = 1;
10365  residue -= 1;
10366  }
10367  dt.amount = dt_amount + dt_residue;
10368  }
10369  transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
10370  detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10371  txBlob = t_serializable_object_to_blob(test_ptx.tx);
10372  needed_fee = tx_version == 2 ? 0 : calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
10373  LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
10374  " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
10375  } while (needed_fee > test_ptx.fee);
10376 
10377  LOG_PRINT_L2("Made a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_etn(test_ptx.fee) <<
10378  " fee and " << print_etn(test_ptx.change_dts.amount) << " change");
10379 
10380  tx.tx = test_tx;
10381  tx.ptx = test_ptx;
10382  tx.weight = get_transaction_weight(test_tx, txBlob.size());
10383  tx.outs = outs;
10384  tx.needed_fee = test_ptx.fee;
10385  accumulated_fee += test_ptx.fee;
10386  accumulated_change += test_ptx.change_dts.amount;
10387  if (!unused_transfers_indices.empty() || !unused_dust_indices.empty())
10388  {
10389  LOG_PRINT_L2("We have more to pay, starting another tx");
10390  txes.push_back(TX());
10391  }
10392  }
10393  }
10394 
10395  LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_etn(accumulated_fee) <<
10396  " total fee, " << print_etn(accumulated_change) << " total change");
10397 
10399  for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10400  {
10401  TX &tx = *i;
10402  cryptonote::transaction test_tx;
10403  test_tx.version = tx_version;
10404  pending_tx test_ptx;
10405  transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra,
10406  detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
10407 
10408  auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
10409  tx.tx = test_tx;
10410  tx.ptx = test_ptx;
10411  tx.weight = get_transaction_weight(test_tx, txBlob.size());
10412  }
10413 
10414  std::vector<wallet2::pending_tx> ptx_vector;
10415  for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
10416  {
10417  TX &tx = *i;
10418  uint64_t tx_etn = 0;
10419  for (size_t idx: tx.selected_transfers)
10420  tx_etn += m_transfers[idx].amount();
10421  LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
10422  " " << get_transaction_hash(tx.ptx.tx) << ": " << get_weight_string(tx.weight) << ", sending " << print_etn(tx_etn) << " in " << tx.selected_transfers.size() <<
10423  " outputs to " << tx.dsts.size() << " destination(s), including " <<
10424  print_etn(tx.ptx.fee) << " fee, " << print_etn(tx.ptx.change_dts.amount) << " change");
10425  ptx_vector.push_back(tx.ptx);
10426  }
10427 
10428  uint64_t a = 0;
10429  for (const TX &tx: txes)
10430  {
10431  for (size_t idx: tx.selected_transfers)
10432  {
10433  a += m_transfers[idx].amount();
10434  }
10435  a -= tx.ptx.fee;
10436  }
10437  std::vector<cryptonote::tx_destination_entry> synthetic_dsts(1, cryptonote::tx_destination_entry("", a, address, is_subaddress));
10438  THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, synthetic_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
10439 
10440  // if we made it this far, we're OK to actually send the transactions
10441  return ptx_vector;
10442 }
Here is the call 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 10206 of file wallet2.cpp.

10207 {
10208  std::vector<size_t> unused_transfers_indices;
10209  std::vector<size_t> unused_dust_indices;
10210  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
10211  const bool use_rct = use_fork_rules(4, 0);
10212  // find output with the given key image (
10213  for (size_t i = 0; i < m_transfers.size(); ++i)
10214  {
10215  const transfer_details& td = m_transfers[i];
10216 
10217  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))
10218  {
10219  if (td.is_rct() || is_valid_decomposed_amount(td.amount()))
10220  unused_transfers_indices.push_back(i);
10221  else
10222  unused_dust_indices.push_back(i);
10223  break;
10224  }
10225  }
10226  return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, tx_version);
10227 }
Here is the call graph for this function:

◆ create_unmixable_sweep_transactions()

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

Definition at line 10660 of file wallet2.cpp.

10661 {
10662  // From hard fork 1, we don't consider small amounts to be dust anymore
10663  const bool hf1_rules = use_fork_rules(2, 10); // first hard fork has version 2
10664  tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD);
10665 
10666  uint8_t tx_version = this->public_transactions_required() ? 3 : 1;
10667  const uint64_t base_fee = get_base_fee();
10668 
10669  // may throw
10670  std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
10671  size_t num_dust_outputs = unmixable_outputs.size();
10672 
10673  if (num_dust_outputs == 0)
10674  {
10675  return std::vector<wallet2::pending_tx>();
10676  }
10677 
10678  // split in "dust" and "non dust" to make it easier to select outputs
10679  std::vector<size_t> unmixable_transfer_outputs, unmixable_dust_outputs;
10680  for (auto n: unmixable_outputs)
10681  {
10682  if (m_transfers[n].amount() < base_fee)
10683  unmixable_dust_outputs.push_back(n);
10684  else
10685  unmixable_transfer_outputs.push_back(n);
10686  }
10687 
10688  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);
10689 }
std::vector< size_t > select_available_unmixable_outputs()
Definition: wallet2.cpp:10648

◆ decrypt()

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

Definition at line 13003 of file wallet2.cpp.

13004 {
13005  const size_t prefix_size = sizeof(chacha_iv) + (authenticated ? sizeof(crypto::signature) : 0);
13006  THROW_WALLET_EXCEPTION_IF(ciphertext.size() < prefix_size,
13007  error::wallet_internal_error, "Unexpected ciphertext size");
13008 
13009  crypto::chacha_key key;
13010  crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds);
13011  const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0];
13012  if (authenticated)
13013  {
13015  crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash);
13016  crypto::public_key pkey;
13018  const crypto::signature &signature = *(const crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)];
13020  error::wallet_internal_error, "Failed to authenticate ciphertext");
13021  }
13022  std::unique_ptr<char[]> buffer{new char[ciphertext.size() - prefix_size]};
13023  auto wiper = epee::misc_utils::create_scope_leave_handler([&]() { memwipe(buffer.get(), ciphertext.size() - prefix_size); });
13024  crypto::chacha20(ciphertext.data() + sizeof(iv), ciphertext.size() - prefix_size, key, iv, buffer.get());
13025  return T(buffer.get(), ciphertext.size() - prefix_size);
13026 }
void chacha20(const void *data, size_t length, const uint8_t *key, const uint8_t *iv, char *cipher)
const uint32_t T[512]
void * memwipe(void *src, size_t n)
bool secret_key_to_public_key(const secret_key &sec, public_key &pub)
Definition: crypto.h:260
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)

◆ decrypt_keys() [1/2]

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

Definition at line 4642 of file wallet2.cpp.

4643 {
4644  m_account.encrypt_viewkey(key);
4645  m_account.decrypt_keys(key);
4646 }
void encrypt_viewkey(const crypto::chacha_key &key)
Definition: account.h:106
void decrypt_keys(const crypto::chacha_key &key)
Definition: account.h:105
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 4655 of file wallet2.cpp.

4656 {
4657  crypto::chacha_key key;
4658  crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
4659  decrypt_keys(key);
4660 }
const char * data() const noexcept
size_t size() const noexcept

◆ 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 13030 of file wallet2.cpp.

13031 {
13032  return decrypt(ciphertext, get_account().get_keys().m_view_secret_key, authenticated);
13033 }
T decrypt(const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated=true) const
Definition: wallet2.cpp:13003
Here is the call graph for this function:

◆ default_mixin() [1/2]

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

Definition at line 1063 of file wallet2.h.

1063 { return m_default_mixin; }

◆ default_mixin() [2/2]

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

Definition at line 1064 of file wallet2.h.

1064 { m_default_mixin = m; }

◆ deinit()

bool tools::wallet2::deinit ( )

Definition at line 3921 of file wallet2.cpp.

3922 {
3923  m_is_initialized=false;
3924  unlock_keys_file();
3925  m_account.deinit();
3926  return true;
3927 }
bool unlock_keys_file()
Definition: wallet2.cpp:8015

◆ delete_address_book_row()

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

Definition at line 3449 of file wallet2.cpp.

3449  {
3450  if(m_address_book.size() <= row_id)
3451  return false;
3452 
3453  m_address_book.erase(m_address_book.begin()+row_id);
3454 
3455  return true;
3456 }

◆ device_derivation_path() [1/2]

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

Definition at line 1103 of file wallet2.h.

1103 { return m_device_derivation_path; }

◆ device_derivation_path() [2/2]

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

Definition at line 1104 of file wallet2.h.

1104 { m_device_derivation_path = device_derivation_path; }
const std::string & device_derivation_path() const
Definition: wallet2.h:1103
Here is the call graph for this function:
Here is the caller 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 1187 of file wallet2.cpp.

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

◆ device_name() [1/2]

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

Definition at line 1101 of file wallet2.h.

1101 { return m_device_name; }

◆ device_name() [2/2]

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

Definition at line 1102 of file wallet2.h.

1102 { m_device_name = device_name; }
const std::string & device_name() const
Definition: wallet2.h:1101
Here is the call graph for this function:
Here is the caller 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 1182 of file wallet2.cpp.

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

◆ discard_unmixable_outputs()

void tools::wallet2::discard_unmixable_outputs ( )

Definition at line 10691 of file wallet2.cpp.

10692 {
10693  // may throw
10694  std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
10695  for (size_t idx : unmixable_outputs)
10696  {
10697  freeze(idx);
10698  }
10699 }
void freeze(size_t idx)
Definition: wallet2.cpp:1583

◆ dump_tx_to_str()

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

Definition at line 6783 of file wallet2.cpp.

6784 {
6785  LOG_PRINT_L0("saving " << ptx_vector.size() << " transactions");
6786  unsigned_tx_set txs;
6787  for (auto &tx: ptx_vector)
6788  {
6789  // Short payment id is encrypted with tx_key.
6790  // Since sign_tx() generates new tx_keys and encrypts the payment id, we need to save the decrypted payment ID
6791  // Save tx construction_data to unsigned_tx_set
6792  txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
6793  }
6794 
6795  txs.transfers = export_outputs();
6796  // save as binary
6797  std::ostringstream oss;
6799  try
6800  {
6801  ar << txs;
6802  }
6803  catch (...)
6804  {
6805  return std::string();
6806  }
6807  LOG_PRINT_L2("Saving unsigned tx data: " << oss.str());
6808  std::string ciphertext = encrypt_with_view_secret_key(oss.str());
6809 
6810  return std::string(UNSIGNED_TX_PREFIX) + ciphertext;
6811 }
std::pair< size_t, std::vector< tools::wallet2::transfer_details > > export_outputs(bool all=false) const
Definition: wallet2.cpp:12503
std::string encrypt_with_view_secret_key(const std::string &plaintext, bool authenticated=true) const
Definition: wallet2.cpp:12997
#define UNSIGNED_TX_PREFIX
Definition: wallet2.cpp:106

◆ enable_dns()

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

Definition at line 1375 of file wallet2.h.

1375 { 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 12961 of file wallet2.cpp.

12962 {
12963  crypto::chacha_key key;
12964  crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds);
12965  std::string ciphertext;
12966  crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>();
12967  ciphertext.resize(len + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0));
12968  crypto::chacha20(plaintext, len, key, iv, &ciphertext[sizeof(iv)]);
12969  memcpy(&ciphertext[0], &iv, sizeof(iv));
12970  if (authenticated)
12971  {
12973  crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash);
12974  crypto::public_key pkey;
12976  crypto::signature &signature = *(crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)];
12978  }
12979  return ciphertext;
12980 }
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig)
Definition: crypto.h:290
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

Definition at line 12982 of file wallet2.cpp.

12983 {
12984  return encrypt(plaintext.data(), plaintext.size(), skey, authenticated);
12985 }
std::string encrypt(const char *plaintext, size_t len, const crypto::secret_key &skey, bool authenticated=true) const
Definition: wallet2.cpp:12961

◆ 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 12992 of file wallet2.cpp.

12993 {
12994  return encrypt(plaintext.data(), plaintext.size(), skey, authenticated);
12995 }

◆ encrypt() [4/4]

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

Definition at line 12987 of file wallet2.cpp.

12988 {
12989  return encrypt(plaintext.data(), plaintext.size(), skey, authenticated);
12990 }

◆ encrypt_keys() [1/2]

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

Definition at line 4636 of file wallet2.cpp.

4637 {
4638  m_account.encrypt_keys(key);
4639  m_account.decrypt_viewkey(key);
4640 }
void decrypt_viewkey(const crypto::chacha_key &key)
Definition: account.h:107
void encrypt_keys(const crypto::chacha_key &key)
Definition: account.h:104
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 4648 of file wallet2.cpp.

4649 {
4650  crypto::chacha_key key;
4651  crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
4652  encrypt_keys(key);
4653 }
void encrypt_keys(const crypto::chacha_key &key)
Definition: wallet2.cpp:4636

◆ 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 12997 of file wallet2.cpp.

12998 {
12999  return encrypt(plaintext, get_account().get_keys().m_view_secret_key, authenticated);
13000 }

◆ 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 13269 of file wallet2.cpp.

13270 {
13271  for (const auto &fee_level: fee_levels)
13272  {
13273  THROW_WALLET_EXCEPTION_IF(fee_level.first == 0.0, error::wallet_internal_error, "Invalid 0 fee");
13274  THROW_WALLET_EXCEPTION_IF(fee_level.second == 0.0, error::wallet_internal_error, "Invalid 0 fee");
13275  }
13276 
13277  // get txpool backlog
13280  m_daemon_rpc_mutex.lock();
13281  bool r = invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, rpc_timeout);
13282  m_daemon_rpc_mutex.unlock();
13283  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "Failed to connect to daemon");
13284  THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog");
13285  THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
13286 
13287  uint64_t block_weight_limit = 0;
13288  const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
13289  throw_on_rpc_response_error(result, "get_info");
13290  uint64_t full_reward_zone = block_weight_limit / 2;
13291  THROW_WALLET_EXCEPTION_IF(full_reward_zone == 0, error::wallet_internal_error, "Invalid block weight limit from daemon");
13292 
13293  std::vector<std::pair<uint64_t, uint64_t>> blocks;
13294  for (const auto &fee_level: fee_levels)
13295  {
13296  const double our_fee_byte_min = fee_level.first;
13297  const double our_fee_byte_max = fee_level.second;
13298  uint64_t priority_weight_min = 0, priority_weight_max = 0;
13299  for (const auto &i: res.backlog)
13300  {
13301  if (i.weight == 0)
13302  {
13303  MWARNING("Got 0 weight tx from txpool, ignored");
13304  continue;
13305  }
13306  double this_fee_byte = i.fee / (double)i.weight;
13307  if (this_fee_byte >= our_fee_byte_min)
13308  priority_weight_min += i.weight;
13309  if (this_fee_byte >= our_fee_byte_max)
13310  priority_weight_max += i.weight;
13311  }
13312 
13313  uint64_t nblocks_min = priority_weight_min / full_reward_zone;
13314  uint64_t nblocks_max = priority_weight_max / full_reward_zone;
13315  MDEBUG("estimate_backlog: priority_weight " << priority_weight_min << " - " << priority_weight_max << " for "
13316  << our_fee_byte_min << " - " << our_fee_byte_max << " piconero byte fee, "
13317  << nblocks_min << " - " << nblocks_max << " blocks at block weight " << full_reward_zone);
13318  blocks.push_back(std::make_pair(nblocks_min, nblocks_max));
13319  }
13320  return blocks;
13321 }
Here is the call 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 13323 of file wallet2.cpp.

13324 {
13325  THROW_WALLET_EXCEPTION_IF(min_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
13326  THROW_WALLET_EXCEPTION_IF(max_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
13327  for (uint64_t fee: fees)
13328  {
13329  THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee");
13330  }
13331  std::vector<std::pair<double, double>> fee_levels;
13332  for (uint64_t fee: fees)
13333  {
13334  double our_fee_byte_min = fee / (double)min_tx_weight, our_fee_byte_max = fee / (double)max_tx_weight;
13335  fee_levels.emplace_back(our_fee_byte_min, our_fee_byte_max);
13336  }
13337  return estimate_backlog(fee_levels);
13338 }

◆ estimate_blockchain_height()

uint64_t tools::wallet2::estimate_blockchain_height ( )

Definition at line 4880 of file wallet2.cpp.

4881  {
4882  // -1 month for fluctuations in block time and machine date/time setup.
4883  // avg seconds per block
4884  const int seconds_per_block = DIFFICULTY_TARGET_V6;
4885  // ~num blocks per month
4886  const uint64_t blocks_per_month = 60*60*24*30/seconds_per_block;
4887 
4888  // try asking the daemon first
4889  std::string err;
4890  uint64_t height = 0;
4891 
4892  // we get the max of approximated height and local height.
4893  // approximated height is the least of daemon target height
4894  // (the max of what the other daemons are claiming is their
4895  // height) and the theoretical height based on the local
4896  // clock. This will be wrong only if both the local clock
4897  // is bad *and* a peer daemon claims a highest height than
4898  // the real chain.
4899  // local height is the height the local daemon is currently
4900  // synced to, it will be lower than the real chain height if
4901  // the daemon is currently syncing.
4902  // If we use the approximate height we subtract one month as
4903  // a safety margin.
4905  uint64_t target_height = get_daemon_blockchain_target_height(err);
4906  if (err.empty()) {
4907  if (target_height < height)
4908  height = target_height;
4909  } else {
4910  // if we couldn't talk to the daemon, check safety margin.
4911  if (height > blocks_per_month)
4912  height -= blocks_per_month;
4913  else
4914  height = 0;
4915  }
4916  uint64_t local_height = get_daemon_blockchain_height(err);
4917  if (err.empty() && local_height > height)
4918  height = local_height;
4919  return height;
4920  }
uint64_t get_daemon_blockchain_target_height(std::string &err)
Definition: wallet2.cpp:11739
uint64_t get_approximate_blockchain_height() const
Calculates the approximate blockchain height from current date/time.
Definition: wallet2.cpp:11755
#define DIFFICULTY_TARGET_V6

◆ 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 5170 of file wallet2.cpp.

5172 {
5174  error::wallet_internal_error, "Empty multisig info");
5175 
5176  if (info[0].substr(0, MULTISIG_EXTRA_INFO_MAGIC.size()) != MULTISIG_EXTRA_INFO_MAGIC)
5177  {
5179  error::wallet_internal_error, "Unsupported info string");
5180  }
5181 
5182  std::vector<crypto::public_key> signers;
5183  std::unordered_set<crypto::public_key> pkeys;
5184 
5185  THROW_WALLET_EXCEPTION_IF(!unpack_extra_multisig_info(info, signers, pkeys),
5186  error::wallet_internal_error, "Bad extra multisig info");
5187 
5188  return exchange_multisig_keys(password, pkeys, signers);
5189 }
std::string exchange_multisig_keys(const epee::wipeable_string &password, const std::vector< std::string > &info)
Definition: wallet2.cpp:5170
CXA_THROW_INFO_T * info
Definition: stack_trace.cpp:91

◆ 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 5191 of file wallet2.cpp.

5194 {
5195  CHECK_AND_ASSERT_THROW_MES(!derivations.empty(), "empty pkeys");
5196  CHECK_AND_ASSERT_THROW_MES(!signers.empty(), "empty signers");
5197 
5198  bool ready = false;
5199  CHECK_AND_ASSERT_THROW_MES(multisig(&ready), "The wallet is not multisig");
5200  CHECK_AND_ASSERT_THROW_MES(!ready, "Multisig wallet creation process has already been finished");
5201 
5202  // keys are decrypted
5204  if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
5205  {
5206  crypto::chacha_key chacha_key;
5207  crypto::generate_chacha_key(password.data(), password.size(), chacha_key, m_kdf_rounds);
5208  m_account.encrypt_viewkey(chacha_key);
5209  m_account.decrypt_keys(chacha_key);
5210  keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this, chacha_key]() { m_account.encrypt_keys(chacha_key); m_account.decrypt_viewkey(chacha_key); });
5211  }
5212 
5213  if (m_multisig_rounds_passed == multisig_rounds_required(m_multisig_signers.size(), m_multisig_threshold) - 1)
5214  {
5215  // the last round is passed and we have to calculate spend public key
5216  // add ours if not included
5218 
5219  if (std::find(signers.begin(), signers.end(), local_signer) == signers.end())
5220  {
5221  signers.push_back(local_signer);
5222  for (const auto &msk: get_account().get_multisig_keys())
5223  {
5224  derivations.insert(rct::rct2pk(rct::scalarmultBase(rct::sk2rct(msk))));
5225  }
5226  }
5227 
5228  CHECK_AND_ASSERT_THROW_MES(signers.size() == m_multisig_signers.size(), "Bad signers size");
5229 
5230  // Summing all of unique public multisig keys to calculate common public spend key
5231  crypto::public_key spend_public_key = cryptonote::generate_multisig_M_N_spend_public_key(std::vector<crypto::public_key>(derivations.begin(), derivations.end()));
5232  m_account_public_address.m_spend_public_key = spend_public_key;
5233  m_account.finalize_multisig(spend_public_key);
5234 
5235  m_multisig_signers = signers;
5236  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)); });
5237 
5238  ++m_multisig_rounds_passed;
5239  m_multisig_derivations.clear();
5240 
5241  // keys are encrypted again
5242  keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
5243 
5244  if (!m_wallet_file.empty())
5245  {
5246  bool r = store_keys(m_keys_file, password, false);
5248 
5249  if (boost::filesystem::exists(m_wallet_file + ".address.txt"))
5250  {
5251  r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
5252  if(!r) MERROR("String with address text not saved");
5253  }
5254  }
5255 
5256  m_subaddresses.clear();
5257  m_subaddress_labels.clear();
5258  add_subaddress_account(tr("Primary account"));
5259 
5260  if (!m_wallet_file.empty())
5261  store();
5262 
5263  return {};
5264  }
5265 
5266  // Below are either middle or secret spend key establishment rounds
5267 
5268  for (const auto& key: m_multisig_derivations)
5269  derivations.erase(key);
5270 
5271  // Deriving multisig keys (set of Mi = b * Bi) according to DH from other participants' multisig keys.
5272  auto new_derivations = cryptonote::generate_multisig_derivations(get_account().get_keys(), std::vector<crypto::public_key>(derivations.begin(), derivations.end()));
5273 
5274  std::string extra_multisig_info;
5275  if (m_multisig_rounds_passed == multisig_rounds_required(m_multisig_signers.size(), m_multisig_threshold) - 2) // next round is last
5276  {
5277  // Next round is last therefore we are performing secret spend establishment round as described above.
5278  MINFO("Creating spend key...");
5279 
5280  // Calculating our secret multisig keys by hashing our public multisig keys.
5281  auto multisig_keys = cryptonote::calculate_multisig_keys(std::vector<crypto::public_key>(new_derivations.begin(), new_derivations.end()));
5282  // And summing it to get personal secret spend key
5284 
5285  m_account.make_multisig(m_account.get_keys().m_view_secret_key, spend_skey, rct::rct2pk(rct::identity()), multisig_keys);
5286 
5287  // Packing public multisig keys to exchange with others and calculate common public spend key in the last round
5288  extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, secret_keys_to_public_keys(multisig_keys), spend_skey);
5289  }
5290  else
5291  {
5292  // This is just middle round
5293  MINFO("Preparing keys for next exchange round...");
5294  extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, new_derivations, m_account.get_keys().m_spend_secret_key);
5295  m_multisig_derivations = new_derivations;
5296  }
5297 
5298  ++m_multisig_rounds_passed;
5299 
5300  create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
5301  return extra_multisig_info;
5302 }
void finalize_multisig(const crypto::public_key &spend_public_key)
Definition: account.cpp:259
bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector< crypto::secret_key > &multisig_keys)
Definition: account.cpp:250
const account_keys & get_keys() const
Definition: account.cpp:264
static const char * tr(const char *str)
Definition: wallet2.cpp:993
void add_subaddress_account(const std::string &label, const bool update_account_tags=true)
Definition: wallet2.cpp:1462
crypto::public_key get_multisig_signer_public_key() const
Definition: wallet2.cpp:12678
bool multisig(bool *ready=NULL, uint32_t *threshold=NULL, uint32_t *total=NULL) const
Definition: wallet2.cpp:5524
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)
Definition: file_io_utils.h:73
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
crypto::secret_key m_view_secret_key
Definition: account.h:45
crypto::secret_key m_spend_secret_key
Definition: account.h:44

◆ expand_subaddresses()

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

Definition at line 1477 of file wallet2.cpp.

1478 {
1479  hw::device &hwdev = m_account.get_device();
1480  if (m_subaddress_labels.size() <= index.major)
1481  {
1482  // add new accounts
1484  const uint32_t major_end = get_subaddress_clamped_sum(index.major, m_subaddress_lookahead_major);
1485  for (index2.major = m_subaddress_labels.size(); index2.major < major_end; ++index2.major)
1486  {
1487  const uint32_t end = get_subaddress_clamped_sum((index2.major == index.major ? index.minor : 0), m_subaddress_lookahead_minor);
1488  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);
1489  for (index2.minor = 0; index2.minor < end; ++index2.minor)
1490  {
1491  const crypto::public_key &D = pkeys[index2.minor];
1492  m_subaddresses[D] = index2;
1493  }
1494  }
1495  m_subaddress_labels.resize(index.major + 1, {"Untitled account"});
1496  m_subaddress_labels[index.major].resize(index.minor + 1);
1497 
1498  if(update_account_tags)
1499  get_account_tags();
1500  }
1501  else if (m_subaddress_labels[index.major].size() <= index.minor)
1502  {
1503  // add new subaddresses
1504  const uint32_t end = get_subaddress_clamped_sum(index.minor, m_subaddress_lookahead_minor);
1505  const uint32_t begin = m_subaddress_labels[index.major].size();
1506  cryptonote::subaddress_index index2 = {index.major, begin};
1507  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);
1508  for (; index2.minor < end; ++index2.minor)
1509  {
1510  const crypto::public_key &D = pkeys[index2.minor - begin];
1511  m_subaddresses[D] = index2;
1512  }
1513  m_subaddress_labels[index.major].resize(index.minor + 1);
1514  }
1515 }
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.
Definition: wallet2.cpp:11826
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 740 of file wallet2.h.

740 {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 739 of file wallet2.h.

739 {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 12471 of file wallet2.cpp.

12472 {
12473  std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> bc;
12474  std::get<0>(bc) = m_blockchain.offset();
12475  std::get<1>(bc) = m_blockchain.empty() ? crypto::null_hash: m_blockchain.genesis();
12476  for (size_t n = m_blockchain.offset(); n < m_blockchain.size(); ++n)
12477  {
12478  std::get<2>(bc).push_back(m_blockchain[n]);
12479  }
12480  return bc;
12481 }
size_t offset() const
Definition: wallet2.h:182
bool empty() const
Definition: wallet2.h:190
const crypto::hash & genesis() const
Definition: wallet2.h:183

◆ 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 12011 of file wallet2.cpp.

12012 {
12013  PERF_TIMER(export_key_images_raw);
12014  std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
12015 
12016  size_t offset = 0;
12017  if (!all)
12018  {
12019  while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_request)
12020  ++offset;
12021  }
12022 
12023  ski.reserve(m_transfers.size() - offset);
12024  for (size_t n = offset; n < m_transfers.size(); ++n)
12025  {
12026  const transfer_details &td = m_transfers[n];
12027 
12028  // get ephemeral public key
12029  const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index];
12030  THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error,
12031  "Output is not txout_to_key");
12032  const cryptonote::txout_to_key &o = boost::get<const cryptonote::txout_to_key>(out.target);
12033  const crypto::public_key pkey = o.key;
12034 
12035  // get tx pub key
12036  std::vector<tx_extra_field> tx_extra_fields;
12037  if(!parse_tx_extra(td.m_tx.extra, tx_extra_fields))
12038  {
12039  // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
12040  }
12041 
12043  const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
12044 
12045  // generate ephemeral secret key
12046  crypto::key_image ki;
12047  cryptonote::keypair in_ephemeral;
12048  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);
12049  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
12050 
12051  THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image,
12052  error::wallet_internal_error, "key_image generated not matched with cached key image");
12053  THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != pkey,
12054  error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
12055 
12056  // sign the key image with the output secret key
12058  std::vector<const crypto::public_key*> key_ptrs;
12059  key_ptrs.push_back(&pkey);
12060 
12061  crypto::generate_ring_signature((const crypto::hash&)td.m_key_image, td.m_key_image, key_ptrs, in_ephemeral.sec, 0, &signature);
12062 
12063  ski.push_back(std::make_pair(td.m_key_image, signature));
12064  }
12065  return std::make_pair(offset, ski);
12066 }
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const
Definition: wallet2.cpp:11933
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:325
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 11981 of file wallet2.cpp.

11982 {
11984  std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images();
11987  const uint32_t offset = ski.first;
11988 
11989  std::string data;
11990  data.reserve(4 + ski.second.size() * (sizeof(crypto::key_image) + sizeof(crypto::signature)) + 2 * sizeof(crypto::public_key));
11991  data.resize(4);
11992  data[0] = offset & 0xff;
11993  data[1] = (offset >> 8) & 0xff;
11994  data[2] = (offset >> 16) & 0xff;
11995  data[3] = (offset >> 24) & 0xff;
11996  data += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
11997  data += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
11998  for (const auto &i: ski.second)
11999  {
12000  data += std::string((const char *)&i.first, sizeof(crypto::key_image));
12001  data += std::string((const char *)&i.second, sizeof(crypto::signature));
12002  }
12003 
12004  // encrypt data, keep magic plaintext
12005  PERF_TIMER(export_key_images_encrypt);
12006  std::string ciphertext = encrypt_with_view_secret_key(data);
12007  return epee::file_io_utils::save_string_to_file(filename, magic + ciphertext);
12008 }
bool export_key_images(const std::string &filename) const
Definition: wallet2.cpp:11981
account_public_address m_account_address
Definition: account.h:43
#define KEY_IMAGE_EXPORT_FILE_MAGIC
Definition: wallet2.cpp:122
Here is the call 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 12774 of file wallet2.cpp.

12775 {
12776  std::vector<tools::wallet2::multisig_info> info;
12777 
12779 
12780  info.resize(m_transfers.size());
12781  for (size_t n = 0; n < m_transfers.size(); ++n)
12782  {
12783  transfer_details &td = m_transfers[n];
12784  crypto::key_image ki;
12785  td.m_multisig_k.clear();
12786  info[n].m_LR.clear();
12787  info[n].m_partial_key_images.clear();
12788 
12789  for (size_t m = 0; m < get_account().get_multisig_keys().size(); ++m)
12790  {
12791  // we want to export the partial key image, not the full one, so we can't use td.m_key_image
12792  bool r = generate_multisig_key_image(get_account().get_keys(), m, td.get_public_key(), ki);
12793  CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate key image");
12794  info[n].m_partial_key_images.push_back(ki);
12795  }
12796 
12797  // Wallet tries to create as many transactions as many signers combinations. We calculate the maximum number here as follows:
12798  // 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.
12799  // That means counting combinations for excluding 2-of-3 wallets (k = total signers count - threshold, n = total signers count - 1).
12800  size_t nlr = tools::combinations_count(m_multisig_signers.size() - m_multisig_threshold, m_multisig_signers.size() - 1);
12801  for (size_t m = 0; m < nlr; ++m)
12802  {
12803  td.m_multisig_k.push_back(rct::skGen());
12804  const rct::multisig_kLRki kLRki = get_multisig_kLRki(n, td.m_multisig_k.back());
12805  info[n].m_LR.push_back({kLRki.L, kLRki.R});
12806  }
12807 
12808  info[n].m_signer = signer;
12809  }
12810 
12811  std::stringstream oss;
12813  ar << info;
12814 
12816  std::string header;
12817  header += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
12818  header += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
12819  header += std::string((const char *)&signer, sizeof(crypto::public_key));
12820  std::string ciphertext = encrypt_with_view_secret_key(header + oss.str());
12821 
12822  return MULTISIG_EXPORT_FILE_MAGIC + ciphertext;
12823 }
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
void skGen(key &sk)
Definition: rctOps.cpp:253
uint64_t combinations_count(uint32_t k, uint32_t n)
Definition: combinator.cpp:35
#define MULTISIG_EXPORT_FILE_MAGIC
Definition: wallet2.cpp:124
Here is the call 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 12503 of file wallet2.cpp.

12504 {
12506  std::vector<tools::wallet2::transfer_details> outs;
12507 
12508  size_t offset = 0;
12509  if (!all)
12510  while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
12511  ++offset;
12512 
12513  outs.reserve(m_transfers.size() - offset);
12514  for (size_t n = offset; n < m_transfers.size(); ++n)
12515  {
12516  const transfer_details &td = m_transfers[n];
12517 
12518  outs.push_back(td);
12519  }
12520 
12521  return std::make_pair(offset, outs);
12522 }

◆ export_outputs_to_str()

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

Definition at line 12524 of file wallet2.cpp.

12525 {
12527 
12528  std::stringstream oss;
12530  const auto& outputs = export_outputs(all);
12531  ar << outputs;
12532 
12535  std::string header;
12536  header += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
12537  header += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
12538  PERF_TIMER(export_outputs_encryption);
12539  std::string ciphertext = encrypt_with_view_secret_key(header + oss.str());
12540  return magic + ciphertext;
12541 }
std::string export_outputs_to_str(bool all=false) const
Definition: wallet2.cpp:12524
#define OUTPUT_EXPORT_FILE_MAGIC
Definition: wallet2.cpp:139

◆ export_payments()

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

Definition at line 12445 of file wallet2.cpp.

12446 {
12447  payment_container payments;
12448  for (auto const &p : m_payments)
12449  {
12450  payments.emplace(p);
12451  }
12452  return payments;
12453 }
std::unordered_multimap< crypto::hash, payment_details > payment_container
Definition: wallet2.h:444

◆ 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 5366 of file wallet2.cpp.

5367 {
5368  bool ready;
5369  uint32_t threshold, total;
5370  if (!multisig(&ready, &threshold, &total))
5371  {
5372  MERROR("This is not a multisig wallet");
5373  return false;
5374  }
5375  if (ready)
5376  {
5377  MERROR("This multisig wallet is already finalized");
5378  return false;
5379  }
5380  if (threshold + 1 != total)
5381  {
5382  MERROR("finalize_multisig should only be used for N-1/N wallets, use exchange_multisig_keys instead");
5383  return false;
5384  }
5385  exchange_multisig_keys(password, pkeys, signers);
5386  return true;
5387 }
uint8_t threshold
Definition: blockchain.cpp:92

◆ 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 5406 of file wallet2.cpp.

5407 {
5408  std::unordered_set<crypto::public_key> public_keys;
5409  std::vector<crypto::public_key> signers;
5410  if (!unpack_extra_multisig_info(info, signers, public_keys))
5411  {
5412  MERROR("Bad multisig info");
5413  return false;
5414  }
5415 
5416  return finalize_multisig(password, public_keys, signers);
5417 }
bool finalize_multisig(const epee::wipeable_string &password, const std::vector< std::string > &info)
Finalizes creation of a multisig wallet.
Definition: wallet2.cpp:5406

◆ find_and_save_rings()

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

Definition at line 7899 of file wallet2.cpp.

7900 {
7901  if (!force && m_ring_history_saved)
7902  return true;
7903  if (!m_ringdb)
7904  return false;
7905 
7908 
7909  MDEBUG("Finding and saving rings...");
7910 
7911  // get payments we made
7912  std::vector<crypto::hash> txs_hashes;
7913  std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> payments;
7914  get_payments_out(payments, 0, std::numeric_limits<uint64_t>::max(), boost::none, std::set<uint32_t>());
7915  for (const std::pair<crypto::hash,wallet2::confirmed_transfer_details> &entry: payments)
7916  {
7917  const crypto::hash &txid = entry.first;
7918  txs_hashes.push_back(txid);
7919  }
7920 
7921  MDEBUG("Found " << std::to_string(txs_hashes.size()) << " transactions");
7922 
7923  // get those transactions from the daemon
7924  auto it = txs_hashes.begin();
7925  static const size_t SLICE_SIZE = 200;
7926  for (size_t slice = 0; slice < txs_hashes.size(); slice += SLICE_SIZE)
7927  {
7928  req.decode_as_json = false;
7929  req.prune = true;
7930  req.txs_hashes.clear();
7931  size_t ntxes = slice + SLICE_SIZE > txs_hashes.size() ? txs_hashes.size() - slice : SLICE_SIZE;
7932  for (size_t s = slice; s < slice + ntxes; ++s)
7933  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txs_hashes[s]));
7934  bool r;
7935  {
7936  const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
7937  r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
7938  }
7939  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
7940  THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
7941  THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
7942  THROW_WALLET_EXCEPTION_IF(res.txs.size() != req.txs_hashes.size(), error::wallet_internal_error,
7943  "daemon returned wrong response for gettransactions, wrong txs count = " +
7944  std::to_string(res.txs.size()) + ", expected " + std::to_string(req.txs_hashes.size()));
7945 
7946  MDEBUG("Scanning " << res.txs.size() << " transactions");
7947  THROW_WALLET_EXCEPTION_IF(slice + res.txs.size() > txs_hashes.size(), error::wallet_internal_error, "Unexpected tx array size");
7948  for (size_t i = 0; i < res.txs.size(); ++i, ++it)
7949  {
7950  const auto &tx_info = res.txs[i];
7952  crypto::hash tx_hash;
7953  THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(tx_info, tx, tx_hash), error::wallet_internal_error,
7954  "Failed to get transaction from daemon");
7955  THROW_WALLET_EXCEPTION_IF(!(tx_hash == *it), error::wallet_internal_error, "Wrong txid received");
7956  THROW_WALLET_EXCEPTION_IF(!add_rings(get_ringdb_key(), tx), error::wallet_internal_error, "Failed to save ring");
7957  }
7958  }
7959 
7960  MINFO("Found and saved rings for " << txs_hashes.size() << " transactions");
7961  m_ring_history_saved = true;
7962  return true;
7963 }
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:6236
Here is the call 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 13514 of file wallet2.cpp.

13515 {
13516  // Compute hash of m_transfers, if differs there had to be BC reorg.
13517  crypto::hash new_transfers_hash{};
13518  hash_m_transfers((int64_t) transfer_height, new_transfers_hash);
13519 
13520  if (new_transfers_hash != hash)
13521  {
13522  // Soft-Reset to avoid inconsistency in case of BC reorg.
13523  clear_soft(false); // keep_key_images works only with soft reset.
13524  THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Transfers changed during rescan, soft or hard rescan is needed");
13525  }
13526 
13527  // Restore key images in m_transfers from m_key_images
13528  for(auto it = m_key_images.begin(); it != m_key_images.end(); it++)
13529  {
13530  THROW_WALLET_EXCEPTION_IF(it->second >= m_transfers.size(), error::wallet_internal_error, "Key images cache contains illegal transfer offset");
13531  m_transfers[it->second].m_key_image = it->first;
13532  m_transfers[it->second].m_key_image_known = true;
13533  }
13534 }
uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const
Definition: wallet2.cpp:13490
signed __int64 int64_t
Definition: stdint.h:135

◆ freeze() [1/2]

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

Definition at line 1604 of file wallet2.cpp.

1605 {
1607 }
const transfer_details & get_transfer_details(size_t idx) const
Definition: wallet2.cpp:10642
Here is the call graph for this function:

◆ freeze() [2/2]

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

Definition at line 1583 of file wallet2.cpp.

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

◆ frozen() [1/3]

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

Definition at line 1614 of file wallet2.cpp.

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

◆ frozen() [2/3]

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

Definition at line 1630 of file wallet2.cpp.

1631 {
1632  return td.m_frozen;
1633 }

◆ frozen() [3/3]

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

Definition at line 1597 of file wallet2.cpp.

1598 {
1599  CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
1600  const transfer_details &td = m_transfers[idx];
1601  return td.m_frozen;
1602 }
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

Definition at line 4847 of file wallet2.cpp.

4849 {
4850  clear();
4851  prepare_file_names(wallet_);
4852 
4853  if (!wallet_.empty())
4854  {
4855  boost::system::error_code ignored_ec;
4856  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
4857  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
4858  }
4859 
4860  crypto::secret_key retval = m_account.generate(recovery_param, recover, two_random);
4861 
4862  init_type(hw::device::device_type::SOFTWARE);
4863  setup_keys(password);
4864 
4865  // calculate a starting refresh height
4866  if(m_refresh_from_block_height == 0 && !recover){
4867  m_refresh_from_block_height = estimate_blockchain_height();
4868  }
4869 
4870  create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
4871 
4872  setup_new_blockchain();
4873 
4874  if (!wallet_.empty())
4875  store();
4876 
4877  return retval;
4878 }
crypto::secret_key generate(const crypto::secret_key &recovery_key=crypto::secret_key(), bool recover=false, bool two_random=false)
Definition: account.cpp:158
uint64_t estimate_blockchain_height()
Definition: wallet2.cpp:4880
file_error_base< file_exists_message_index > file_exists

◆ 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

Definition at line 4967 of file wallet2.cpp.

4970 {
4971  clear();
4972  prepare_file_names(wallet_);
4973 
4974  if (!wallet_.empty())
4975  {
4976  boost::system::error_code ignored_ec;
4977  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
4978  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
4979  }
4980 
4981  m_account.create_from_keys(account_public_address, spendkey, viewkey);
4982  init_type(hw::device::device_type::SOFTWARE);
4983  m_account_public_address = account_public_address;
4984  setup_keys(password);
4985 
4986  create_keys_file(wallet_, false, password, create_address_file);
4987 
4988  setup_new_blockchain();
4989 
4990  if (!wallet_.empty())
4991  store();
4992 }
void create_from_keys(const cryptonote::account_public_address &address, const crypto::secret_key &spendkey, const crypto::secret_key &viewkey)
Definition: account.cpp:189
const char * spendkey
Definition: multisig.cpp:38

◆ 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

Definition at line 4930 of file wallet2.cpp.

4933 {
4934  clear();
4935  prepare_file_names(wallet_);
4936 
4937  if (!wallet_.empty())
4938  {
4939  boost::system::error_code ignored_ec;
4940  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
4941  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
4942  }
4943 
4944  m_account.create_from_viewkey(account_public_address, viewkey);
4945  init_type(hw::device::device_type::SOFTWARE);
4946  m_watch_only = true;
4947  m_account_public_address = account_public_address;
4948  setup_keys(password);
4949 
4950  create_keys_file(wallet_, true, password, m_nettype != MAINNET || create_address_file);
4951 
4952  setup_new_blockchain();
4953 
4954  if (!wallet_.empty())
4955  store();
4956 }
void create_from_viewkey(const cryptonote::account_public_address &address, const crypto::secret_key &viewkey)
Definition: account.cpp:243

◆ 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 4759 of file wallet2.cpp.

4761 {
4762  clear();
4763  prepare_file_names(wallet_);
4764 
4765  if (!wallet_.empty())
4766  {
4767  boost::system::error_code ignored_ec;
4768  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
4769  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
4770  }
4771 
4772  m_account.generate(rct::rct2sk(rct::zero()), true, false);
4773 
4774  THROW_WALLET_EXCEPTION_IF(multisig_data.size() < 32, error::invalid_multisig_seed);
4775  size_t offset = 0;
4776  uint32_t threshold = *(uint32_t*)(multisig_data.data() + offset);
4777  offset += sizeof(uint32_t);
4778  uint32_t total = *(uint32_t*)(multisig_data.data() + offset);
4779  offset += sizeof(uint32_t);
4780  THROW_WALLET_EXCEPTION_IF(threshold < 2, error::invalid_multisig_seed);
4781  THROW_WALLET_EXCEPTION_IF(total != threshold && total != threshold + 1, error::invalid_multisig_seed);
4782  const size_t n_multisig_keys = total == threshold ? 1 : threshold;
4783  THROW_WALLET_EXCEPTION_IF(multisig_data.size() != 8 + 32 * (4 + n_multisig_keys + total), error::invalid_multisig_seed);
4784 
4785  std::vector<crypto::secret_key> multisig_keys;
4786  std::vector<crypto::public_key> multisig_signers;
4787  crypto::secret_key spend_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset);
4788  offset += sizeof(crypto::secret_key);
4789  crypto::public_key spend_public_key = *(crypto::public_key*)(multisig_data.data() + offset);
4790  offset += sizeof(crypto::public_key);
4791  crypto::secret_key view_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset);
4792  offset += sizeof(crypto::secret_key);
4793  crypto::public_key view_public_key = *(crypto::public_key*)(multisig_data.data() + offset);
4794  offset += sizeof(crypto::public_key);
4795  for (size_t n = 0; n < n_multisig_keys; ++n)
4796  {
4797  multisig_keys.push_back(*(crypto::secret_key*)(multisig_data.data() + offset));
4798  offset += sizeof(crypto::secret_key);
4799  }
4800  for (size_t n = 0; n < total; ++n)
4801  {
4802  multisig_signers.push_back(*(crypto::public_key*)(multisig_data.data() + offset));
4803  offset += sizeof(crypto::public_key);
4804  }
4805 
4806  crypto::public_key calculated_view_public_key;
4807  THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(view_secret_key, calculated_view_public_key), error::invalid_multisig_seed);
4808  THROW_WALLET_EXCEPTION_IF(view_public_key != calculated_view_public_key, error::invalid_multisig_seed);
4809  crypto::public_key local_signer;
4810  THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(spend_secret_key, local_signer), error::invalid_multisig_seed);
4811  THROW_WALLET_EXCEPTION_IF(std::find(multisig_signers.begin(), multisig_signers.end(), local_signer) == multisig_signers.end(), error::invalid_multisig_seed);
4812  rct::key skey = rct::zero();
4813  for (const auto &msk: multisig_keys)
4814  sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes);
4815  THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed);
4816  memwipe(&skey, sizeof(rct::key));
4817 
4818  m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys);
4819  m_account.finalize_multisig(spend_public_key);
4820 
4821  // Not possible to restore a multisig wallet that is able to activate the MMS
4822  // (because the original keys are not (yet) part of the restore info), so
4823  // keep m_original_keys_available to false
4824  init_type(hw::device::device_type::SOFTWARE);
4825  m_multisig = true;
4826  m_multisig_threshold = threshold;
4827  m_multisig_signers = multisig_signers;
4828  setup_keys(password);
4829 
4830  create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
4831  setup_new_blockchain();
4832 
4833  if (!wallet_.empty())
4834  store();
4835 }
void sc_add(unsigned char *, const unsigned char *, const unsigned char *)
epee::mlocked< tools::scrubbed< ec_scalar > > secret_key
Definition: crypto.h:82
key zero()
Definition: rctOps.h:70
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 728 of file wallet2.h.

728 {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 729 of file wallet2.h.

729 {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 11826 of file wallet2.cpp.

11827 {
11828  // ensure consistency
11829  if (m_account_tags.second.size() != get_num_subaddress_accounts())
11830  m_account_tags.second.resize(get_num_subaddress_accounts(), "");
11831  for (const std::string& tag : m_account_tags.second)
11832  {
11833  if (!tag.empty() && m_account_tags.first.count(tag) == 0)
11834  m_account_tags.first.insert({tag, ""});
11835  }
11836  for (auto i = m_account_tags.first.begin(); i != m_account_tags.first.end(); )
11837  {
11838  if (std::find(m_account_tags.second.begin(), m_account_tags.second.end(), i->first) == m_account_tags.second.end())
11839  i = m_account_tags.first.erase(i);
11840  else
11841  ++i;
11842  }
11843  return m_account_tags;
11844 }
Here is the caller graph for this function:

◆ get_address()

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

Definition at line 787 of file wallet2.h.

787 { 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 792 of file wallet2.h.

792 { return get_subaddress_as_str({0, 0}); }
std::string get_subaddress_as_str(const cryptonote::subaddress_index &index) const
Definition: wallet2.cpp:1451
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 1142 of file wallet2.h.

1142 { 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 11755 of file wallet2.cpp.

11756 {
11757  // time of v2 fork
11758  const time_t fork_time = m_nettype == TESTNET ? 1341378000 : m_nettype == STAGENET ? 1521000000 : 1538815057;
11759  // v2 fork block
11760  const uint64_t fork_block = m_nettype == TESTNET ? 190060 : m_nettype == STAGENET ? 32000 : 307500;
11761  // avg seconds per block
11762  const int seconds_per_block = DIFFICULTY_TARGET_V6;
11763  // Calculated blockchain height
11764  uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
11765  // testnet got some huge rollbacks, so the estimation is way off
11766  static const uint64_t approximate_testnet_rolled_back_blocks = 303967;
11767  if (m_nettype == TESTNET && approx_blockchain_height > approximate_testnet_rolled_back_blocks)
11768  approx_blockchain_height -= approximate_testnet_rolled_back_blocks;
11769  // estiamte blocks from v6
11770  if(m_nettype == MAINNET) {
11771  approx_blockchain_height += 82000;
11772  }
11773  LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
11774  return approx_blockchain_height;
11775 }

◆ get_attribute()

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

Definition at line 11808 of file wallet2.cpp.

11809 {
11810  std::unordered_map<std::string, std::string>::const_iterator i = m_attributes.find(key);
11811  if (i == m_attributes.end())
11812  return std::string();
11813  return i->second;
11814 }

◆ get_base_fee()

uint64_t tools::wallet2::get_base_fee ( ) const

Definition at line 7584 of file wallet2.cpp.

7585 {
7586  if(m_light_wallet)
7587  {
7589  return m_light_wallet_per_kb_fee / 1024;
7590  else
7591  return m_light_wallet_per_kb_fee;
7592  }
7593  bool use_dyn_fee = use_fork_rules(HF_VERSION_DYNAMIC_FEE, -720 * 1);
7594  if (!use_dyn_fee)
7595  return FEE_PER_KB_V6;
7596 
7597  return get_dynamic_base_fee_estimate();
7598 }
#define HF_VERSION_DYNAMIC_FEE
#define FEE_PER_KB_V6

◆ get_blockchain_current_height()

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

Definition at line 890 of file wallet2.h.

890 { 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 13173 of file wallet2.cpp.

13174 {
13175  uint32_t version;
13176  if (!check_connection(&version))
13177  {
13178  throw std::runtime_error("failed to connect to daemon: " + get_daemon_address());
13179  }
13180  if (version < MAKE_CORE_RPC_VERSION(1, 6))
13181  {
13182  throw std::runtime_error("this function requires RPC version 1.6 or higher");
13183  }
13184  std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 };
13185  date.tm_year = year - 1900;
13186  date.tm_mon = month - 1;
13187  date.tm_mday = day;
13188  if (date.tm_mon < 0 || 11 < date.tm_mon || date.tm_mday < 1 || 31 < date.tm_mday)
13189  {
13190  throw std::runtime_error("month or day out of range");
13191  }
13192  uint64_t timestamp_target = std::mktime(&date);
13193  std::string err;
13194  uint64_t height_min = 0;
13195  uint64_t height_max = get_daemon_blockchain_height(err) - 1;
13196  if (!err.empty())
13197  {
13198  throw std::runtime_error("failed to get blockchain height");
13199  }
13200  while (true)
13201  {
13204  uint64_t height_mid = (height_min + height_max) / 2;
13205  req.heights =
13206  {
13207  height_min,
13208  height_mid,
13209  height_max
13210  };
13211  bool r = invoke_http_bin("/getblocks_by_height.bin", req, res, rpc_timeout);
13212  if (!r || res.status != CORE_RPC_STATUS_OK)
13213  {
13214  std::ostringstream oss;
13215  oss << "failed to get blocks by heights: ";
13216  for (auto height : req.heights)
13217  oss << height << ' ';
13218  oss << endl << "reason: ";
13219  if (!r)
13220  oss << "possibly lost connection to daemon";
13221  else if (res.status == CORE_RPC_STATUS_BUSY)
13222  oss << "daemon is busy";
13223  else
13224  oss << get_rpc_status(res.status);
13225  throw std::runtime_error(oss.str());
13226  }
13227  cryptonote::block blk_min, blk_mid, blk_max;
13228  if (res.blocks.size() < 3) throw std::runtime_error("Not enough blocks returned from daemon");
13229  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));
13230  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));
13231  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));
13232  uint64_t timestamp_min = blk_min.timestamp;
13233  uint64_t timestamp_mid = blk_mid.timestamp;
13234  uint64_t timestamp_max = blk_max.timestamp;
13235  if (!(timestamp_min <= timestamp_mid && timestamp_mid <= timestamp_max))
13236  {
13237  // the timestamps are not in the chronological order.
13238  // assuming they're sufficiently close to each other, simply return the smallest height
13239  return std::min({height_min, height_mid, height_max});
13240  }
13241  if (timestamp_target > timestamp_max)
13242  {
13243  throw std::runtime_error("specified date is in the future");
13244  }
13245  if (timestamp_target <= timestamp_min + 2 * 24 * 60 * 60) // two days of "buffer" period
13246  {
13247  return height_min;
13248  }
13249  if (timestamp_target <= timestamp_mid)
13250  height_max = height_mid;
13251  else
13252  height_min = height_mid;
13253  if (height_max - height_min <= 2 * 24 * 30) // don't divide the height range finer than two days
13254  {
13255  return height_min;
13256  }
13257  }
13258 }
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
Here is the call graph for this function:

◆ get_bytes_received()

uint64_t tools::wallet2::get_bytes_received ( ) const

Definition at line 13541 of file wallet2.cpp.

13542 {
13543  return m_http_client.get_bytes_received();
13544 }

◆ get_bytes_sent()

uint64_t tools::wallet2::get_bytes_sent ( ) const

Definition at line 13536 of file wallet2.cpp.

13537 {
13538  return m_http_client.get_bytes_sent();
13539 }

◆ get_confirm_backlog_threshold()

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

Definition at line 1082 of file wallet2.h.

1082 { return m_confirm_backlog_threshold; };

◆ get_daemon_address()

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

Definition at line 11716 of file wallet2.cpp.

11717 {
11718  return m_daemon_address;
11719 }
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 11721 of file wallet2.cpp.

11722 {
11723  uint64_t height;
11724 
11725  boost::optional<std::string> result = m_node_rpc_proxy.get_height(height);
11726  if (result)
11727  {
11728  if (m_trusted_daemon)
11729  err = *result;
11730  else
11731  err = "daemon error";
11732  return 0;
11733  }
11734 
11735  err = "";
11736  return height;
11737 }
boost::optional< std::string > get_height(uint64_t &height) const

◆ get_daemon_blockchain_target_height()

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

Definition at line 11739 of file wallet2.cpp.

11740 {
11741  err = "";
11742  uint64_t target_height = 0;
11743  const auto result = m_node_rpc_proxy.get_target_height(target_height);
11744  if (result && *result != CORE_RPC_STATUS_OK)
11745  {
11746  if (m_trusted_daemon)
11747  err = *result;
11748  else
11749  err = "daemon error";
11750  return 0;
11751  }
11752  return target_height;
11753 }
boost::optional< std::string > get_target_height(uint64_t &height) const

◆ get_daemon_login()

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

Definition at line 1157 of file wallet2.h.

1157 { 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 1065 of file wallet2.h.

1065 { return m_default_priority; }

◆ get_description()

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

Definition at line 11821 of file wallet2.cpp.

11822 {
11824 }
std::string get_attribute(const std::string &key) const
Definition: wallet2.cpp:11808
const char *const ATTRIBUTE_DESCRIPTION
Definition: wallet2.h:1301

◆ get_device_last_key_image_sync()

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

Definition at line 899 of file wallet2.h.

899 { return m_device_last_key_image_sync; }

◆ get_device_type()

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

Definition at line 825 of file wallet2.h.

825 { 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 7617 of file wallet2.cpp.

7618 {
7619  // changes at v3, v5, v8
7620  if (use_fork_rules(6, 0))
7621  return 3;
7622  if (use_fork_rules(5, 0))
7623  return 2;
7624  if (use_fork_rules(3, -720 * 14))
7625  return 1;
7626  return 0;
7627 }

◆ get_fee_multiplier()

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

Definition at line 7531 of file wallet2.cpp.

7532 {
7533  static const struct
7534  {
7535  size_t count;
7536  uint64_t multipliers[4];
7537  }
7538  multipliers[] =
7539  {
7540  { 3, {1, 2, 3} },
7541  { 3, {1, 20, 166} },
7542  { 4, {1, 4, 20, 166} },
7543  { 4, {1, 2, 4, 8} },
7544  };
7545 
7546  if (fee_algorithm == -1)
7547  fee_algorithm = get_fee_algorithm();
7548 
7549  // 0 -> default (here, x1 till fee algorithm 2, x4 from it)
7550  if (priority == 0)
7551  priority = m_default_priority;
7552  if (priority == 0)
7553  {
7554  if (fee_algorithm == 2)
7555  priority = 2;
7556  else
7557  priority = 1;
7558  }
7559 
7560  THROW_WALLET_EXCEPTION_IF(fee_algorithm < 0 || fee_algorithm > 4, error::invalid_priority);
7561 
7562  // 1 to 3/4 are allowed as priorities
7563  const uint32_t max_priority = multipliers[fee_algorithm].count;
7564  if (priority >= 1 && priority <= max_priority)
7565  {
7566  return multipliers[fee_algorithm].multipliers[priority-1];
7567  }
7568 
7569  THROW_WALLET_EXCEPTION_IF (false, error::invalid_priority);
7570  return 1;
7571 }
mdb_size_t count(MDB_cursor *cur)
Here is the call graph for this function:

◆ get_fee_quantization_mask()

uint64_t tools::wallet2::get_fee_quantization_mask ( ) const

Definition at line 7600 of file wallet2.cpp.

7601 {
7602  if(m_light_wallet)
7603  {
7604  return 1; // TODO
7605  }
7606  bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
7607  if (!use_per_byte_fee)
7608  return 1;
7609 
7610  uint64_t fee_quantization_mask;
7611  boost::optional<std::string> result = m_node_rpc_proxy.get_fee_quantization_mask(fee_quantization_mask);
7612  if (result)
7613  return 1;
7614  return fee_quantization_mask;
7615 }
boost::optional< std::string > get_fee_quantization_mask(uint64_t &fee_quantization_mask) const

◆ get_hard_fork_info()

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

Definition at line 10504 of file wallet2.cpp.

10505 {
10506  boost::optional<std::string> result = m_node_rpc_proxy.get_earliest_height(version, earliest_height);
10507  throw_on_rpc_response_error(result, "get_hard_fork_info");
10508 }
boost::optional< std::string > get_earliest_height(uint8_t version, uint64_t &earliest_height) const

◆ get_human_readable_timestamp()

static 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 1031 of file wallet2.h.

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

◆ get_integrated_address_as_str()

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

Definition at line 1457 of file wallet2.cpp.

1458 {
1459  return cryptonote::get_account_integrated_address_as_str(m_nettype, get_address(), payment_id);
1460 }
cryptonote::account_public_address get_address() const
Definition: wallet2.h:787
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 11711 of file wallet2.cpp.

11712 {
11713  return m_keys_file;
11714 }

◆ get_last_block_reward()

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

Definition at line 898 of file wallet2.h.

898 { return m_last_block_reward; }

◆ get_light_wallet_blockchain_height()

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

Definition at line 774 of file wallet2.h.

774 { 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 773 of file wallet2.h.

773 { return m_light_wallet_scanned_block_height; }

◆ get_max_ring_size()

uint64_t tools::wallet2::get_max_ring_size ( ) const

Definition at line 7644 of file wallet2.cpp.

7645 {
7647  return 11;
7649  return 1;
7650  return 0;
7651 }
#define HF_VERSION_ENFORCE_0_DECOY_TXS
#define HF_VERSION_MAX_RING_11

◆ get_message_store() [1/2]

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

Definition at line 1359 of file wallet2.h.

1359 { return m_message_store; };

◆ get_message_store() [2/2]

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

Definition at line 1360 of file wallet2.h.

1360 { return m_message_store; };

◆ get_min_output_count()

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

Definition at line 1074 of file wallet2.h.

1074 { return m_min_output_count; }

◆ get_min_output_value()

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

Definition at line 1076 of file wallet2.h.

1076 { return m_min_output_value; }

◆ get_min_ring_size()

uint64_t tools::wallet2::get_min_ring_size ( ) const

Definition at line 7629 of file wallet2.cpp.

7630 {
7632  return 11;
7634  return 7;
7636  return 5;
7638  return 1;
7640  return 3;
7641  return 0;
7642 }
#define HF_VERSION_MIN_MIXIN_6
#define HF_VERSION_MIN_MIXIN_2
#define HF_VERSION_MIN_MIXIN_10
#define HF_VERSION_MIN_MIXIN_4

◆ get_multisig_info()

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

Get a packaged multisig information string

Definition at line 5419 of file wallet2.cpp.

5420 {
5421  // It's a signed package of private view key and public spend key
5422  const crypto::secret_key skey = cryptonote::get_multisig_blinded_secret_key(get_account().get_keys().m_view_secret_key);
5423  const crypto::public_key pkey = get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key);
5425 
5426  std::string data;
5427  data += std::string((const char *)&skey, sizeof(crypto::secret_key));
5428  data += std::string((const char *)&pkey, sizeof(crypto::public_key));
5429 
5430  data.resize(data.size() + sizeof(crypto::signature));
5431  crypto::cn_fast_hash(data.data(), data.size() - sizeof(signature), hash);
5432  crypto::signature &signature = *(crypto::signature*)&data[data.size() - sizeof(crypto::signature)];
5433  crypto::generate_signature(hash, pkey, get_multisig_blinded_secret_key(get_account().get_keys().m_spend_secret_key), signature);
5434 
5435  return std::string("MultisigV1") + tools::base58::encode(data);
5436 }
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:

◆ 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 1326 of file wallet2.cpp.

1327 {
1328  bool ready;
1329  uint32_t threshold, total;
1330  if (!multisig(&ready, &threshold, &total))
1331  {
1332  std::cout << "This is not a multisig wallet" << std::endl;
1333  return false;
1334  }
1335  if (!ready)
1336  {
1337  std::cout << "This multisig wallet is not yet finalized" << std::endl;
1338  return false;
1339  }
1340  if (!raw && seed_language.empty())
1341  {
1342  std::cout << "seed_language not set" << std::endl;
1343  return false;
1344  }
1345 
1346  crypto::secret_key skey;
1347  crypto::public_key pkey;
1348  const account_keys &keys = get_account().get_keys();
1349  epee::wipeable_string data;
1350  data.append((const char*)&threshold, sizeof(uint32_t));
1351  data.append((const char*)&total, sizeof(uint32_t));
1352  skey = keys.m_spend_secret_key;
1353  data.append((const char*)&skey, sizeof(skey));
1355  data.append((const char*)&pkey, sizeof(pkey));
1356  skey = keys.m_view_secret_key;
1357  data.append((const char*)&skey, sizeof(skey));
1359  data.append((const char*)&pkey, sizeof(pkey));
1360  for (const auto &skey: keys.m_multisig_keys)
1361  data.append((const char*)&skey, sizeof(skey));
1362  for (const auto &signer: m_multisig_signers)
1363  data.append((const char*)&signer, sizeof(signer));
1364 
1365  if (!passphrase.empty())
1366  {
1368  crypto::cn_slow_hash(passphrase.data(), passphrase.size(), (crypto::hash&)key);
1369  sc_reduce32((unsigned char*)key.data);
1370  data = encrypt(data, key, true);
1371  }
1372 
1373  if (raw)
1374  {
1375  seed = epee::to_hex::wipeable_string({(const unsigned char*)data.data(), data.size()});
1376  }
1377  else
1378  {
1379  if (!crypto::ElectrumWords::bytes_to_words(data.data(), data.size(), seed, seed_language))
1380  {
1381  std::cout << "Failed to encode seed";
1382  return false;
1383  }
1384  }
1385 
1386  return true;
1387 }
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, std::size_t length, hash &hash, int variant=0, uint64_t height=0)
Definition: hash.h:79
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 12678 of file wallet2.cpp.

12679 {
12680  CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12681  crypto::public_key signer;
12682  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");
12683  return signer;
12684 }
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 12671 of file wallet2.cpp.

12672 {
12673  crypto::public_key pkey;
12675  return pkey;
12676 }
Here is the call 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 12686 of file wallet2.cpp.

12687 {
12688  CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12689  crypto::public_key pkey;
12690  CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(msk, pkey), "Failed to derive public key");
12691  return pkey;
12692 }
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 12694 of file wallet2.cpp.

12695 {
12696  CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12697  CHECK_AND_ASSERT_THROW_MES(idx < get_account().get_multisig_keys().size(), "Multisig signing key index out of range");
12698  return get_multisig_signing_public_key(get_account().get_multisig_keys()[idx]);
12699 }
crypto::public_key get_multisig_signing_public_key(size_t idx) const
Definition: wallet2.cpp:12694

◆ get_multisig_wallet_state()

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

Definition at line 13395 of file wallet2.cpp.

13396 {
13398  state.nettype = m_nettype;
13399  state.multisig = multisig(&state.multisig_is_ready);
13400  state.has_multisig_partial_key_images = has_multisig_partial_key_images();
13401  state.multisig_rounds_passed = m_multisig_rounds_passed;
13402  state.num_transfer_details = m_transfers.size();
13403  if (state.multisig)
13404  {
13405  THROW_WALLET_EXCEPTION_IF(!m_original_keys_available, error::wallet_internal_error, "MMS use not possible because own original Electroneum address not available");
13406  state.address = m_original_address;
13407  state.view_secret_key = m_original_view_secret_key;
13408  }
13409  else
13410  {
13411  state.address = m_account.get_keys().m_account_address;
13412  state.view_secret_key = m_account.get_keys().m_view_secret_key;
13413  }
13414  state.mms_file=m_mms_file;
13415  return state;
13416 }
bool has_multisig_partial_key_images() const
Definition: wallet2.cpp:5537
Definition: blake256.h:37

◆ get_num_rct_outputs()

uint64_t tools::wallet2::get_num_rct_outputs ( )

Definition at line 10621 of file wallet2.cpp.

10622 {
10625  m_daemon_rpc_mutex.lock();
10626  req_t.amounts.push_back(0);
10627  req_t.min_count = 0;
10628  req_t.max_count = 0;
10629  req_t.unlocked = true;
10630  req_t.recent_cutoff = 0;
10631  bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
10632  m_daemon_rpc_mutex.unlock();
10633  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_num_rct_outputs");
10634  THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
10635  THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status);
10636  THROW_WALLET_EXCEPTION_IF(resp_t.histogram.size() != 1, error::get_histogram_error, "Expected exactly one response");
10637  THROW_WALLET_EXCEPTION_IF(resp_t.histogram[0].amount != 0, error::get_histogram_error, "Expected 0 amount");
10638 
10639  return resp_t.histogram[0].total_instances;
10640 }
Here is the call graph for this function:

◆ get_num_subaddress_accounts()

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

Definition at line 795 of file wallet2.h.

795 { 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 796 of file wallet2.h.

796 { 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 1147 of file wallet2.h.

1147 { 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 6210 of file wallet2.cpp.

6211 {
6212  auto range = m_payments.equal_range(payment_id);
6213  std::for_each(range.first, range.second, [&payments, &min_height, &subaddr_account, &subaddr_indices](const payment_container::value_type& x) {
6214  if (min_height < x.second.m_block_height &&
6215  (!subaddr_account || *subaddr_account == x.second.m_subaddr_index.major) &&
6216  (subaddr_indices.empty() || subaddr_indices.count(x.second.m_subaddr_index.minor) == 1))
6217  {
6218  payments.push_back(x.second);
6219  }
6220  });
6221 }

◆ 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 6223 of file wallet2.cpp.

6224 {
6225  auto range = std::make_pair(m_payments.begin(), m_payments.end());
6226  std::for_each(range.first, range.second, [&payments, &min_height, &max_height, &subaddr_account, &subaddr_indices](const payment_container::value_type& x) {
6227  if (min_height < x.second.m_block_height && max_height >= x.second.m_block_height &&
6228  (!subaddr_account || *subaddr_account == x.second.m_subaddr_index.major) &&
6229  (subaddr_indices.empty() || subaddr_indices.count(x.second.m_subaddr_index.minor) == 1))
6230  {
6231  payments.push_back(x);
6232  }
6233  });
6234 }

◆ 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 6236 of file wallet2.cpp.

6238 {
6239  for (auto i = m_confirmed_txs.begin(); i != m_confirmed_txs.end(); ++i) {
6240  if (i->second.m_block_height <= min_height || i->second.m_block_height > max_height)
6241  continue;
6242  if (subaddr_account && *subaddr_account != i->second.m_subaddr_account)
6243  continue;
6244  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)
6245  continue;
6246  if (i->second.m_is_migration)
6247  continue;
6248  confirmed_payments.push_back(*i);
6249  }
6250 }//----------------------------------------------------------------------------------------------------

◆ 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 6251 of file wallet2.cpp.

6253 {
6254  for (auto i = m_confirmed_txs.begin(); i != m_confirmed_txs.end(); ++i) {
6255  if (i->second.m_block_height <= min_height || i->second.m_block_height > max_height)
6256  continue;
6257  if (subaddr_account && *subaddr_account != i->second.m_subaddr_account)
6258  continue;
6259  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)
6260  continue;
6261  if (!i->second.m_is_migration)
6262  continue;
6263  confirmed_payments.push_back(*i);
6264  }
6265 }

◆ get_refresh_from_block_height()

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

Definition at line 737 of file wallet2.h.

737 {return m_refresh_from_block_height;}

◆ get_refresh_type()

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

Definition at line 816 of file wallet2.h.

816 { 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 11459 of file wallet2.cpp.

11460 {
11461  THROW_WALLET_EXCEPTION_IF(m_watch_only || m_multisig, error::wallet_internal_error, "Reserve proof can only be generated by a full wallet");
11462  THROW_WALLET_EXCEPTION_IF(balance_all(false) == 0, error::wallet_internal_error, "Zero balance");
11463  THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first, false) < account_minreserve->second, error::wallet_internal_error,
11464  "Not enough balance in this account for the requested minimum reserve amount");
11465 
11466  // determine which outputs to include in the proof
11467  std::vector<size_t> selected_transfers;
11468  for (size_t i = 0; i < m_transfers.size(); ++i)
11469  {
11470  const transfer_details &td = m_transfers[i];
11471  if (!td.m_spent && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
11472  selected_transfers.push_back(i);
11473  }
11474 
11475  if (account_minreserve)
11476  {
11477  THROW_WALLET_EXCEPTION_IF(account_minreserve->second == 0, error::wallet_internal_error, "Proved amount must be greater than 0");
11478  // minimize the number of outputs included in the proof, by only picking the N largest outputs that can cover the requested min reserve amount
11479  std::sort(selected_transfers.begin(), selected_transfers.end(), [&](const size_t a, const size_t b)
11480  { return m_transfers[a].amount() > m_transfers[b].amount(); });
11481  while (selected_transfers.size() >= 2 && m_transfers[selected_transfers[1]].amount() >= account_minreserve->second)
11482  selected_transfers.erase(selected_transfers.begin());
11483  size_t sz = 0;
11484  uint64_t total = 0;
11485  while (total < account_minreserve->second)
11486  {
11487  total += m_transfers[selected_transfers[sz]].amount();
11488  ++sz;
11489  }
11490  selected_transfers.resize(sz);
11491  }
11492 
11493  // compute signature prefix hash
11494  std::string prefix_data = message;
11495  prefix_data.append((const char*)&m_account.get_keys().m_account_address, sizeof(cryptonote::account_public_address));
11496  for (size_t i = 0; i < selected_transfers.size(); ++i)
11497  {
11498  prefix_data.append((const char*)&m_transfers[selected_transfers[i]].m_key_image, sizeof(crypto::key_image));
11499  }
11500  crypto::hash prefix_hash;
11501  crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11502 
11503  // generate proof entries
11504  std::vector<reserve_proof_entry> proofs(selected_transfers.size());
11505  std::unordered_set<cryptonote::subaddress_index> subaddr_indices = { {0,0} };
11506  for (size_t i = 0; i < selected_transfers.size(); ++i)
11507  {
11508  transfer_details &td = m_transfers[selected_transfers[i]];
11509  reserve_proof_entry& proof = proofs[i];
11510  proof.txid = td.m_txid;
11511  proof.index_in_tx = td.m_internal_output_index;
11512  proof.key_image = td.m_key_image;
11513  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};
11514  td.m_subaddr_index = index2;
11515  subaddr_indices.insert(td.m_subaddr_index);
11516 
11517  // get tx pub key
11518  const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
11519  THROW_WALLET_EXCEPTION_IF(tx_pub_key == crypto::null_pkey, error::wallet_internal_error, "The tx public key isn't found");
11520  const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
11521 
11522  // determine which tx pub key was used for deriving the output key
11523  const crypto::public_key *tx_pub_key_used = &tx_pub_key;
11524  for (int i = 0; i < 2; ++i)
11525  {
11526  proof.shared_secret = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(*tx_pub_key_used), rct::sk2rct(m_account.get_keys().m_view_secret_key)));
11527  crypto::key_derivation derivation;
11528  THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(proof.shared_secret, rct::rct2sk(rct::I), derivation),
11529  error::wallet_internal_error, "Failed to generate key derivation");
11530  crypto::public_key subaddress_spendkey;
11531  THROW_WALLET_EXCEPTION_IF(!derive_subaddress_public_key(td.get_public_key(), derivation, proof.index_in_tx, subaddress_spendkey),
11532  error::wallet_internal_error, "Failed to derive subaddress public key");
11533  if (m_subaddresses.count(subaddress_spendkey) == 1)
11534  break;
11535  THROW_WALLET_EXCEPTION_IF(additional_tx_pub_keys.empty(), error::wallet_internal_error,
11536  "Normal tx pub key doesn't derive the expected output, while the additional tx pub keys are empty");
11537  THROW_WALLET_EXCEPTION_IF(i == 1, error::wallet_internal_error,
11538  "Neither normal tx pub key nor additional tx pub key derive the expected output key");
11539  tx_pub_key_used = &additional_tx_pub_keys[proof.index_in_tx];
11540  }
11541 
11542  // generate signature for shared secret
11543  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);
11544 
11545  // derive ephemeral secret key
11546  crypto::key_image ki;
11547  cryptonote::keypair ephemeral;
11548  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);
11549  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
11550  THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one");
11551 
11552  // generate signature for key image
11553  const std::vector<const crypto::public_key*> pubs = { &ephemeral.pub };
11554  crypto::generate_ring_signature(prefix_hash, td.m_key_image, &pubs[0], 1, ephemeral.sec, 0, &proof.key_image_sig);
11555  }
11556 
11557  // collect all subaddress spend keys that received those outputs and generate their signatures
11558  std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
11559  for (const cryptonote::subaddress_index &index : subaddr_indices)
11560  {
11561  crypto::secret_key subaddr_spend_skey = m_account.get_keys().m_spend_secret_key;
11562  if (!index.is_zero())
11563  {
11565  crypto::secret_key tmp = subaddr_spend_skey;
11566  sc_add((unsigned char*)&subaddr_spend_skey, (unsigned char*)&m, (unsigned char*)&tmp);
11567  }
11568  crypto::public_key subaddr_spend_pkey;
11569  secret_key_to_public_key(subaddr_spend_skey, subaddr_spend_pkey);
11570  crypto::generate_signature(prefix_hash, subaddr_spend_pkey, subaddr_spend_skey, subaddr_spendkeys[subaddr_spend_pkey]);
11571  }
11572 
11573  // serialize & encode
11574  std::ostringstream oss;
11576  ar << proofs << subaddr_spendkeys;
11577  return "ReserveProofV1" + tools::base58::encode(oss.str());
11578 }
virtual crypto::secret_key get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index)=0
uint64_t balance_all(bool public_blockchain) const
Definition: wallet2.cpp:6182
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:309
void scalarmultKey(key &aP, const key &P, const key &a)
Definition: rctOps.cpp:368
Here is the call 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 7847 of file wallet2.cpp.

7848 {
7849  try { return get_ring(get_ringdb_key(), key_image, outs); }
7850  catch (const std::exception &e) { return false; }
7851 }
bool get_ring(const crypto::key_image &key_image, std::vector< uint64_t > &outs)
Definition: wallet2.cpp:7847

◆ get_ring_database()

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

Definition at line 1333 of file wallet2.h.

1333 { 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 7824 of file wallet2.cpp.

7825 {
7826  for (auto i: m_confirmed_txs)
7827  {
7828  if (txid == i.first)
7829  {
7830  for (const auto &x: i.second.m_rings)
7831  outs.push_back({x.first, cryptonote::relative_output_offsets_to_absolute(x.second)});
7832  return true;
7833  }
7834  }
7835  for (auto i: m_unconfirmed_txs)
7836  {
7837  if (txid == i.first)
7838  {
7839  for (const auto &x: i.second.m_rings)
7840  outs.push_back({x.first, cryptonote::relative_output_offsets_to_absolute(x.second)});
7841  return true;
7842  }
7843  }
7844  return false;
7845 }
Here is the call 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 1300 of file wallet2.cpp.

1301 {
1302  bool keys_deterministic = is_deterministic();
1303  if (!keys_deterministic)
1304  {
1305  std::cout << "This is not a deterministic wallet" << std::endl;
1306  return false;
1307  }
1308  if (seed_language.empty())
1309  {
1310  std::cout << "seed_language not set" << std::endl;
1311  return false;
1312  }
1313 
1315  if (!passphrase.empty())
1316  key = cryptonote::encrypt_key(key, passphrase);
1317  if (!crypto::ElectrumWords::bytes_to_words(key, electrum_words, seed_language))
1318  {
1319  std::cout << "Failed to create seed from key for language: " << seed_language << std::endl;
1320  return false;
1321  }
1322 
1323  return true;
1324 }
bool is_deterministic() const
Checks if deterministic wallet.
Definition: wallet2.cpp:1292
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 1416 of file wallet2.cpp.

1417 {
1418  return seed_language;
1419 }

◆ get_spend_proof()

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

Definition at line 10837 of file wallet2.cpp.

10838 {
10839  THROW_WALLET_EXCEPTION_IF(m_watch_only, error::wallet_internal_error,
10840  "get_spend_proof requires spend secret key and is not available for a watch-only wallet");
10841 
10842  // fetch tx from daemon
10844  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
10845  req.decode_as_json = false;
10846  req.prune = true;
10848  bool r;
10849  {
10850  const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
10851  r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
10852  }
10853  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
10854  THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
10855  THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
10856  THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
10857  "daemon returned wrong response for gettransactions, wrong txs count = " +
10858  std::to_string(res.txs.size()) + ", expected 1");
10859 
10861  crypto::hash tx_hash;
10862  THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(res.txs[0], tx, tx_hash), error::wallet_internal_error, "Failed to get tx from daemon");
10863 
10864  std::vector<std::vector<crypto::signature>> signatures;
10865 
10866  // get signature prefix hash
10867  std::string sig_prefix_data((const char*)&txid, sizeof(crypto::hash));
10868  sig_prefix_data += message;
10869  crypto::hash sig_prefix_hash;
10870  crypto::cn_fast_hash(sig_prefix_data.data(), sig_prefix_data.size(), sig_prefix_hash);
10871 
10872  for(size_t i = 0; i < tx.vin.size(); ++i)
10873  {
10874  const txin_to_key* const in_key = boost::get<txin_to_key>(std::addressof(tx.vin[i]));
10875  if (in_key == nullptr)
10876  continue;
10877 
10878  // check if the key image belongs to us
10879  const auto found = m_key_images.find(in_key->k_image);
10880  if(found == m_key_images.end())
10881  {
10882  THROW_WALLET_EXCEPTION_IF(i > 0, error::wallet_internal_error, "subset of key images belong to us, very weird!");
10883  THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "This tx wasn't generated by this wallet!");
10884  }
10885 
10886  // derive the real output keypair
10887  const transfer_details& in_td = m_transfers[found->second];
10888  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));
10889  THROW_WALLET_EXCEPTION_IF(in_tx_out_pkey == nullptr, error::wallet_internal_error, "Output is not txout_to_key");
10890  const crypto::public_key in_tx_pub_key = get_tx_pub_key_from_extra(in_td.m_tx, in_td.m_pk_index);
10891  const std::vector<crypto::public_key> in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx);
10892  keypair in_ephemeral;
10893  crypto::key_image in_img;
10894  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),
10895  error::wallet_internal_error, "failed to generate key image");
10896  THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch");
10897 
10898  // get output pubkeys in the ring
10899  const std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key->key_offsets);
10900  const size_t ring_size = in_key->key_offsets.size();
10901  THROW_WALLET_EXCEPTION_IF(absolute_offsets.size() != ring_size, error::wallet_internal_error, "absolute offsets size is wrong");
10903  req.outputs.resize(ring_size);
10904  for (size_t j = 0; j < ring_size; ++j)
10905  {
10906  req.outputs[j].amount = in_key->amount;
10907  req.outputs[j].index = absolute_offsets[j];
10908  }
10910  bool r;
10911  {
10912  const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
10913  r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
10914  }
10915  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
10916  THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
10917  THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "get_outs.bin");
10918  THROW_WALLET_EXCEPTION_IF(res.outs.size() != ring_size, error::wallet_internal_error,
10919  "daemon returned wrong response for get_outs.bin, wrong amounts count = " +
10920  std::to_string(res.outs.size()) + ", expected " + std::to_string(ring_size));
10921 
10922  // copy pubkey pointers
10923  std::vector<const crypto::public_key *> p_output_keys;
10924  for (const COMMAND_RPC_GET_OUTPUTS_BIN::outkey &out : res.outs)
10925  p_output_keys.push_back(&out.key);
10926 
10927  // figure out real output index and secret key
10928  size_t sec_index = -1;
10929  for (size_t j = 0; j < ring_size; ++j)
10930  {
10931  if (res.outs[j].key == in_ephemeral.pub)
10932  {
10933  sec_index = j;
10934  break;
10935  }
10936  }
10937  THROW_WALLET_EXCEPTION_IF(sec_index >= ring_size, error::wallet_internal_error, "secret index not found");
10938 
10939  // generate ring sig for this input
10940  signatures.push_back(std::vector<crypto::signature>());
10941  std::vector<crypto::signature>& sigs = signatures.back();
10942  sigs.resize(in_key->key_offsets.size());
10943  crypto::generate_ring_signature(sig_prefix_hash, in_key->k_image, p_output_keys, in_ephemeral.sec, sec_index, sigs.data());
10944  }
10945 
10946  std::string sig_str = "SpendProofV1";
10947  for (const std::vector<crypto::signature>& ring_sig : signatures)
10948  for (const crypto::signature& sig : ring_sig)
10949  sig_str += tools::base58::encode(std::string((const char *)&sig, sizeof(crypto::signature)));
10950  return sig_str;
10951 }
Here is the call graph for this function:

◆ get_subaddress()

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

Definition at line 1429 of file wallet2.cpp.

1430 {
1431  hw::device &hwdev = m_account.get_device();
1432  cryptonote::subaddress_index index2 = {index.major + (index.major != 0 ? m_account_major_offset : 0), index.minor};
1433  return hwdev.get_subaddress(m_account.get_keys(), index2);
1434 }
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 1451 of file wallet2.cpp.

1452 {
1454  return cryptonote::get_account_address_as_str(m_nettype, !index.is_zero(), address);
1455 }
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 1436 of file wallet2.cpp.

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

◆ get_subaddress_label()

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

Definition at line 1517 of file wallet2.cpp.

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

◆ get_subaddress_lookahead()

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

Definition at line 802 of file wallet2.h.

802 { 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 1444 of file wallet2.cpp.

1445 {
1446  hw::device &hwdev = m_account.get_device();
1447  cryptonote::subaddress_index index2 = {index.major + (index.major != 0 ? m_account_major_offset : 0), index.minor};
1448  return hwdev.get_subaddress_spend_public_key(m_account.get_keys(), index2);
1449 }
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

◆ get_transfer_details()

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

Definition at line 10642 of file wallet2.cpp.

10643 {
10644  THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Bad transfer index");
10645  return m_transfers[idx];
10646 }
Here is the caller graph for this function:

◆ get_transfers()

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

Definition at line 6205 of file wallet2.cpp.

6206 {
6207  incoming_transfers = m_transfers;
6208 }
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 11795 of file wallet2.cpp.

11796 {
11797  std::unordered_map<crypto::hash, std::string>::const_iterator i = m_tx_device.find(txid);
11798  if (i == m_tx_device.end())
11799  return std::string();
11800  return i->second;
11801 }

◆ 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 10714 of file wallet2.cpp.

10715 {
10716  bool r = get_tx_key_cached(txid, tx_key, additional_tx_keys);
10717  if (r)
10718  {
10719  return true;
10720  }
10721 
10722  auto & hwdev = get_account().get_device();
10723 
10724  // So far only Cold protocol devices are supported.
10725  if (hwdev.device_protocol() != hw::device::PROTOCOL_COLD)
10726  {
10727  return false;
10728  }
10729 
10730  const auto tx_data_it = m_tx_device.find(txid);
10731  if (tx_data_it == m_tx_device.end())
10732  {
10733  MDEBUG("Aux data not found for txid: " << txid);
10734  return false;
10735  }
10736 
10737  auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
10738  CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
10739  if (!dev_cold->is_get_tx_key_supported())
10740  {
10741  MDEBUG("get_tx_key not supported by the device");
10742  return false;
10743  }
10744 
10745  hw::device_cold::tx_key_data_t tx_key_data;
10746  dev_cold->load_tx_key_data(tx_key_data, tx_data_it->second);
10747 
10748  // Load missing tx prefix hash
10749  if (tx_key_data.tx_prefix_hash.empty())
10750  {
10753  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
10754  req.decode_as_json = false;
10755  req.prune = true;
10756  m_daemon_rpc_mutex.lock();
10757  bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
10758  m_daemon_rpc_mutex.unlock();
10759  THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
10760  error::wallet_internal_error, "Failed to get transaction from daemon");
10761 
10763  crypto::hash tx_hash{};
10764  cryptonote::blobdata tx_data;
10765  crypto::hash tx_prefix_hash{};
10766  ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
10767  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
10768  THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash),
10769  error::wallet_internal_error, "Failed to validate transaction from daemon");
10770  THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error,
10771  "Failed to get the right transaction from daemon");
10772 
10773  tx_key_data.tx_prefix_hash = std::string(tx_prefix_hash.data, 32);
10774  }
10775 
10776  std::vector<crypto::secret_key> tx_keys;
10777  dev_cold->get_tx_key(tx_keys, tx_key_data, m_account.get_keys().m_view_secret_key);
10778  if (tx_keys.empty())
10779  {
10780  return false;
10781  }
10782 
10783  tx_key = tx_keys[0];
10784  tx_keys.erase(tx_keys.begin());
10785  additional_tx_keys = tx_keys;
10786 
10787  return true;
10788 }
@ 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
Definition: wallet2.cpp:10701
Here is the call 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 10701 of file wallet2.cpp.

10702 {
10703  additional_tx_keys.clear();
10704  const std::unordered_map<crypto::hash, crypto::secret_key>::const_iterator i = m_tx_keys.find(txid);
10705  if (i == m_tx_keys.end())
10706  return false;
10707  tx_key = i->second;
10708  const auto j = m_additional_tx_keys.find(txid);
10709  if (j != m_additional_tx_keys.end())
10710  additional_tx_keys = j->second;
10711  return true;
10712 }

◆ get_tx_note()

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

Definition at line 11782 of file wallet2.cpp.

11783 {
11784  std::unordered_map<crypto::hash, std::string>::const_iterator i = m_tx_notes.find(txid);
11785  if (i == m_tx_notes.end())
11786  return std::string();
11787  return i->second;
11788 }

◆ 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 11161 of file wallet2.cpp.

11162 {
11163  // fetch tx pubkey from the daemon
11166  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
11167  req.decode_as_json = false;
11168  req.prune = true;
11169  m_daemon_rpc_mutex.lock();
11170  bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
11171  m_daemon_rpc_mutex.unlock();
11172  THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
11173  error::wallet_internal_error, "Failed to get transaction from daemon");
11174 
11176  crypto::hash tx_hash;
11177  if (res.txs.size() == 1)
11178  {
11179  ok = get_pruned_tx(res.txs.front(), tx, tx_hash);
11180  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11181  }
11182  else
11183  {
11184  cryptonote::blobdata tx_data;
11185  ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
11186  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
11188  error::wallet_internal_error, "Failed to validate transaction from daemon");
11189  tx_hash = cryptonote::get_transaction_hash(tx);
11190  }
11191 
11192  CHECK_AND_ASSERT_THROW_MES(tx.version == 1, "Tx proofs are for v1 transactions only");
11193  THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
11194 
11195  // determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound)
11197  std::vector<crypto::secret_key> additional_tx_keys;
11198  const bool is_out = m_subaddresses.count(address.m_spend_public_key) == 0;
11199  if (is_out)
11200  {
11201  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.");
11202  }
11203 
11204  return get_tx_proof(tx, tx_key, additional_tx_keys, address, is_subaddress, message);
11205 }
bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys)
Definition: wallet2.cpp:10714
std::string get_tx_proof(const crypto::hash &txid, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message)
Definition: wallet2.cpp:11161
const crypto::secret_key null_skey
Definition: crypto.cpp:73
Here is the call 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 11207 of file wallet2.cpp.

11208 {
11209  hw::device &hwdev = m_account.get_device();
11210  rct::key aP;
11211  // determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound)
11212  const bool is_out = m_subaddresses.count(address.m_spend_public_key) == 0;
11213 
11215  std::string prefix_data((const char*)&txid, sizeof(crypto::hash));
11216  prefix_data += message;
11217  crypto::hash prefix_hash;
11218  crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
11219 
11220  std::vector<crypto::public_key> shared_secret;
11221  std::vector<crypto::signature> sig;
11222  std::string sig_str;
11223  if (is_out)
11224  {
11225  const size_t num_sigs = 1 + additional_tx_keys.size();
11226  shared_secret.resize(num_sigs);
11227  sig.resize(num_sigs);
11228 
11229  hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key));
11230  shared_secret[0] = rct::rct2pk(aP);
11231  crypto::public_key tx_pub_key;
11232  if (is_subaddress)
11233  {
11234  hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key));
11235  tx_pub_key = rct2pk(aP);
11236  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]);
11237  }
11238  else
11239  {
11240  hwdev.secret_key_to_public_key(tx_key, tx_pub_key);
11241  hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]);
11242  }
11243  for (size_t i = 1; i < num_sigs; ++i)
11244  {
11245  hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
11246  shared_secret[i] = rct::rct2pk(aP);
11247  if (is_subaddress)
11248  {
11249  hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
11250  tx_pub_key = rct2pk(aP);
11251  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]);
11252  }
11253  else
11254  {
11255  hwdev.secret_key_to_public_key(additional_tx_keys[i - 1], tx_pub_key);
11256  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]);
11257  }
11258  }
11259  sig_str = std::string("OutProofV1");
11260  }
11261  else
11262  {
11264  THROW_WALLET_EXCEPTION_IF(tx_pub_key == null_pkey, error::wallet_internal_error, "Tx pubkey was not found");
11265 
11266  std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
11267  const size_t num_sigs = 1 + additional_tx_pub_keys.size();
11268  shared_secret.resize(num_sigs);
11269  sig.resize(num_sigs);
11270 
11271  const crypto::secret_key& a = m_account.get_keys().m_view_secret_key;
11272  hwdev.scalarmultKey(aP, rct::pk2rct(tx_pub_key), rct::sk2rct(a));
11273  shared_secret[0] = rct2pk(aP);
11274  if (is_subaddress)
11275  {
11276  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]);
11277  }
11278  else
11279  {
11280  hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], a, sig[0]);
11281  }
11282  for (size_t i = 1; i < num_sigs; ++i)
11283  {
11284  hwdev.scalarmultKey(aP,rct::pk2rct(additional_tx_pub_keys[i - 1]), rct::sk2rct(a));
11285  shared_secret[i] = rct2pk(aP);
11286  if (is_subaddress)
11287  {
11288  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]);
11289  }
11290  else
11291  {
11292  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]);
11293  }
11294  }
11295  sig_str = std::string("InProofV1");
11296  }
11297  const size_t num_sigs = shared_secret.size();
11298 
11299  // check if this address actually received any funds
11300  crypto::key_derivation derivation;
11301  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");
11302  std::vector<crypto::key_derivation> additional_derivations(num_sigs - 1);
11303  for (size_t i = 1; i < num_sigs; ++i)
11304  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");
11305  uint64_t received;
11306  check_tx_key_helper(tx, derivation, additional_derivations, address, received);
11307  THROW_WALLET_EXCEPTION_IF(!received, error::wallet_internal_error, tr("No funds received in this tx."));
11308 
11309  // concatenate all signature strings
11310  for (size_t i = 0; i < num_sigs; ++i)
11311  sig_str +=
11312  tools::base58::encode(std::string((const char *)&shared_secret[i], sizeof(crypto::public_key))) +
11313  tools::base58::encode(std::string((const char *)&sig[i], sizeof(crypto::signature)));
11314  return sig_str;
11315 }
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 11933 of file wallet2.cpp.

11934 {
11935  std::vector<tx_extra_field> tx_extra_fields;
11936  if(!parse_tx_extra(td.m_tx.extra, tx_extra_fields))
11937  {
11938  // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
11939  }
11940 
11941  // Due to a previous bug, there might be more than one tx pubkey in extra, one being
11942  // the result of a previously discarded signature.
11943  // For speed, since scanning for outputs is a slow process, we check whether extra
11944  // contains more than one pubkey. If not, the first one is returned. If yes, they're
11945  // checked for whether they yield at least one output
11946  tx_extra_pub_key pub_key_field;
11947  THROW_WALLET_EXCEPTION_IF(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 0), error::wallet_internal_error,
11948  "Public key wasn't found in the transaction extra");
11949  const crypto::public_key tx_pub_key = pub_key_field.pub_key;
11950  bool two_found = find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 1);
11951  if (!two_found) {
11952  // easy case, just one found
11953  return tx_pub_key;
11954  }
11955 
11956  // more than one, loop and search
11957  const cryptonote::account_keys& keys = m_account.get_keys();
11958  size_t pk_index = 0;
11959  hw::device &hwdev = m_account.get_device();
11960 
11961  while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) {
11962  const crypto::public_key tx_pub_key = pub_key_field.pub_key;
11963  crypto::key_derivation derivation;
11964  bool r = hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
11965  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
11966 
11967  for (size_t i = 0; i < td.m_tx.vout.size(); ++i)
11968  {
11969  tx_scan_info_t tx_scan_info;
11970  check_acc_out_precomp(td.m_tx.vout[i], derivation, {}, i, tx_scan_info);
11971  if (!tx_scan_info.error && tx_scan_info.received)
11972  return tx_pub_key;
11973  }
11974  }
11975 
11976  // we found no key yielding an output, but it might be in the additional
11977  // tx pub keys only, which we do not need to check, so return the first one
11978  return tx_pub_key;
11979 }
std::vector< uint8_t > extra
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:99
cryptonote::transaction_prefix m_tx
Definition: wallet2.h:304

◆ 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 6278 of file wallet2.cpp.

6279 {
6280  for (auto i = m_unconfirmed_payments.begin(); i != m_unconfirmed_payments.end(); ++i) {
6281  if ((!subaddr_account || *subaddr_account == i->second.m_pd.m_subaddr_index.major) &&
6282  (subaddr_indices.empty() || subaddr_indices.count(i->second.m_pd.m_subaddr_index.minor) == 1))
6283  unconfirmed_payments.push_back(*i);
6284  }
6285 }

◆ 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 6267 of file wallet2.cpp.

6268 {
6269  for (auto i = m_unconfirmed_txs.begin(); i != m_unconfirmed_txs.end(); ++i) {
6270  if (subaddr_account && *subaddr_account != i->second.m_subaddr_account)
6271  continue;
6272  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)
6273  continue;
6274  unconfirmed_payments.push_back(*i);
6275  }
6276 }

◆ get_wallet_file()

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

Definition at line 11706 of file wallet2.cpp.

11707 {
11708  return m_wallet_file;
11709 }

◆ has_multisig_partial_key_images()

bool tools::wallet2::has_multisig_partial_key_images ( ) const

Definition at line 5537 of file wallet2.cpp.

5538 {
5539  if (!m_multisig)
5540  return false;
5541  for (const auto &td: m_transfers)
5542  if (td.m_key_image_partial && td.m_tx.version == 1)
5543  return true;
5544  return false;
5545 }

◆ has_stagenet_option()

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

Definition at line 1177 of file wallet2.cpp.

1178 {
1179  return command_line::get_arg(vm, options().stagenet);
1180 }
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 1172 of file wallet2.cpp.

1173 {
1174  return command_line::get_arg(vm, options().testnet);
1175 }
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 5547 of file wallet2.cpp.

5548 {
5549  for (const auto &td: m_transfers)
5550  if (!td.m_key_image_known && td.m_tx.version == 1)
5551  return true;
5552  return false;
5553 }

◆ hash_m_transfer()

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

Definition at line 13479 of file wallet2.cpp.

13480 {
13481  KECCAK_CTX state;
13482  keccak_init(&state);
13483  keccak_update(&state, (const uint8_t *) transfer.m_txid.data, sizeof(transfer.m_txid.data));
13484  keccak_update(&state, (const uint8_t *) transfer.m_internal_output_index, sizeof(transfer.m_internal_output_index));
13485  keccak_update(&state, (const uint8_t *) transfer.m_global_output_index, sizeof(transfer.m_global_output_index));
13486  keccak_update(&state, (const uint8_t *) transfer.m_amount, sizeof(transfer.m_amount));
13487  keccak_finish(&state, (uint8_t *) hash.data);
13488 }
void keccak_finish(KECCAK_CTX *ctx, uint8_t *md)
void keccak_update(KECCAK_CTX *ctx, const uint8_t *in, size_t inlen)
void keccak_init(KECCAK_CTX *ctx)
Here is the call 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 13490 of file wallet2.cpp.

13491 {
13492  CHECK_AND_ASSERT_THROW_MES(transfer_height > (int64_t)m_transfers.size(), "Hash height is greater than number of transfers");
13493 
13494  KECCAK_CTX state;
13495  crypto::hash tmp_hash{};
13496  uint64_t current_height = 0;
13497 
13498  keccak_init(&state);
13499  for(const transfer_details & transfer : m_transfers){
13500  if (transfer_height >= 0 && current_height >= (uint64_t)transfer_height){
13501  break;
13502  }
13503 
13504  hash_m_transfer(transfer, tmp_hash);
13505  keccak_update(&state, (const uint8_t *) transfer.m_block_height, sizeof(transfer.m_block_height));
13506  keccak_update(&state, (const uint8_t *) tmp_hash.data, sizeof(tmp_hash.data));
13507  current_height += 1;
13508  }
13509 
13510  keccak_finish(&state, (uint8_t *) hash.data);
13511  return current_height;
13512 }
void hash_m_transfer(const transfer_details &transfer, crypto::hash &hash) const
Definition: wallet2.cpp:13479
Here is the call graph for this function:

◆ ignore_fractional_outputs() [1/2]

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

Definition at line 1093 of file wallet2.h.

1093 { return m_ignore_fractional_outputs; }

◆ ignore_fractional_outputs() [2/2]

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

Definition at line 1094 of file wallet2.h.

1094 { 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 12483 of file wallet2.cpp.

12484 {
12485  m_blockchain.clear();
12486  if (std::get<0>(bc))
12487  {
12488  for (size_t n = std::get<0>(bc); n > 0; --n)
12489  m_blockchain.push_back(std::get<1>(bc));
12490  m_blockchain.trim(std::get<0>(bc));
12491  }
12492  for (auto const &b : std::get<2>(bc))
12493  {
12494  m_blockchain.push_back(b);
12495  }
12496  cryptonote::block genesis;
12497  generate_genesis(genesis);
12498  crypto::hash genesis_hash = get_block_hash(genesis);
12499  check_genesis(genesis_hash);
12500  m_last_block_reward = cryptonote::get_outs_etn_amount(genesis.miner_tx);
12501 }
void clear()
Definition: wallet2.h:189
void trim(size_t height)
Definition: wallet2.h:191
void push_back(const crypto::hash &hash)
Definition: wallet2.h:184
uint64_t get_outs_etn_amount(const transaction &tx)
crypto::hash get_block_hash(uint64_t height)

◆ 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 12068 of file wallet2.cpp.

12069 {
12070  PERF_TIMER(import_key_images_fsu);
12071  std::string data;
12072  bool r = epee::file_io_utils::load_file_to_string(filename, data);
12073 
12074  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename);
12075 
12076  const size_t magiclen = strlen(KEY_IMAGE_EXPORT_FILE_MAGIC);
12077  if (data.size() < magiclen || memcmp(data.data(), KEY_IMAGE_EXPORT_FILE_MAGIC, magiclen))
12078  {
12079  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad key image export file magic in ") + filename);
12080  }
12081 
12082  try
12083  {
12084  PERF_TIMER(import_key_images_decrypt);
12085  data = decrypt_with_view_secret_key(std::string(data, magiclen));
12086  }
12087  catch (const std::exception &e)
12088  {
12089  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt ") + filename + ": " + e.what());
12090  }
12091 
12092  const size_t headerlen = 4 + 2 * sizeof(crypto::public_key);
12093  THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, std::string("Bad data size from file ") + filename);
12094  const uint32_t offset = (uint8_t)data[0] | (((uint8_t)data[1]) << 8) | (((uint8_t)data[2]) << 16) | (((uint8_t)data[3]) << 24);
12095  const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[4];
12096  const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[4 + sizeof(crypto::public_key)];
12098  if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key)
12099  {
12100  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string( "Key images from ") + filename + " are for a different account");
12101  }
12102  THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Offset larger than known outputs");
12103 
12104  const size_t record_size = sizeof(crypto::key_image) + sizeof(crypto::signature);
12105  THROW_WALLET_EXCEPTION_IF((data.size() - headerlen) % record_size,
12106  error::wallet_internal_error, std::string("Bad data size from file ") + filename);
12107  size_t nki = (data.size() - headerlen) / record_size;
12108 
12109  std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
12110  ski.reserve(nki);
12111  for (size_t n = 0; n < nki; ++n)
12112  {
12113  crypto::key_image key_image = *reinterpret_cast<const crypto::key_image*>(&data[headerlen + n * record_size]);
12114  crypto::signature signature = *reinterpret_cast<const crypto::signature*>(&data[headerlen + n * record_size + sizeof(crypto::key_image)]);
12115 
12116  ski.push_back(std::make_pair(key_image, signature));
12117  }
12118 
12119  return import_key_images(ski, offset, spent, unspent);
12120 }
std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated=true) const
Definition: wallet2.cpp:13030
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 12123 of file wallet2.cpp.

12124 {
12125  PERF_TIMER(import_key_images_lots);
12127  COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
12128 
12129  THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Offset larger than known outputs");
12130  THROW_WALLET_EXCEPTION_IF(signed_key_images.size() > m_transfers.size() - offset, error::wallet_internal_error,
12131  "The blockchain is out of date compared to the signed key images");
12132 
12133  if (signed_key_images.empty() && offset == 0)
12134  {
12135  spent = 0;
12136  unspent = 0;
12137  return 0;
12138  }
12139 
12140  req.key_images.reserve(signed_key_images.size());
12141 
12142  PERF_TIMER_START(import_key_images_A);
12143  for (size_t n = 0; n < signed_key_images.size(); ++n)
12144  {
12145  const transfer_details &td = m_transfers[n + offset];
12146  const crypto::key_image &key_image = signed_key_images[n].first;
12147  const crypto::signature &signature = signed_key_images[n].second;
12148 
12149  // get ephemeral public key
12150  const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index];
12151  THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error,
12152  "Non txout_to_key output found");
12153  const cryptonote::txout_to_key &o = boost::get<cryptonote::txout_to_key>(out.target);
12154  const crypto::public_key pkey = o.key;
12155 
12156  if (!td.m_key_image_known || !(key_image == td.m_key_image))
12157  {
12158  std::vector<const crypto::public_key*> pkeys;
12159  pkeys.push_back(&pkey);
12161  error::wallet_internal_error, "Key image out of validity domain: input " + boost::lexical_cast<std::string>(n + offset) + "/"
12162  + boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image));
12163 
12165  error::signature_check_failed, boost::lexical_cast<std::string>(n + offset) + "/"
12166  + boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image)
12167  + ", signature " + epee::string_tools::pod_to_hex(signature) + ", pubkey " + epee::string_tools::pod_to_hex(*pkeys[0]));
12168  }
12169  req.key_images.push_back(epee::string_tools::pod_to_hex(key_image));
12170  }
12171  PERF_TIMER_STOP(import_key_images_A);
12172 
12173  PERF_TIMER_START(import_key_images_B);
12174  for (size_t n = 0; n < signed_key_images.size(); ++n)
12175  {
12176  m_transfers[n + offset].m_key_image = signed_key_images[n].first;
12177  m_key_images[m_transfers[n + offset].m_key_image] = n + offset;
12178  m_transfers[n + offset].m_key_image_known = true;
12179  m_transfers[n + offset].m_key_image_request = false;
12180  m_transfers[n + offset].m_key_image_partial = false;
12181  }
12182  PERF_TIMER_STOP(import_key_images_B);
12183 
12184  if(check_spent)
12185  {
12186  PERF_TIMER(import_key_images_RPC);
12187  m_daemon_rpc_mutex.lock();
12188  bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout);
12189  m_daemon_rpc_mutex.unlock();
12190  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
12191  THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
12192  THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
12193  THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
12194  "daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
12195  std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
12196  for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
12197  {
12198  transfer_details &td = m_transfers[n + offset];
12199  td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT;
12200  }
12201  }
12202  spent = 0;
12203  unspent = 0;
12204  std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input.
12205  std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
12206  // was created by sweep_all, so we can't know the spent height and other detailed info.
12207  std::unordered_map<crypto::key_image, crypto::hash> spent_key_images;
12208 
12209  PERF_TIMER_START(import_key_images_C);
12210  for (const transfer_details &td: m_transfers)
12211  {
12212  for (const cryptonote::txin_v& in : td.m_tx.vin)
12213  {
12214  if (in.type() == typeid(cryptonote::txin_to_key))
12215  spent_key_images.insert(std::make_pair(boost::get<cryptonote::txin_to_key>(in).k_image, td.m_txid));
12216  }
12217  }
12218  PERF_TIMER_STOP(import_key_images_C);
12219 
12220  // accumulate outputs before the updated data
12221  for(size_t i = 0; i < offset; ++i)
12222  {
12223  const transfer_details &td = m_transfers[i];
12224  if (td.m_frozen)
12225  continue;
12226  uint64_t amount = td.amount();
12227  if (td.m_spent)
12228  spent += amount;
12229  else
12230  unspent += amount;
12231  }
12232 
12233  PERF_TIMER_START(import_key_images_D);
12234  for(size_t i = 0; i < signed_key_images.size(); ++i)
12235  {
12236  const transfer_details &td = m_transfers[i + offset];
12237  if (td.m_frozen)
12238  continue;
12239  uint64_t amount = td.amount();
12240  if (td.m_spent)
12241  spent += amount;
12242  else
12243  unspent += amount;
12244  LOG_PRINT_L2("Transfer " << i << ": " << print_etn(amount) << " (" << td.m_global_output_index << "): "
12245  << (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[i] << ")");
12246 
12247  if (i < daemon_resp.spent_status.size() && daemon_resp.spent_status[i] == COMMAND_RPC_IS_KEY_IMAGE_SPENT::SPENT_IN_BLOCKCHAIN)
12248  {
12249  const std::unordered_map<crypto::key_image, crypto::hash>::const_iterator skii = spent_key_images.find(td.m_key_image);
12250  if (skii == spent_key_images.end())
12251  swept_transfers.push_back(i);
12252  else
12253  spent_txids.insert(skii->second);
12254  }
12255  }
12256  PERF_TIMER_STOP(import_key_images_D);
12257 
12258  MDEBUG("Total: " << print_etn(spent) << " spent, " << print_etn(unspent) << " unspent");
12259 
12260  if (check_spent)
12261  {
12262  // query outgoing txes
12265  gettxs_req.decode_as_json = false;
12266  gettxs_req.prune = true;
12267  gettxs_req.txs_hashes.reserve(spent_txids.size());
12268  for (const crypto::hash& spent_txid : spent_txids)
12269  gettxs_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(spent_txid));
12270 
12271 
12272  PERF_TIMER_START(import_key_images_E);
12273  m_daemon_rpc_mutex.lock();
12274  bool r = invoke_http_json("/gettransactions", gettxs_req, gettxs_res, rpc_timeout);
12275  m_daemon_rpc_mutex.unlock();
12276  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
12277  THROW_WALLET_EXCEPTION_IF(gettxs_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
12278  THROW_WALLET_EXCEPTION_IF(gettxs_res.txs.size() != spent_txids.size(), error::wallet_internal_error,
12279  "daemon returned wrong response for gettransactions, wrong count = " + std::to_string(gettxs_res.txs.size()) + ", expected " + std::to_string(spent_txids.size()));
12280  PERF_TIMER_STOP(import_key_images_E);
12281 
12282  // process each outgoing tx
12283  PERF_TIMER_START(import_key_images_F);
12284  auto spent_txid = spent_txids.begin();
12285  hw::device &hwdev = m_account.get_device();
12286  auto it = spent_txids.begin();
12287  for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs)
12288  {
12289  THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool");
12290 
12291  cryptonote::transaction spent_tx;
12292  crypto::hash spnet_txid_parsed;
12293  THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(e, spent_tx, spnet_txid_parsed), error::wallet_internal_error, "Failed to get tx from daemon");
12294  THROW_WALLET_EXCEPTION_IF(!(spnet_txid_parsed == *it), error::wallet_internal_error, "parsed txid mismatch");
12295  ++it;
12296 
12297  // get received (change) amount
12298  uint64_t tx_etn_got_in_outs = 0;
12299  const cryptonote::account_keys& keys = m_account.get_keys();
12300  const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx);
12301  crypto::key_derivation derivation;
12302  bool r = hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
12303  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
12304  const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(spent_tx);
12305  std::vector<crypto::key_derivation> additional_derivations;
12306  for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
12307  {
12308  additional_derivations.push_back({});
12309  r = hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back());
12310  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
12311  }
12312  size_t output_index = 0;
12313  bool miner_tx = cryptonote::is_coinbase(spent_tx);
12314  for (const cryptonote::tx_out& out : spent_tx.vout)
12315  {
12316  tx_scan_info_t tx_scan_info;
12317  check_acc_out_precomp(out, derivation, additional_derivations, output_index, tx_scan_info);
12318  THROW_WALLET_EXCEPTION_IF(tx_scan_info.error, error::wallet_internal_error, "check_acc_out_precomp failed");
12319  if (tx_scan_info.received)
12320  {
12321  if (tx_scan_info.etn_transfered == 0 && !miner_tx)
12322  {
12323  rct::key mask;
12324  tx_scan_info.etn_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask, hwdev);
12325  }
12326  THROW_WALLET_EXCEPTION_IF(tx_etn_got_in_outs >= std::numeric_limits<uint64_t>::max() - tx_scan_info.etn_transfered,
12327  error::wallet_internal_error, "Overflow in received amounts");
12328  tx_etn_got_in_outs += tx_scan_info.etn_transfered;
12329  }
12330  ++output_index;
12331  }
12332 
12333  // get spent amount
12334  uint64_t tx_etn_spent_in_ins = 0;
12335  uint32_t subaddr_account = (uint32_t)-1;
12336  std::set<uint32_t> subaddr_indices;
12337  for (const cryptonote::txin_v& in : spent_tx.vin)
12338  {
12339  if (in.type() != typeid(cryptonote::txin_to_key))
12340  continue;
12341  auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
12342  if (it != m_key_images.end())
12343  {
12344  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()));
12345  const transfer_details& td = m_transfers[it->second];
12346  uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
12347  if (amount > 0)
12348  {
12349  THROW_WALLET_EXCEPTION_IF(amount != td.amount(), error::wallet_internal_error,
12350  std::string("Inconsistent amount in tx input: got ") + print_etn(amount) +
12351  std::string(", expected ") + print_etn(td.amount()));
12352  }
12353  amount = td.amount();
12354  tx_etn_spent_in_ins += amount;
12355 
12356  LOG_PRINT_L0("Spent ETN: " << print_etn(amount) << ", with tx: " << *spent_txid);
12357  set_spent(it->second, e.block_height);
12358  if (m_callback)
12359  m_callback->on_etn_spent(e.block_height, *spent_txid, spent_tx, amount, spent_tx, td.m_subaddr_index);
12360  if (subaddr_account != (uint32_t)-1 && subaddr_account != td.m_subaddr_index.major)
12361  LOG_PRINT_L0("WARNING: This tx spends outputs received by different subaddress accounts, which isn't supposed to happen");
12362  subaddr_account = td.m_subaddr_index.major;
12363  subaddr_indices.insert(td.m_subaddr_index.minor);
12364  }
12365  }
12366 
12367  // create outgoing payment
12368  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);
12369 
12370  // erase corresponding incoming payment
12371  for (auto j = m_payments.begin(); j != m_payments.end(); ++j)
12372  {
12373  if (j->second.m_tx_hash == *spent_txid)
12374  {
12375  m_payments.erase(j);
12376  break;
12377  }
12378  }
12379 
12380  ++spent_txid;
12381  }
12382  PERF_TIMER_STOP(import_key_images_F);
12383 
12384  PERF_TIMER_START(import_key_images_G);
12385  for (size_t n : swept_transfers)
12386  {
12387  const transfer_details& td = m_transfers[n];
12388  confirmed_transfer_details pd;
12389  pd.m_change = (uint64_t)-1; // change is unknown
12390  pd.m_amount_in = pd.m_amount_out = td.amount(); // fee is unknown
12391  pd.m_block_height = 0; // spent block height is unknown
12392  pd.m_is_migration = td.m_tx.version == 2;
12393  const crypto::hash &spent_txid = crypto::null_hash; // spent txid is unknown
12394  m_confirmed_txs.insert(std::make_pair(spent_txid, pd));
12395  }
12396  PERF_TIMER_STOP(import_key_images_G);
12397  }
12398 
12399  // this can be 0 if we do not know the height
12400  return m_transfers[signed_key_images.size() + offset - 1].m_block_height;
12401 }
virtual void on_etn_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction &in_tx, uint64_t amount, const cryptonote::transaction &spend_tx, const cryptonote::subaddress_index &subaddr_index)
Definition: wallet2.h:130
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:

◆ 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 12430 of file wallet2.cpp.

12431 {
12432  std::unordered_set<size_t> selected_transfers;
12433  if (only_selected_transfers)
12434  {
12435  for (const pending_tx & ptx : signed_tx.ptx)
12436  {
12437  for (const size_t s: ptx.selected_transfers)
12438  selected_transfers.insert(s);
12439  }
12440  }
12441 
12442  return import_key_images(signed_tx.key_images, offset, only_selected_transfers ? boost::make_optional(selected_transfers) : boost::none);
12443 }

◆ 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 
)

◆ 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 12847 of file wallet2.cpp.

12848 {
12849  CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
12850 
12851  std::vector<std::vector<tools::wallet2::multisig_info>> info;
12852  std::unordered_set<crypto::public_key> seen;
12853  for (cryptonote::blobdata &data: blobs)
12854  {
12855  const size_t magiclen = strlen(MULTISIG_EXPORT_FILE_MAGIC);
12856  THROW_WALLET_EXCEPTION_IF(data.size() < magiclen || memcmp(data.data(), MULTISIG_EXPORT_FILE_MAGIC, magiclen),
12857  error::wallet_internal_error, "Bad multisig info file magic in ");
12858 
12859  data = decrypt_with_view_secret_key(std::string(data, magiclen));
12860 
12861  const size_t headerlen = 3 * sizeof(crypto::public_key);
12862  THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, "Bad data size");
12863 
12864  const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0];
12865  const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)];
12866  const crypto::public_key &signer = *(const crypto::public_key*)&data[2*sizeof(crypto::public_key)];
12868  THROW_WALLET_EXCEPTION_IF(public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key,
12869  error::wallet_internal_error, "Multisig info is for a different account");
12870  if (get_multisig_signer_public_key() == signer)
12871  {
12872  MINFO("Multisig info from this wallet ignored");
12873  continue;
12874  }
12875  if (seen.find(signer) != seen.end())
12876  {
12877  MINFO("Duplicate multisig info ignored");
12878  continue;
12879  }
12880  seen.insert(signer);
12881 
12882  std::string body(data, headerlen);
12883  std::istringstream iss(body);
12884  std::vector<tools::wallet2::multisig_info> i;
12886  ar >> i;
12887  MINFO(boost::format("%u outputs found") % boost::lexical_cast<std::string>(i.size()));
12888  info.push_back(std::move(i));
12889  }
12890 
12891  CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources");
12892 
12893  std::vector<std::vector<rct::key>> k;
12894  k.reserve(m_transfers.size());
12895  for (const auto &td: m_transfers)
12896  k.push_back(td.m_multisig_k);
12897 
12898  // how many outputs we're going to update
12899  size_t n_outputs = m_transfers.size();
12900  for (const auto &pi: info)
12901  if (pi.size() < n_outputs)
12902  n_outputs = pi.size();
12903 
12904  if (n_outputs == 0)
12905  return 0;
12906 
12907  // check signers are consistent
12908  for (const auto &pi: info)
12909  {
12910  CHECK_AND_ASSERT_THROW_MES(std::find(m_multisig_signers.begin(), m_multisig_signers.end(), pi[0].m_signer) != m_multisig_signers.end(),
12911  "Signer is not a member of this multisig wallet");
12912  for (size_t n = 1; n < n_outputs; ++n)
12913  CHECK_AND_ASSERT_THROW_MES(pi[n].m_signer == pi[0].m_signer, "Mismatched signers in imported multisig info");
12914  }
12915 
12916  // trim data we don't have info for from all participants
12917  for (auto &pi: info)
12918  pi.resize(n_outputs);
12919 
12920  // sort by signer
12921  if (!info.empty() && !info.front().empty())
12922  {
12923  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)); });
12924  }
12925 
12926  // first pass to determine where to detach the blockchain
12927  for (size_t n = 0; n < n_outputs; ++n)
12928  {
12929  const transfer_details &td = m_transfers[n];
12930  if (!td.m_key_image_partial)
12931  continue;
12932  MINFO("Multisig info importing from block height " << td.m_block_height);
12933  detach_blockchain(td.m_block_height);
12934  break;
12935  }
12936 
12937  for (size_t n = 0; n < n_outputs && n < m_transfers.size(); ++n)
12938  {
12939  update_multisig_rescan_info(k, info, n);
12940  }
12941 
12942  m_multisig_rescan_k = &k;
12943  m_multisig_rescan_info = &info;
12944  try
12945  {
12946 
12947  refresh(false);
12948  }
12949  catch (...)
12950  {
12951  m_multisig_rescan_info = NULL;
12952  m_multisig_rescan_k = NULL;
12953  throw;
12954  }
12955  m_multisig_rescan_info = NULL;
12956  m_multisig_rescan_k = NULL;
12957 
12958  return n_outputs;
12959 }
void refresh(bool trusted_daemon)
Definition: wallet2.cpp:3043
const T & move(const T &t)
Definition: gtest-port.h:1317
Here is the call 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 12543 of file wallet2.cpp.

12544 {
12546 
12547  THROW_WALLET_EXCEPTION_IF(outputs.first > m_transfers.size(), error::wallet_internal_error,
12548  "Imported outputs omit more outputs that we know of");
12549 
12550  const size_t offset = outputs.first;
12551  const size_t original_size = m_transfers.size();
12552  m_transfers.resize(offset + outputs.second.size());
12553  for (size_t i = 0; i < offset; ++i)
12554  m_transfers[i].m_key_image_request = false;
12555  for (size_t i = 0; i < outputs.second.size(); ++i)
12556  {
12557  transfer_details td = outputs.second[i];
12558 
12559  // skip those we've already imported, or which have different data
12560  if (i + offset < original_size)
12561  {
12562  // compare the data used to create the key image below
12563  const transfer_details &org_td = m_transfers[i + offset];
12564  if (!org_td.m_key_image_known)
12565  goto process;
12566 #define CMPF(f) if (!(td.f == org_td.f)) goto process
12567  CMPF(m_txid);
12568  CMPF(m_key_image);
12569  CMPF(m_internal_output_index);
12570 #undef CMPF
12571  if (!(get_transaction_prefix_hash(td.m_tx) == get_transaction_prefix_hash(org_td.m_tx)))
12572  goto process;
12573 
12574  // copy anyway, since the comparison does not include ancillary fields which may have changed
12575  m_transfers[i + offset] = std::move(td);
12576  continue;
12577  }
12578 
12579 process:
12580 
12581  // the hot wallet wouldn't have known about key images (except if we already exported them)
12582  cryptonote::keypair in_ephemeral;
12583 
12584  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));
12586  const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
12587 
12588  THROW_WALLET_EXCEPTION_IF(td.m_tx.vout[td.m_internal_output_index].target.type() != typeid(cryptonote::txout_to_key),
12589  error::wallet_internal_error, "Unsupported output type");
12590  const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
12591  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);
12592  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
12593  expand_subaddresses(td.m_subaddr_index);
12594  td.m_key_image_known = true;
12595  td.m_key_image_request = true;
12596  td.m_key_image_partial = false;
12597  THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
12598  error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i + offset));
12599 
12600  m_key_images[td.m_key_image] = i + offset;
12601  m_pub_keys[td.get_public_key()] = i + offset;
12602  m_transfers[i + offset] = std::move(td);
12603  }
12604 
12605  return m_transfers.size();
12606 }
size_t import_outputs(const std::pair< size_t, std::vector< tools::wallet2::transfer_details >> &outputs)
Definition: wallet2.cpp:12543
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 12608 of file wallet2.cpp.

12609 {
12611  std::string data = outputs_st;
12612  const size_t magiclen = strlen(OUTPUT_EXPORT_FILE_MAGIC);
12613  if (data.size() < magiclen || memcmp(data.data(), OUTPUT_EXPORT_FILE_MAGIC, magiclen))
12614  {
12615  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad magic from outputs"));
12616  }
12617 
12618  try
12619  {
12620  PERF_TIMER(import_outputs_decrypt);
12621  data = decrypt_with_view_secret_key(std::string(data, magiclen));
12622  }
12623  catch (const std::exception &e)
12624  {
12625  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt outputs: ") + e.what());
12626  }
12627 
12628  const size_t headerlen = 2 * sizeof(crypto::public_key);
12629  if (data.size() < headerlen)
12630  {
12631  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad data size for outputs"));
12632  }
12633  const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0];
12634  const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)];
12636  if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key)
12637  {
12638  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Outputs from are for a different account"));
12639  }
12640 
12641  size_t imported_outputs = 0;
12642  try
12643  {
12644  std::string body(data, headerlen);
12645  std::stringstream iss;
12646  iss << body;
12647  std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
12648  try
12649  {
12651  ar >> outputs;
12652  }
12653  catch (...)
12654  {
12655  iss.str("");
12656  iss << body;
12657  boost::archive::binary_iarchive ar(iss);
12658  ar >> outputs;
12659  }
12660 
12661  imported_outputs = import_outputs(outputs);
12662  }
12663  catch (const std::exception &e)
12664  {
12665  THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to import outputs") + e.what());
12666  }
12667 
12668  return imported_outputs;
12669 }
size_t import_outputs_from_str(const std::string &outputs_st)
Definition: wallet2.cpp:12608

◆ import_payments()

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

Definition at line 12454 of file wallet2.cpp.

12455 {
12456  m_payments.clear();
12457  for (auto const &p : payments)
12458  {
12459  m_payments.emplace(p);
12460  }
12461 }

◆ 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 12462 of file wallet2.cpp.

12463 {
12464  m_confirmed_txs.clear();
12465  for (auto const &p : confirmed_payments)
12466  {
12467  m_confirmed_txs.emplace(p);
12468  }
12469 }

◆ 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 1281 of file wallet2.cpp.

1282 {
1283  m_checkpoints.init_default_checkpoints(m_nettype);
1284  m_is_initialized = true;
1285  m_upper_transaction_weight_limit = upper_transaction_weight_limit;
1286 
1287  if (proxy != boost::asio::ip::tcp::endpoint{})
1288  m_http_client.set_connector(net::socks::connector{std::move(proxy)});
1289  return set_daemon(daemon_address, daemon_login, trusted_daemon, std::move(ssl_options));
1290 }
bool init_default_checkpoints(network_type nettype)
loads the default main chain checkpoints
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:1267
Primarily for use with epee::net_utils::http_client.
Definition: socks_connect.h:42
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 1192 of file wallet2.cpp.

1193 {
1194  const options opts{};
1195  command_line::add_arg(desc_params, opts.daemon_address);
1196  command_line::add_arg(desc_params, opts.daemon_host);
1197  command_line::add_arg(desc_params, opts.proxy);
1198  command_line::add_arg(desc_params, opts.trusted_daemon);
1199  command_line::add_arg(desc_params, opts.untrusted_daemon);
1200  command_line::add_arg(desc_params, opts.password);
1201  command_line::add_arg(desc_params, opts.password_file);
1202  command_line::add_arg(desc_params, opts.daemon_port);
1203  command_line::add_arg(desc_params, opts.daemon_login);
1204  command_line::add_arg(desc_params, opts.daemon_ssl);
1205  command_line::add_arg(desc_params, opts.daemon_ssl_private_key);
1206  command_line::add_arg(desc_params, opts.daemon_ssl_certificate);
1207  command_line::add_arg(desc_params, opts.daemon_ssl_ca_certificates);
1208  command_line::add_arg(desc_params, opts.daemon_ssl_allowed_fingerprints);
1209  command_line::add_arg(desc_params, opts.daemon_ssl_allow_any_cert);
1210  command_line::add_arg(desc_params, opts.daemon_ssl_allow_chained);
1211  command_line::add_arg(desc_params, opts.testnet);
1212  command_line::add_arg(desc_params, opts.stagenet);
1213  command_line::add_arg(desc_params, opts.shared_ringdb_dir);
1214  command_line::add_arg(desc_params, opts.kdf_rounds);
1215  mms::message_store::init_options(desc_params);
1216  command_line::add_arg(desc_params, opts.hw_device);
1217  command_line::add_arg(desc_params, opts.hw_device_derivation_path);
1218  command_line::add_arg(desc_params, opts.tx_notify);
1219  command_line::add_arg(desc_params, opts.no_dns);
1220  command_line::add_arg(desc_params, opts.offline);
1221  command_line::add_arg(desc_params, opts.data_dir);
1222  command_line::add_arg(desc_params, opts.fallback_to_pow_checkpoint_height);
1223  command_line::add_arg(desc_params, opts.fallback_to_pow_checkpoint_hash);
1224 }
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)
Definition: command_line.h:188
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 1318 of file wallet2.h.

1319  {
1320  if (m_offline) return false;
1321  boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1322  return epee::net_utils::invoke_http_bin(uri, req, res, m_http_client, timeout, http_method);
1323  }
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:

◆ 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 1311 of file wallet2.h.

1312  {
1313  if (m_offline) return false;
1314  boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1315  return epee::net_utils::invoke_http_json(uri, req, res, m_http_client, timeout, http_method);
1316  }
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:

◆ 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 1325 of file wallet2.h.

1326  {
1327  if (m_offline) return false;
1328  boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1329  return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, m_http_client, timeout, http_method, req_id);
1330  }
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:

◆ is_deprecated()

bool tools::wallet2::is_deprecated ( ) const

Tells if the wallet file is deprecated.

Definition at line 1545 of file wallet2.cpp.

1546 {
1547  return is_old_file_format;
1548 }

◆ is_deterministic()

bool tools::wallet2::is_deterministic ( ) const

Checks if deterministic wallet.

Definition at line 1292 of file wallet2.cpp.

1293 {
1294  crypto::secret_key second;
1295  keccak((uint8_t *)&get_account().get_keys().m_spend_secret_key, sizeof(crypto::secret_key), (uint8_t *)&second, sizeof(crypto::secret_key));
1296  sc_reduce32((uint8_t *)&second);
1297  return memcmp(second.data,get_account().get_keys().m_view_secret_key.data, sizeof(crypto::secret_key)) == 0;
1298 }
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 8026 of file wallet2.cpp.

8027 {
8028  return m_keys_file_locker->locked();
8029 }

◆ is_output_blackballed()

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

Definition at line 7996 of file wallet2.cpp.

7997 {
7998  if (!m_ringdb)
7999  return false;
8000  try { return m_ringdb->blackballed(output); }
8001  catch (const std::exception &e) { return false; }
8002 }

◆ is_synced()

bool tools::wallet2::is_synced ( ) const

Definition at line 13260 of file wallet2.cpp.

13261 {
13262  uint64_t height;
13263  boost::optional<std::string> result = m_node_rpc_proxy.get_target_height(height);
13264  if (result && *result != CORE_RPC_STATUS_OK)
13265  return false;
13267 }
uint64_t get_blockchain_current_height() const
Definition: wallet2.h:890

◆ is_transfer_unlocked() [1/2]

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

Definition at line 6364 of file wallet2.cpp.

6365 {
6366  return is_transfer_unlocked(td.m_tx.unlock_time, td.m_block_height);
6367 }

◆ is_transfer_unlocked() [2/2]

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

Definition at line 6369 of file wallet2.cpp.

6370 {
6371  if(!is_tx_spendtime_unlocked(unlock_time, block_height))
6372  return false;
6373 
6374  uint64_t v8height = m_nettype == TESTNET ? 446674 : 589169;
6375  uint16_t UNLOCK_WINDOW = block_height > v8height ? ETN_DEFAULT_TX_SPENDABLE_AGE_V8 : CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
6376 
6377  if(block_height + UNLOCK_WINDOW > get_blockchain_current_height())
6378  return false;
6379 
6380  return true;
6381 }
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const
Definition: wallet2.cpp:6383
#define ETN_DEFAULT_TX_SPENDABLE_AGE_V8
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
unsigned short uint16_t
Definition: stdint.h:125

◆ is_trusted_daemon()

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

Definition at line 759 of file wallet2.h.

759 { 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 6383 of file wallet2.cpp.

6384 {
6385  if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
6386  {
6387  //interpret as block index
6389  return true;
6390  else
6391  return false;
6392  }else
6393  {
6394  //interpret as time
6395  uint64_t current_time = static_cast<uint64_t>(time(NULL));
6396  // XXX: this needs to be fast, so we'd need to get the starting heights
6397  // from the daemon to be correct once voting kicks in
6398  uint64_t v6height = m_nettype == TESTNET ? 190059 : 307499;
6400  if(current_time + leeway >= unlock_time)
6401  return true;
6402  else
6403  return false;
6404  }
6405  return false;
6406 }
#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

◆ is_unattended()

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

Definition at line 1266 of file wallet2.h.

1266 { return m_unattended; }
Here is the caller graph for this function:

◆ key_on_device()

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

Definition at line 824 of file wallet2.h.

824 { return get_device_type() != hw::device::device_type::SOFTWARE; }
hw::device::device_type get_device_type() const
Definition: wallet2.h:825
Here is the call graph for this function:

◆ key_reuse_mitigation2() [1/2]

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

Definition at line 1089 of file wallet2.h.

1089 { return m_key_reuse_mitigation2; }

◆ key_reuse_mitigation2() [2/2]

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

Definition at line 1090 of file wallet2.h.

1090 { 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 771 of file wallet2.h.

771 { 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 9228 of file wallet2.cpp.

9229 {
9230  MTRACE(__FUNCTION__);
9231 
9233 
9234  request.address = get_account().get_public_address_str(m_nettype);
9235  request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9236  m_daemon_rpc_mutex.lock();
9237  bool r = invoke_http_json("/get_address_info", request, response, rpc_timeout, "POST");
9238  m_daemon_rpc_mutex.unlock();
9239  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_info");
9240  // TODO: Validate result
9241  return true;
9242 }
#define MTRACE(x)
Definition: misc_log_ex.h:77
epee::misc_utils::struct_init< response_t > response
Here is the call graph for this function:

◆ light_wallet_get_address_txs()

void tools::wallet2::light_wallet_get_address_txs ( )

Definition at line 9244 of file wallet2.cpp.

9245 {
9246  MDEBUG("Refreshing light wallet");
9247 
9250 
9251  ireq.address = get_account().get_public_address_str(m_nettype);
9252  ireq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9253  m_daemon_rpc_mutex.lock();
9254  bool r = invoke_http_json("/get_address_txs", ireq, ires, rpc_timeout, "POST");
9255  m_daemon_rpc_mutex.unlock();
9256  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_txs");
9257  //OpenMonero sends status=success, Mymonero doesn't.
9258  THROW_WALLET_EXCEPTION_IF((!ires.status.empty() && ires.status != "success"), error::no_connection_to_daemon, "get_address_txs");
9259 
9260 
9261  // Abort if no transactions
9262  if(ires.transactions.empty())
9263  return;
9264 
9265  // Create searchable vectors
9266  std::vector<crypto::hash> payments_txs;
9267  for(const auto &p: m_payments)
9268  payments_txs.push_back(p.second.m_tx_hash);
9269  std::vector<crypto::hash> unconfirmed_payments_txs;
9270  for(const auto &up: m_unconfirmed_payments)
9271  unconfirmed_payments_txs.push_back(up.second.m_pd.m_tx_hash);
9272 
9273  // for balance calculation
9274  uint64_t wallet_total_sent = 0;
9275  // txs in pool
9276  std::vector<crypto::hash> pool_txs;
9277 
9278  for (const auto &t: ires.transactions) {
9279  const uint64_t total_received = t.total_received;
9280  uint64_t total_sent = t.total_sent;
9281 
9282  // Check key images - subtract fake outputs from total_sent
9283  for(const auto &so: t.spent_outputs)
9284  {
9285  crypto::public_key tx_public_key;
9287  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, so.tx_pub_key), error::wallet_internal_error, "Invalid tx_pub_key field");
9288  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, so.key_image), error::wallet_internal_error, "Invalid key_image field");
9289  string_tools::hex_to_pod(so.tx_pub_key, tx_public_key);
9290  string_tools::hex_to_pod(so.key_image, key_image);
9291 
9292  if(!light_wallet_key_image_is_ours(key_image, tx_public_key, so.out_index)) {
9293  THROW_WALLET_EXCEPTION_IF(so.amount > t.total_sent, error::wallet_internal_error, "Lightwallet: total sent is negative!");
9294  total_sent -= so.amount;
9295  }
9296  }
9297 
9298  // Do not add tx if empty.
9299  if(total_sent == 0 && total_received == 0)
9300  continue;
9301 
9302  crypto::hash payment_id = null_hash;
9303  crypto::hash tx_hash;
9304 
9305  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, t.payment_id), error::wallet_internal_error, "Invalid payment_id field");
9306  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, t.hash), error::wallet_internal_error, "Invalid hash field");
9307  string_tools::hex_to_pod(t.payment_id, payment_id);
9308  string_tools::hex_to_pod(t.hash, tx_hash);
9309 
9310  // lightwallet specific info
9311  bool incoming = (total_received > total_sent);
9312  address_tx address_tx;
9313  address_tx.m_tx_hash = tx_hash;
9314  address_tx.m_incoming = incoming;
9315  address_tx.m_amount = incoming ? total_received - total_sent : total_sent - total_received;
9316  address_tx.m_fee = 0; // TODO
9317  address_tx.m_block_height = t.height;
9318  address_tx.m_unlock_time = t.unlock_time;
9319  address_tx.m_timestamp = t.timestamp;
9320  address_tx.m_coinbase = t.coinbase;
9321  address_tx.m_mempool = t.mempool;
9322  m_light_wallet_address_txs.emplace(tx_hash,address_tx);
9323 
9324  // populate data needed for history (m_payments, m_unconfirmed_payments, m_confirmed_txs)
9325  // INCOMING transfers
9326  if(total_received > total_sent) {
9327  payment_details payment;
9328  payment.m_tx_hash = tx_hash;
9329  payment.m_amount = total_received - total_sent;
9330  payment.m_fee = 0; // TODO
9331  payment.m_block_height = t.height;
9332  payment.m_unlock_time = t.unlock_time;
9333  payment.m_timestamp = t.timestamp;
9334  payment.m_coinbase = t.coinbase;
9335 
9336  if (t.mempool) {
9337  if (std::find(unconfirmed_payments_txs.begin(), unconfirmed_payments_txs.end(), tx_hash) == unconfirmed_payments_txs.end()) {
9338  pool_txs.push_back(tx_hash);
9339  // assume false as we don't get that info from the light wallet server
9340  crypto::hash payment_id;
9341  THROW_WALLET_EXCEPTION_IF(!epee::string_tools::hex_to_pod(t.payment_id, payment_id),
9342  error::wallet_internal_error, "Failed to parse payment id");
9343  emplace_or_replace(m_unconfirmed_payments, payment_id, pool_payment_details{payment, false, false});
9344  if (0 != m_callback) {
9345  m_callback->on_lw_unconfirmed_etn_received(t.height, payment.m_tx_hash, payment.m_amount);
9346  }
9347  }
9348  } else {
9349  if (std::find(payments_txs.begin(), payments_txs.end(), tx_hash) == payments_txs.end()) {
9350  m_payments.emplace(tx_hash, payment);
9351  if (0 != m_callback) {
9352  m_callback->on_lw_etn_received(t.height, payment.m_tx_hash, payment.m_amount);
9353  }
9354  }
9355  }
9356  // Outgoing transfers
9357  } else {
9358  uint64_t amount_sent = total_sent - total_received;
9359  cryptonote::transaction dummy_tx; // not used by light wallet
9360  // increase wallet total sent
9361  wallet_total_sent += total_sent;
9362  if (t.mempool)
9363  {
9364  // Handled by add_unconfirmed_tx in commit_tx
9365  // If sent from another wallet instance we need to add it
9366  if(m_unconfirmed_txs.find(tx_hash) == m_unconfirmed_txs.end())
9367  {
9368  unconfirmed_transfer_details utd;
9369  utd.m_amount_in = amount_sent;
9370  utd.m_amount_out = amount_sent;
9371  utd.m_change = 0;
9372  utd.m_payment_id = payment_id;
9373  utd.m_timestamp = t.timestamp;
9375  m_unconfirmed_txs.emplace(tx_hash,utd);
9376  }
9377  }
9378  else
9379  {
9380  // Only add if new
9381  auto confirmed_tx = m_confirmed_txs.find(tx_hash);
9382  if(confirmed_tx == m_confirmed_txs.end()) {
9383  // tx is added to m_unconfirmed_txs - move to confirmed
9384  if(m_unconfirmed_txs.find(tx_hash) != m_unconfirmed_txs.end())
9385  {
9386  process_unconfirmed(tx_hash, dummy_tx, t.height);
9387  }
9388  // Tx sent by another wallet instance
9389  else
9390  {
9391  confirmed_transfer_details ctd;
9392  ctd.m_amount_in = amount_sent;
9393  ctd.m_amount_out = amount_sent;
9394  ctd.m_change = 0;
9395  ctd.m_payment_id = payment_id;
9396  ctd.m_block_height = t.height;
9397  ctd.m_timestamp = t.timestamp;
9398  m_confirmed_txs.emplace(tx_hash,ctd);
9399  }
9400  if (0 != m_callback)
9401  {
9402  m_callback->on_lw_etn_spent(t.height, tx_hash, amount_sent);
9403  }
9404  }
9405  // If not new - check the amount and update if necessary.
9406  // when sending a tx to same wallet the receiving amount has to be credited
9407  else
9408  {
9409  if(confirmed_tx->second.m_amount_in != amount_sent || confirmed_tx->second.m_amount_out != amount_sent)
9410  {
9411  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));
9412  confirmed_tx->second.m_amount_in = amount_sent;
9413  confirmed_tx->second.m_amount_out = amount_sent;
9414  confirmed_tx->second.m_change = 0;
9415  }
9416  }
9417  }
9418  }
9419  }
9420  // TODO: purge old unconfirmed_txs
9421  remove_obsolete_pool_txs(pool_txs);
9422 
9423  // Calculate wallet balance
9424  m_light_wallet_balance = ires.total_received-wallet_total_sent;
9425  // MyMonero doesn't send unlocked balance
9426  if(ires.total_received_unlocked > 0)
9427  m_light_wallet_unlocked_balance = ires.total_received_unlocked-wallet_total_sent;
9428  else
9429  m_light_wallet_unlocked_balance = m_light_wallet_balance;
9430 }
virtual void on_lw_unconfirmed_etn_received(uint64_t height, const crypto::hash &txid, uint64_t amount)
Definition: wallet2.h:136
virtual void on_lw_etn_spent(uint64_t height, const crypto::hash &txid, uint64_t amount)
Definition: wallet2.h:137
virtual void on_lw_etn_received(uint64_t height, const crypto::hash &txid, uint64_t amount)
Definition: wallet2.h:135
void remove_obsolete_pool_txs(const std::vector< crypto::hash > &tx_hashes)
Definition: wallet2.cpp:3119
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:9457
bool hex_to_pod(const std::string &hex_str, t_pod_type &s)
Definition: string_tools.h:324
bool validate_hex(uint64_t length, const std::string &str)
Here is the call 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 8058 of file wallet2.cpp.

8058  {
8059 
8060  MDEBUG("LIGHTWALLET - Getting random outs");
8061 
8064 
8065  size_t light_wallet_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
8066 
8067  // Amounts to ask for
8068  // MyMonero api handle amounts and fees as strings
8069  for(size_t idx: selected_transfers) {
8070  const uint64_t ask_amount = m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount();
8071  std::ostringstream amount_ss;
8072  amount_ss << ask_amount;
8073  oreq.amounts.push_back(amount_ss.str());
8074  }
8075 
8076  oreq.count = light_wallet_requested_outputs_count;
8077  m_daemon_rpc_mutex.lock();
8078  bool r = invoke_http_json("/get_random_outs", oreq, ores, rpc_timeout, "POST");
8079  m_daemon_rpc_mutex.unlock();
8080  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
8081  THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
8082 
8083  // Check if we got enough outputs for each amount
8084  for(auto& out: ores.amount_outs) {
8085  const uint64_t out_amount = boost::lexical_cast<uint64_t>(out.amount);
8086  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));
8087  MDEBUG(out.outputs.size() << " outputs for amount "+ boost::lexical_cast<std::string>(out.amount) + " received from light wallet node");
8088  }
8089 
8090  MDEBUG("selected transfers size: " << selected_transfers.size());
8091 
8092  for(size_t idx: selected_transfers)
8093  {
8094  // Create new index
8095  outs.push_back(std::vector<get_outs_entry>());
8096  outs.back().reserve(fake_outputs_count + 1);
8097 
8098  // add real output first
8099  const transfer_details &td = m_transfers[idx];
8100  const uint64_t amount = td.is_rct() ? 0 : td.amount();
8101  outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), rct::commit(td.amount(), td.m_mask)));
8102  MDEBUG("added real output " << string_tools::pod_to_hex(td.get_public_key()));
8103 
8104  // Even if the lightwallet server returns random outputs, we pick them randomly.
8105  std::vector<size_t> order;
8106  order.resize(light_wallet_requested_outputs_count);
8107  for (size_t n = 0; n < order.size(); ++n)
8108  order[n] = n;
8109  std::shuffle(order.begin(), order.end(), std::default_random_engine(crypto::rand<unsigned>()));
8110 
8111 
8112  LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs with amounts " << print_etn(td.is_rct() ? 0 : td.amount()));
8113  MDEBUG("OUTS SIZE: " << outs.back().size());
8114  for (size_t o = 0; o < light_wallet_requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
8115  {
8116  // Random pick
8117  size_t i = order[o];
8118 
8119  // Find which random output key to use
8120  bool found_amount = false;
8121  size_t amount_key;
8122  for(amount_key = 0; amount_key < ores.amount_outs.size(); ++amount_key)
8123  {
8124  if(boost::lexical_cast<uint64_t>(ores.amount_outs[amount_key].amount) == amount) {
8125  found_amount = true;
8126  break;
8127  }
8128  }
8129  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" );
8130 
8131  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);
8132 
8133  // Convert light wallet string data to proper data structures
8134  crypto::public_key tx_public_key;
8135  rct::key mask = AUTO_VAL_INIT(mask); // decrypted mask - not used here
8136  rct::key rct_commit = AUTO_VAL_INIT(rct_commit);
8137  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");
8138  string_tools::hex_to_pod(ores.amount_outs[amount_key].outputs[i].public_key, tx_public_key);
8139  const uint64_t global_index = ores.amount_outs[amount_key].outputs[i].global_index;
8140  if(!light_wallet_parse_rct_str(ores.amount_outs[amount_key].outputs[i].rct, tx_public_key, 0, mask, rct_commit, false))
8141  rct_commit = rct::zeroCommit(td.amount());
8142 
8143  if (tx_add_fake_output(outs, global_index, tx_public_key, rct_commit, td.m_global_output_index, true)) {
8144  MDEBUG("added fake output " << ores.amount_outs[amount_key].outputs[i].public_key);
8145  MDEBUG("index " << global_index);
8146  }
8147  }
8148 
8149  THROW_WALLET_EXCEPTION_IF(outs.back().size() < fake_outputs_count + 1 , error::wallet_internal_error, "Not enough fake outputs found" );
8150 
8151  // Real output is the first. Shuffle outputs
8152  MTRACE(outs.back().size() << " outputs added. Sorting outputs by index:");
8153  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); });
8154 
8155  // Print output order
8156  for(auto added_out: outs.back())
8157  MTRACE(std::get<0>(added_out));
8158 
8159  }
8160 }
std::tuple< uint64_t, crypto::public_key, rct::key > get_outs_entry
Definition: chaingen.h:352
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:9432
key zeroCommit(etn_amount amount)
Definition: rctOps.cpp:322
key commit(etn_amount amount, const key &mask)
Definition: rctOps.cpp:336
tuple make_tuple()
Definition: gtest-tuple.h:675
Here is the call graph for this function:

◆ light_wallet_get_unspent_outs()

void tools::wallet2::light_wallet_get_unspent_outs ( )

Definition at line 9074 of file wallet2.cpp.

9075 {
9076  MDEBUG("Getting unspent outs");
9077 
9080 
9081  oreq.amount = "0";
9082  oreq.address = get_account().get_public_address_str(m_nettype);
9083  oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9084  // openMonero specific
9085  oreq.dust_threshold = boost::lexical_cast<std::string>(::config::DEFAULT_DUST_THRESHOLD);
9086  // below are required by openMonero api - but are not used.
9087  oreq.mixin = 0;
9088  oreq.use_dust = true;
9089 
9090 
9091  m_daemon_rpc_mutex.lock();
9092  bool r = invoke_http_json("/get_unspent_outs", oreq, ores, rpc_timeout, "POST");
9093  m_daemon_rpc_mutex.unlock();
9094  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_unspent_outs");
9095  THROW_WALLET_EXCEPTION_IF(ores.status == "error", error::wallet_internal_error, ores.reason);
9096 
9097  m_light_wallet_per_kb_fee = ores.per_kb_fee;
9098 
9099  std::unordered_map<crypto::hash,bool> transfers_txs;
9100  for(const auto &t: m_transfers)
9101  transfers_txs.emplace(t.m_txid,t.m_spent);
9102 
9103  MDEBUG("FOUND " << ores.outputs.size() <<" outputs");
9104 
9105  // return if no outputs found
9106  if(ores.outputs.empty())
9107  return;
9108 
9109  // Clear old outputs
9110  m_transfers.clear();
9111 
9112  for (const auto &o: ores.outputs) {
9113  bool spent = false;
9114  bool add_transfer = true;
9115  crypto::key_image unspent_key_image;
9116  crypto::public_key tx_public_key = AUTO_VAL_INIT(tx_public_key);
9117  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.tx_pub_key), error::wallet_internal_error, "Invalid tx_pub_key field");
9118  string_tools::hex_to_pod(o.tx_pub_key, tx_public_key);
9119 
9120  for (const std::string &ski: o.spend_key_images) {
9121  spent = false;
9122 
9123  // Check if key image is ours
9124  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, ski), error::wallet_internal_error, "Invalid key image");
9125  string_tools::hex_to_pod(ski, unspent_key_image);
9126  if(light_wallet_key_image_is_ours(unspent_key_image, tx_public_key, o.index)){
9127  MTRACE("Output " << o.public_key << " is spent. Key image: " << ski);
9128  spent = true;
9129  break;
9130  } {
9131  MTRACE("Unspent output found. " << o.public_key);
9132  }
9133  }
9134 
9135  // Check if tx already exists in m_transfers.
9136  crypto::hash txid;
9137  crypto::public_key tx_pub_key;
9139  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.tx_hash), error::wallet_internal_error, "Invalid tx_hash field");
9140  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.public_key), error::wallet_internal_error, "Invalid public_key field");
9141  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, o.tx_pub_key), error::wallet_internal_error, "Invalid tx_pub_key field");
9142  string_tools::hex_to_pod(o.tx_hash, txid);
9143  string_tools::hex_to_pod(o.public_key, public_key);
9144  string_tools::hex_to_pod(o.tx_pub_key, tx_pub_key);
9145 
9146  for(auto &t: m_transfers){
9147  if(t.get_public_key() == public_key) {
9148  t.m_spent = spent;
9149  add_transfer = false;
9150  break;
9151  }
9152  }
9153 
9154  if(!add_transfer)
9155  continue;
9156 
9157  m_transfers.push_back(boost::value_initialized<transfer_details>());
9158  transfer_details& td = m_transfers.back();
9159 
9160  td.m_block_height = o.height;
9161  td.m_global_output_index = o.global_index;
9162  td.m_txid = txid;
9163 
9164  // Add to extra
9165  add_tx_pub_key_to_extra(td.m_tx, tx_pub_key);
9166 
9167  td.m_key_image = unspent_key_image;
9168  td.m_key_image_known = !m_watch_only && !m_multisig;
9169  td.m_key_image_request = false;
9170  td.m_key_image_partial = m_multisig;
9171  td.m_amount = o.amount;
9172  td.m_pk_index = 0;
9173  td.m_internal_output_index = o.index;
9174  td.m_spent = spent;
9175  td.m_frozen = false;
9176 
9177  tx_out txout;
9178  txout.target = txout_to_key(public_key);
9179  txout.amount = td.m_amount;
9180 
9181  td.m_tx.vout.resize(td.m_internal_output_index + 1);
9182  td.m_tx.vout[td.m_internal_output_index] = txout;
9183 
9184  // Add unlock time and coinbase bool got from get_address_txs api call
9185  std::unordered_map<crypto::hash,address_tx>::const_iterator found = m_light_wallet_address_txs.find(txid);
9186  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");
9187  bool miner_tx = found->second.m_coinbase;
9188  td.m_tx.unlock_time = found->second.m_unlock_time;
9189 
9190  if (!o.rct.empty())
9191  {
9192  // Coinbase tx's
9193  if(miner_tx)
9194  {
9195  td.m_mask = rct::identity();
9196  }
9197  else
9198  {
9199  // rct txs
9200  // decrypt rct mask, calculate commit hash and compare against blockchain commit hash
9201  rct::key rct_commit;
9202  light_wallet_parse_rct_str(o.rct, tx_pub_key, td.m_internal_output_index, td.m_mask, rct_commit, true);
9203  bool valid_commit = (rct_commit == rct::commit(td.amount(), td.m_mask));
9204  if(!valid_commit)
9205  {
9206  MDEBUG("output index: " << o.global_index);
9207  MDEBUG("mask: " + string_tools::pod_to_hex(td.m_mask));
9208  MDEBUG("calculated commit: " + string_tools::pod_to_hex(rct::commit(td.amount(), td.m_mask)));
9209  MDEBUG("expected commit: " + string_tools::pod_to_hex(rct_commit));
9210  MDEBUG("amount: " << td.amount());
9211  }
9212  THROW_WALLET_EXCEPTION_IF(!valid_commit, error::wallet_internal_error, "Lightwallet: rct commit hash mismatch!");
9213  }
9214  td.m_rct = true;
9215  }
9216  else
9217  {
9218  td.m_mask = rct::identity();
9219  td.m_rct = false;
9220  }
9221  if(!spent)
9222  set_unspent(m_transfers.size()-1);
9223  m_key_images[td.m_key_image] = m_transfers.size()-1;
9224  m_pub_keys[td.get_public_key()] = m_transfers.size()-1;
9225  }
9226 }
bool add_tx_pub_key_to_extra(transaction &tx, const crypto::public_key &tx_pub_key)
txout_target_v target
Here is the call 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 9059 of file wallet2.cpp.

9060 {
9061  MDEBUG("Light wallet import wallet request");
9063  oreq.address = get_account().get_public_address_str(m_nettype);
9064  oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9065  m_daemon_rpc_mutex.lock();
9066  bool r = invoke_http_json("/import_wallet_request", oreq, response, rpc_timeout, "POST");
9067  m_daemon_rpc_mutex.unlock();
9068  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "import_wallet_request");
9069 
9070 
9071  return true;
9072 }
Here is the call 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 9457 of file wallet2.cpp.

9458 {
9459  // Lookup key image from cache
9460  std::map<uint64_t, crypto::key_image> index_keyimage_map;
9461  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);
9462  if(found_pub_key != m_key_image_cache.end()) {
9463  // pub key found. key image for index cached?
9464  index_keyimage_map = found_pub_key->second;
9465  std::map<uint64_t,crypto::key_image>::const_iterator index_found = index_keyimage_map.find(out_index);
9466  if(index_found != index_keyimage_map.end())
9467  return key_image == index_found->second;
9468  }
9469 
9470  // Not in cache - calculate key image
9471  crypto::key_image calculated_key_image;
9472  cryptonote::keypair in_ephemeral;
9473 
9474  // Subaddresses aren't supported in mymonero/openmonero yet. Roll out the original scheme:
9475  // compute D = a*R
9476  // compute P = Hs(D || i)*G + B
9477  // compute x = Hs(D || i) + b (and check if P==x*G)
9478  // compute I = x*Hp(P)
9479  const account_keys& ack = get_account().get_keys();
9480  crypto::key_derivation derivation;
9481  bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, derivation);
9482  CHECK_AND_ASSERT_MES(r, false, "failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
9483 
9484  r = crypto::derive_public_key(derivation, out_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub);
9485  CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key (" << derivation << ", " << out_index << ", " << ack.m_account_address.m_spend_public_key << ")");
9486 
9487  crypto::derive_secret_key(derivation, out_index, ack.m_spend_secret_key, in_ephemeral.sec);
9488  crypto::public_key out_pkey_test;
9489  r = crypto::secret_key_to_public_key(in_ephemeral.sec, out_pkey_test);
9490  CHECK_AND_ASSERT_MES(r, false, "failed to secret_key_to_public_key(" << in_ephemeral.sec << ")");
9491  CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_pkey_test, false, "derived secret key doesn't match derived public key");
9492 
9493  crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, calculated_key_image);
9494 
9495  index_keyimage_map.emplace(out_index, calculated_key_image);
9496  m_key_image_cache.emplace(tx_public_key, index_keyimage_map);
9497  return key_image == calculated_key_image;
9498 }
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
void derive_secret_key(const key_derivation &derivation, std::size_t output_index, const secret_key &base, secret_key &derived_key)
Definition: crypto.h:280
void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image)
Definition: crypto.h:322
Here is the call graph for this function:

◆ light_wallet_login()

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

Definition at line 9030 of file wallet2.cpp.

9031 {
9032  MDEBUG("Light wallet login request");
9033  m_light_wallet_connected = false;
9036  request.address = get_account().get_public_address_str(m_nettype);
9037  request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
9038  // Always create account if it doesn't exist.
9039  request.create_account = true;
9040  m_daemon_rpc_mutex.lock();
9041  bool connected = invoke_http_json("/login", request, response, rpc_timeout, "POST");
9042  m_daemon_rpc_mutex.unlock();
9043  // MyMonero doesn't send any status message. OpenMonero does.
9044  m_light_wallet_connected = connected && (response.status.empty() || response.status == "success");
9045  new_address = response.new_address;
9046  MDEBUG("Status: " << response.status);
9047  MDEBUG("Reason: " << response.reason);
9048  MDEBUG("New wallet: " << response.new_address);
9049  if(m_light_wallet_connected)
9050  {
9051  // Clear old data on successful login.
9052  // m_transfers.clear();
9053  // m_payments.clear();
9054  // m_unconfirmed_payments.clear();
9055  }
9056  return m_light_wallet_connected;
9057 }
Here is the call 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 9432 of file wallet2.cpp.

9433 {
9434  // rct string is empty if output is non RCT
9435  if (rct_string.empty())
9436  return false;
9437  // rct_string is a string with length 64+64+64 (<rct commit> + <encrypted mask> + <rct amount>)
9438  rct::key encrypted_mask;
9439  std::string rct_commit_str = rct_string.substr(0,64);
9440  std::string encrypted_mask_str = rct_string.substr(64,64);
9441  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, rct_commit_str), error::wallet_internal_error, "Invalid rct commit hash: " + rct_commit_str);
9442  THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, encrypted_mask_str), error::wallet_internal_error, "Invalid rct mask: " + encrypted_mask_str);
9443  string_tools::hex_to_pod(rct_commit_str, rct_commit);
9444  string_tools::hex_to_pod(encrypted_mask_str, encrypted_mask);
9445  if (decrypt) {
9446  // Decrypt the mask
9447  crypto::key_derivation derivation;
9448  bool r = generate_key_derivation(tx_pub_key, get_account().get_keys().m_view_secret_key, derivation);
9449  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
9450  crypto::secret_key scalar;
9451  crypto::derivation_to_scalar(derivation, internal_output_index, scalar);
9452  sc_sub(decrypted_mask.bytes,encrypted_mask.bytes,rct::hash_to_scalar(rct::sk2rct(scalar)).bytes);
9453  }
9454  return true;
9455 }
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:

◆ load()

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

Definition at line 5723 of file wallet2.cpp.

5724 {
5725  clear();
5726  prepare_file_names(wallet_);
5727 
5728  boost::system::error_code e;
5729  bool exists = boost::filesystem::exists(m_keys_file, e);
5730  THROW_WALLET_EXCEPTION_IF(e || !exists, error::file_not_found, m_keys_file);
5731  lock_keys_file();
5732  THROW_WALLET_EXCEPTION_IF(!is_keys_file_locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program");
5733 
5734  // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
5735  unlock_keys_file();
5736  if (!load_keys(m_keys_file, password))
5737  {
5739  }
5740  LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype));
5741  lock_keys_file();
5742 
5743  wallet_keys_unlocker unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, password);
5744 
5745  //keys loaded ok!
5746  //try to load wallet file. but even if we failed, it is not big problem
5747  if(!boost::filesystem::exists(m_wallet_file, e) || e)
5748  {
5749  LOG_PRINT_L0("file not found: " << m_wallet_file << ", starting with empty blockchain");
5750  m_account_public_address = m_account.get_keys().m_account_address;
5751  }
5752  else
5753  {
5754  wallet2::cache_file_data cache_file_data;
5755  std::string buf;
5756  bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf, std::numeric_limits<size_t>::max());
5758 
5759  // try to read it as an encrypted cache
5760  try
5761  {
5762  LOG_PRINT_L1("Trying to decrypt cache data");
5763 
5764  r = ::serialization::parse_binary(buf, cache_file_data);
5765  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + '\"');
5766  std::string cache_data;
5767  cache_data.resize(cache_file_data.cache_data.size());
5768  crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cache_data[0]);
5769 
5770  try {
5771  std::stringstream iss;
5772  iss << cache_data;
5774  ar >> *this;
5775  }
5776  catch(...)
5777  {
5778  // try with previous scheme: direct from keys
5779  crypto::chacha_key key;
5780  generate_chacha_key_from_secret_keys(key);
5781  crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]);
5782  try {
5783  std::stringstream iss;
5784  iss << cache_data;
5786  ar >> *this;
5787  }
5788  catch (...)
5789  {
5790  crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]);
5791  try
5792  {
5793  std::stringstream iss;
5794  iss << cache_data;
5796  ar >> *this;
5797  }
5798  catch (...)
5799  {
5800  LOG_PRINT_L0("Failed to open portable binary, trying unportable");
5801  boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
5802  std::stringstream iss;
5803  iss.str("");
5804  iss << cache_data;
5805  boost::archive::binary_iarchive ar(iss);
5806  ar >> *this;
5807  }
5808  }
5809  }
5810  }
5811  catch (...)
5812  {
5813  LOG_PRINT_L1("Failed to load encrypted cache, trying unencrypted");
5814  try {
5815  std::stringstream iss;
5816  iss << buf;
5818  ar >> *this;
5819  }
5820  catch (...)
5821  {
5822  LOG_PRINT_L0("Failed to open portable binary, trying unportable");
5823  boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
5824  std::stringstream iss;
5825  iss.str("");
5826  iss << buf;
5827  boost::archive::binary_iarchive ar(iss);
5828  ar >> *this;
5829  }
5830  }
5832  m_account_public_address.m_spend_public_key != m_account.get_keys().m_account_address.m_spend_public_key ||
5833  m_account_public_address.m_view_public_key != m_account.get_keys().m_account_address.m_view_public_key,
5834  error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file);
5835  }
5836 
5837  cryptonote::block genesis;
5838  generate_genesis(genesis);
5839  crypto::hash genesis_hash = get_block_hash(genesis);
5840 
5841  if (m_blockchain.empty())
5842  {
5843  m_blockchain.push_back(genesis_hash);
5844  m_last_block_reward = cryptonote::get_outs_etn_amount(genesis.miner_tx);
5845  }
5846  else
5847  {
5848  check_genesis(genesis_hash);
5849  }
5850 
5851  trim_hashchain();
5852 
5853  if (get_num_subaddress_accounts() == 0)
5854  add_subaddress_account(tr("Primary account"));
5855 
5856  try
5857  {
5858  find_and_save_rings(false);
5859  }
5860  catch (const std::exception &e)
5861  {
5862  MERROR("Failed to save rings, will try again next time");
5863  }
5864 
5865  try
5866  {
5867  m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file);
5868  }
5869  catch (const std::exception &e)
5870  {
5871  MERROR("Failed to initialize MMS, it will be unusable");
5872  }
5873 }
void chacha8(const void *data, size_t length, const uint8_t *key, const uint8_t *iv, char *cipher)
void read_from_file(const multisig_wallet_state &state, const std::string &filename)
bool is_keys_file_locked() const
Definition: wallet2.cpp:8026
bool lock_keys_file()
Definition: wallet2.cpp:8004
mms::multisig_wallet_state get_multisig_wallet_state() const
Definition: wallet2.cpp:13395
friend class wallet_keys_unlocker
Definition: wallet2.h:213
bool find_and_save_rings(bool force=true)
Definition: wallet2.cpp:7899
bool parse_binary(const std::string &blob, T &v)
Definition: binary_utils.h:41
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
Definition: slow_memmem.cpp:74
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 7348 of file wallet2.cpp.

7349 {
7350  if(!parse_multisig_tx_from_str(s, exported_txs))
7351  {
7352  LOG_PRINT_L0("Failed to parse multisig transaction from string");
7353  return false;
7354  }
7355 
7356  LOG_PRINT_L1("Loaded multisig tx unsigned data from binary: " << exported_txs.m_ptx.size() << " transactions");
7357  for (auto &ptx: exported_txs.m_ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(ptx.tx));
7358 
7359  if (accept_func && !accept_func(exported_txs))
7360  {
7361  LOG_PRINT_L1("Transactions rejected by callback");
7362  return false;
7363  }
7364 
7365  const bool is_signed = exported_txs.m_signers.size() >= m_multisig_threshold;
7366  if (is_signed)
7367  {
7368  for (const auto &ptx: exported_txs.m_ptx)
7369  {
7370  const crypto::hash txid = get_transaction_hash(ptx.tx);
7371  if (store_tx_info())
7372  {
7373  m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
7374  m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
7375  }
7376  }
7377  }
7378 
7379  return true;
7380 }
bool parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const
Definition: wallet2.cpp:7304
Here is the call 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 7382 of file wallet2.cpp.

7383 {
7384  std::string s;
7385  boost::system::error_code errcode;
7386 
7387  if (!boost::filesystem::exists(filename, errcode))
7388  {
7389  LOG_PRINT_L0("File " << filename << " does not exist: " << errcode);
7390  return false;
7391  }
7392  if (!epee::file_io_utils::load_file_to_string(filename.c_str(), s))
7393  {
7394  LOG_PRINT_L0("Failed to load from " << filename);
7395  return false;
7396  }
7397 
7398  if (!load_multisig_tx(s, exported_txs, accept_func))
7399  {
7400  LOG_PRINT_L0("Failed to parse multisig tx data from " << filename);
7401  return false;
7402  }
7403  return true;
7404 }
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:7348
Here is the call 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 7120 of file wallet2.cpp.

7121 {
7122  std::string s;
7123  boost::system::error_code errcode;
7124  signed_tx_set signed_txs;
7125 
7126  if (!boost::filesystem::exists(signed_filename, errcode))
7127  {
7128  LOG_PRINT_L0("File " << signed_filename << " does not exist: " << errcode);
7129  return false;
7130  }
7131 
7132  if (!epee::file_io_utils::load_file_to_string(signed_filename.c_str(), s))
7133  {
7134  LOG_PRINT_L0("Failed to load from " << signed_filename);
7135  return false;
7136  }
7137 
7138  return parse_tx_from_str(s, ptx, accept_func);
7139 }
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:7141
Here is the call 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 6813 of file wallet2.cpp.

6814 {
6815  std::string s;
6816  boost::system::error_code errcode;
6817 
6818  if (!boost::filesystem::exists(unsigned_filename, errcode))
6819  {
6820  LOG_PRINT_L0("File " << unsigned_filename << " does not exist: " << errcode);
6821  return false;
6822  }
6823  if (!epee::file_io_utils::load_file_to_string(unsigned_filename.c_str(), s))
6824  {
6825  LOG_PRINT_L0("Failed to load from " << unsigned_filename);
6826  return false;
6827  }
6828 
6829  return parse_unsigned_tx_from_str(s, exported_txs);
6830 }
bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const
Definition: wallet2.cpp:6832
Here is the call graph for this function:

◆ lock_keys_file()

bool tools::wallet2::lock_keys_file ( )

Definition at line 8004 of file wallet2.cpp.

8005 {
8006  if (m_keys_file_locker)
8007  {
8008  MDEBUG(m_keys_file << " is already locked.");
8009  return false;
8010  }
8011  m_keys_file_locker.reset(new tools::file_locker(m_keys_file));
8012  return true;
8013 }

◆ 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 1260 of file wallet2.cpp.

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

◆ 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 1232 of file wallet2.cpp.

1234 {
1235  const options opts{};
1236  auto pwd = get_password(vm, opts, password_prompter, false);
1237  if (!pwd)
1238  {
1239  return {nullptr, password_container{}};
1240  }
1241  auto wallet = make_basic(vm, unattended, opts, password_prompter);
1242  if (wallet && !wallet_file.empty())
1243  {
1244  wallet->load(wallet_file, pwd->password());
1245  }
1246  return {std::move(wallet), std::move(*pwd)};
1247 }
Here is the call graph for this function:
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 1226 of file wallet2.cpp.

1227 {
1228  const options opts{};
1229  return generate_from_json(json_file, vm, unattended, opts, password_prompter);
1230 }
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 5035 of file wallet2.cpp.

5039 {
5040  CHECK_AND_ASSERT_THROW_MES(!view_keys.empty(), "empty view keys");
5041  CHECK_AND_ASSERT_THROW_MES(view_keys.size() == spend_keys.size(), "Mismatched view/spend key sizes");
5042  CHECK_AND_ASSERT_THROW_MES(threshold > 1 && threshold <= spend_keys.size() + 1, "Invalid threshold");
5043 
5044  std::string extra_multisig_info;
5045  std::vector<crypto::secret_key> multisig_keys;
5046  rct::key spend_pkey = rct::identity();
5047  rct::key spend_skey;
5048  std::vector<crypto::public_key> multisig_signers;
5049 
5050  // decrypt keys
5052  if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
5053  {
5054  crypto::chacha_key chacha_key;
5055  crypto::generate_chacha_key(password.data(), password.size(), chacha_key, m_kdf_rounds);
5056  m_account.encrypt_viewkey(chacha_key);
5057  m_account.decrypt_keys(chacha_key);
5058  keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this, chacha_key]() { m_account.encrypt_keys(chacha_key); m_account.decrypt_viewkey(chacha_key); });
5059  }
5060 
5061  // In common multisig scheme there are 4 types of key exchange rounds:
5062  // 1. First round is exchange of view secret keys and public spend keys.
5063  // 2. Middle round is exchange of derivations: Ki = b * Mj, where b - spend secret key,
5064  // M - public multisig key (in first round it equals to public spend key), K - new public multisig key.
5065  // 3. Secret spend establishment round sets your secret multisig keys as follows: kl = H(Ml), where M - is *your* public multisig key,
5066  // k - secret multisig key used to sign transactions. k and M are sets of keys, of course.
5067  // And secret spend key as the sum of all participant's secret multisig keys
5068  // 4. Last round establishes multisig wallet's public spend key. Participants exchange their public multisig keys
5069  // and calculate common spend public key as sum of all unique participants' public multisig keys.
5070  // 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.
5071 
5072  // IMPORTANT: wallet's public spend key is not equal to secret_spend_key * G!
5073  // Wallet's public spend key is the sum of unique public multisig keys of all participants.
5074  // secret_spend_key * G = public signer key
5075 
5076  if (threshold == spend_keys.size() + 1)
5077  {
5078  // In N / N case we only need to do one round and calculate secret multisig keys and new secret spend key
5079  MINFO("Creating spend key...");
5080 
5081  // Calculates all multisig keys and spend key
5082  cryptonote::generate_multisig_N_N(get_account().get_keys(), spend_keys, multisig_keys, spend_skey, spend_pkey);
5083 
5084  // Our signer key is b * G, where b is secret spend key.
5085  multisig_signers = spend_keys;
5086  multisig_signers.push_back(get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key));
5087  }
5088  else
5089  {
5090  // We just got public spend keys of all participants and deriving multisig keys (set of Mi = b * Bi).
5091  // note that derivations are public keys as DH exchange suppose it to be
5092  auto derivations = cryptonote::generate_multisig_derivations(get_account().get_keys(), spend_keys);
5093 
5094  spend_pkey = rct::identity();
5095  multisig_signers = std::vector<crypto::public_key>(spend_keys.size() + 1, crypto::null_pkey);
5096 
5097  if (threshold == spend_keys.size())
5098  {
5099  // N - 1 / N case
5100 
5101  // We need an extra step, so we package all the composite public keys
5102  // we know about, and make a signed string out of them
5103  MINFO("Creating spend key...");
5104 
5105  // Calculating set of our secret multisig keys as follows: mi = H(Mi),
5106  // where mi - secret multisig key, Mi - others' participants public multisig key
5107  multisig_keys = cryptonote::calculate_multisig_keys(derivations);
5108 
5109  // calculating current participant's spend secret key as sum of all secret multisig keys for current participant.
5110  // IMPORTANT: participant's secret spend key is not an entire wallet's secret spend!
5111  // Entire wallet's secret spend is sum of all unique secret multisig keys
5112  // among all of participants and is not held by anyone!
5113  spend_skey = rct::sk2rct(cryptonote::calculate_multisig_signer_key(multisig_keys));
5114 
5115  // Preparing data for the last round to calculate common public spend key. The data contains public multisig keys.
5116  extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, secret_keys_to_public_keys(multisig_keys), rct::rct2sk(spend_skey));
5117  }
5118  else
5119  {
5120  // M / N case
5121  MINFO("Preparing keys for next exchange round...");
5122 
5123  // Preparing data for middle round - packing new public multisig keys to exchage with others.
5124  extra_multisig_info = pack_multisignature_keys(MULTISIG_EXTRA_INFO_MAGIC, derivations, m_account.get_keys().m_spend_secret_key);
5125  spend_skey = rct::sk2rct(m_account.get_keys().m_spend_secret_key);
5126 
5127  // Need to store middle keys to be able to proceed in case of wallet shutdown.
5128  m_multisig_derivations = derivations;
5129  }
5130  }
5131 
5132  if (!m_original_keys_available)
5133  {
5134  // Save the original i.e. non-multisig keys so the MMS can continue to use them to encrypt and decrypt messages
5135  // (making a wallet multisig overwrites those keys, see account_base::make_multisig)
5136  m_original_address = m_account.get_keys().m_account_address;
5137  m_original_view_secret_key = m_account.get_keys().m_view_secret_key;
5138  m_original_keys_available = true;
5139  }
5140 
5141  clear();
5142  MINFO("Creating view key...");
5143  crypto::secret_key view_skey = cryptonote::generate_multisig_view_secret_key(get_account().get_keys().m_view_secret_key, view_keys);
5144 
5145  MINFO("Creating multisig address...");
5146  CHECK_AND_ASSERT_THROW_MES(m_account.make_multisig(view_skey, rct::rct2sk(spend_skey), rct::rct2pk(spend_pkey), multisig_keys),
5147  "Failed to create multisig wallet due to bad keys");
5148  memwipe(&spend_skey, sizeof(rct::key));
5149 
5150  init_type(hw::device::device_type::SOFTWARE);
5151  m_original_keys_available = true;
5152  m_multisig = true;
5153  m_multisig_threshold = threshold;
5154  m_multisig_signers = multisig_signers;
5155  ++m_multisig_rounds_passed;
5156 
5157  // re-encrypt keys
5158  keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
5159 
5160  create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
5161 
5162  setup_new_blockchain();
5163 
5164  if (!m_wallet_file.empty())
5165  store();
5166 
5167  return extra_multisig_info;
5168 }
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 5356 of file wallet2.cpp.

5359 {
5360  std::vector<crypto::secret_key> secret_keys(info.size());
5361  std::vector<crypto::public_key> public_keys(info.size());
5362  unpack_multisig_info(info, public_keys, secret_keys);
5363  return make_multisig(password, secret_keys, public_keys, threshold);
5364 }
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:5356

◆ 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 7276 of file wallet2.cpp.

7277 {
7278  multisig_tx_set txs;
7279  txs.m_ptx = ptx_vector;
7280 
7281  for (const auto &msk: get_account().get_multisig_keys())
7282  {
7284  for (auto &ptx: txs.m_ptx) for (auto &sig: ptx.multisig_sigs) sig.signing_keys.insert(pkey);
7285  }
7286 
7287  txs.m_signers.insert(get_multisig_signer_public_key());
7288  return txs;
7289 }

◆ 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 1249 of file wallet2.cpp.

1250 {
1251  const options opts{};
1252  auto pwd = get_password(vm, opts, password_prompter, true);
1253  if (!pwd)
1254  {
1255  return {nullptr, password_container{}};
1256  }
1257  return {make_basic(vm, unattended, opts, password_prompter), std::move(*pwd)};
1258 }
Here is the call graph for this function:

◆ 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 13035 of file wallet2.cpp.

13036 {
13039  {
13040  error = std::string("wrong address: ") + address;
13041  return std::string();
13042  }
13043 
13044  // we want only one payment id
13045  if (info.has_payment_id && !payment_id.empty())
13046  {
13047  error = "A single payment id is allowed";
13048  return std::string();
13049  }
13050 
13051  if (!payment_id.empty())
13052  {
13053  crypto::hash pid32;
13054  crypto::hash8 pid8;
13055  if (!wallet2::parse_long_payment_id(payment_id, pid32) && !parse_short_payment_id(payment_id, pid8))
13056  {
13057  error = "Invalid payment id";
13058  return std::string();
13059  }
13060  }
13061 
13062  std::string uri = "electroneum:" + address;
13063  unsigned int n_fields = 0;
13064 
13065  if (!payment_id.empty())
13066  {
13067  uri += (n_fields++ ? "&" : "?") + std::string("tx_payment_id=") + payment_id;
13068  }
13069 
13070  if (amount > 0)
13071  {
13072  // URI encoded amount is in decimal units, not atomic units
13073  uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + cryptonote::print_etn(amount);
13074  }
13075 
13076  if (!recipient_name.empty())
13077  {
13078  uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + epee::net_utils::conver_to_url_format(recipient_name);
13079  }
13080 
13081  if (!tx_description.empty())
13082  {
13083  uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::conver_to_url_format(tx_description);
13084  }
13085 
13086  return uri;
13087 }
static bool parse_long_payment_id(const std::string &payment_id_str, crypto::hash &payment_id)
Definition: wallet2.cpp:5602
static bool parse_short_payment_id(const std::string &payment_id_str, crypto::hash8 &payment_id)
Definition: wallet2.cpp:5615
POD_CLASS hash8
Definition: hash.h:53
bool get_account_address_from_str(address_parse_info &info, network_type nettype, std::string const &str)
Here is the call graph for this function:

◆ merge_destinations() [1/2]

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

Definition at line 1078 of file wallet2.h.

1078 { return m_merge_destinations; }

◆ merge_destinations() [2/2]

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

Definition at line 1077 of file wallet2.h.

1077 { m_merge_destinations = merge; }

◆ multisig()

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

Definition at line 5524 of file wallet2.cpp.

5525 {
5526  if (!m_multisig)
5527  return false;
5528  if (threshold)
5529  *threshold = m_multisig_threshold;
5530  if (total)
5531  *total = m_multisig_signers.size();
5532  if (ready)
5533  *ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity()));
5534  return true;
5535 }
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 818 of file wallet2.h.

818 { 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 5602 of file wallet2.cpp.

5603 {
5604  cryptonote::blobdata payment_id_data;
5605  if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data))
5606  return false;
5607 
5608  if(sizeof(crypto::hash) != payment_id_data.size())
5609  return false;
5610 
5611  payment_id = *reinterpret_cast<const crypto::hash*>(payment_id_data.data());
5612  return true;
5613 }
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 7304 of file wallet2.cpp.

7305 {
7306  const size_t magiclen = strlen(MULTISIG_UNSIGNED_TX_PREFIX);
7307  if (strncmp(multisig_tx_st.c_str(), MULTISIG_UNSIGNED_TX_PREFIX, magiclen))
7308  {
7309  LOG_PRINT_L0("Bad magic from multisig tx data");
7310  return false;
7311  }
7312  try
7313  {
7314  multisig_tx_st = decrypt_with_view_secret_key(std::string(multisig_tx_st, magiclen));
7315  }
7316  catch (const std::exception &e)
7317  {
7318  LOG_PRINT_L0("Failed to decrypt multisig tx data: " << e.what());
7319  return false;
7320  }
7321  try
7322  {
7323  std::istringstream iss(multisig_tx_st);
7325  ar >> exported_txs;
7326  }
7327  catch (...)
7328  {
7329  LOG_PRINT_L0("Failed to parse multisig tx data");
7330  return false;
7331  }
7332 
7333  // sanity checks
7334  for (const auto &ptx: exported_txs.m_ptx)
7335  {
7336  CHECK_AND_ASSERT_MES(ptx.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched selected_transfers/vin sizes");
7337  for (size_t idx: ptx.selected_transfers)
7338  CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range");
7339  CHECK_AND_ASSERT_MES(ptx.construction_data.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched cd selected_transfers/vin sizes");
7340  for (size_t idx: ptx.construction_data.selected_transfers)
7341  CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range");
7342  CHECK_AND_ASSERT_MES(ptx.construction_data.sources.size() == ptx.tx.vin.size(), false, "Mismatched sources/vin sizes");
7343  }
7344 
7345  return true;
7346 }
#define MULTISIG_UNSIGNED_TX_PREFIX
Definition: wallet2.cpp:108

◆ parse_payment_id()

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

Definition at line 5628 of file wallet2.cpp.

5629 {
5630  if (parse_long_payment_id(payment_id_str, payment_id))
5631  return true;
5632  crypto::hash8 payment_id8;
5633  if (parse_short_payment_id(payment_id_str, payment_id8))
5634  {
5635  memcpy(payment_id.data, payment_id8.data, 8);
5636  memset(payment_id.data + 8, 0, 24);
5637  return true;
5638  }
5639  return false;
5640 }
Here is the call 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 5615 of file wallet2.cpp.

5616 {
5617  cryptonote::blobdata payment_id_data;
5618  if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data))
5619  return false;
5620 
5621  if(sizeof(crypto::hash8) != payment_id_data.size())
5622  return false;
5623 
5624  payment_id = *reinterpret_cast<const crypto::hash8*>(payment_id_data.data());
5625  return true;
5626 }
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 7141 of file wallet2.cpp.

7142 {
7143  std::string s = signed_tx_st;
7144  boost::system::error_code errcode;
7145  signed_tx_set signed_txs;
7146 
7147  const size_t magiclen = strlen(SIGNED_TX_PREFIX) - 1;
7148  if (strncmp(s.c_str(), SIGNED_TX_PREFIX, magiclen))
7149  {
7150  LOG_PRINT_L0("Bad magic from signed transaction");
7151  return false;
7152  }
7153  s = s.substr(magiclen);
7154  const char version = s[0];
7155  s = s.substr(1);
7156  if (version == '\003')
7157  {
7158  try
7159  {
7160  std::istringstream iss(s);
7162  ar >> signed_txs;
7163  }
7164  catch (const std::exception &e)
7165  {
7166  LOG_PRINT_L0("Failed to parse data from signed transaction: " << e.what());
7167  return false;
7168  }
7169  catch(...)
7170  {
7171  LOG_PRINT_L0("Failed to parse data from signed transaction");
7172  return false;
7173  }
7174  }
7175  else if (version == '\004')
7176  {
7177  try
7178  {
7180  try
7181  {
7182  std::istringstream iss(s);
7184  ar >> signed_txs;
7185  }
7186  catch (const std::exception &e)
7187  {
7188  LOG_PRINT_L0("Failed to parse decrypted data from signed transaction: " << e.what());
7189  return false;
7190  }
7191  }
7192  catch (const std::exception &e)
7193  {
7194  LOG_PRINT_L0("Failed to decrypt signed transaction: " << e.what());
7195  return false;
7196  }
7197  catch(...)
7198  {
7199  LOG_PRINT_L0("Failed to decrypt signed transaction");
7200  return false;
7201  }
7202  }
7203  else
7204  {
7205  LOG_PRINT_L0("Unsupported version in signed transaction");
7206  return false;
7207  }
7208  LOG_PRINT_L0("Loaded signed tx data from binary: " << signed_txs.ptx.size() << " transactions");
7209  for (auto &c_ptx: signed_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(c_ptx.tx));
7210 
7211  if (accept_func && !accept_func(signed_txs))
7212  {
7213  LOG_PRINT_L1("Transactions rejected by callback");
7214  return false;
7215  }
7216 
7217  // import key images
7218  bool r = import_key_images(signed_txs.key_images);
7219  if (!r) return false;
7220 
7221  // remember key images for this tx, for when we get those txes from the blockchain
7222  for (const auto &e: signed_txs.tx_key_images)
7223  m_cold_key_images.insert(e);
7224 
7225  ptx = signed_txs.ptx;
7226 
7227  return true;
7228 }
#define SIGNED_TX_PREFIX
Definition: wallet2.cpp:107
Here is the call 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 6832 of file wallet2.cpp.

6833 {
6834  std::string s = unsigned_tx_st;
6835  const size_t magiclen = strlen(UNSIGNED_TX_PREFIX) - 1;
6836  if (strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen))
6837  {
6838  LOG_PRINT_L0("Bad magic from unsigned tx");
6839  return false;
6840  }
6841  s = s.substr(magiclen);
6842  const char version = s[0];
6843  s = s.substr(1);
6844  if (version == '\003')
6845  {
6846  try
6847  {
6848  std::istringstream iss(s);
6850  ar >> exported_txs;
6851  }
6852  catch (const std::exception &e)
6853  {
6854  LOG_PRINT_L0("Failed to parse data from unsigned tx: " << e.what());
6855  return false;
6856  }
6857  catch (...)
6858  {
6859  LOG_PRINT_L0("Failed to parse data from unsigned tx");
6860  return false;
6861  }
6862  }
6863  else if (version == '\004')
6864  {
6865  try
6866  {
6868  try
6869  {
6870  std::istringstream iss(s);
6872  ar >> exported_txs;
6873  }
6874  catch (const std::exception &e)
6875  {
6876  LOG_PRINT_L0("Failed to parse decrypted data from unsigned tx: " << e.what());
6877  return false;
6878  }
6879  }
6880  catch (const std::exception &e)
6881  {
6882  LOG_PRINT_L0("Failed to decrypt unsigned tx: " << e.what());
6883  return false;
6884  }
6885  catch(...)
6886  {
6887  LOG_PRINT_L0("Failed to parse decrypted data from unsigned tx");
6888  return false;
6889  }
6890  }
6891  else
6892  {
6893  LOG_PRINT_L0("Unsupported version in unsigned tx");
6894  return false;
6895  }
6896  LOG_PRINT_L1("Loaded tx unsigned data from binary: " << exported_txs.txes.size() << " transactions");
6897 
6898  return true;
6899 }

◆ 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 13089 of file wallet2.cpp.

13090 {
13091  if (uri.substr(0, 12) != "electroneum:")
13092  {
13093  error = std::string("URI has wrong scheme (expected \"electroneum:\"): ") + uri;
13094  return false;
13095  }
13096 
13097  std::string remainder = uri.substr(12);
13098  const char *ptr = strchr(remainder.c_str(), '?');
13099  address = ptr ? remainder.substr(0, ptr-remainder.c_str()) : remainder;
13100 
13103  {
13104  error = std::string("URI has wrong address: ") + address;
13105  return false;
13106  }
13107  if (!strchr(remainder.c_str(), '?'))
13108  return true;
13109 
13110  std::vector<std::string> arguments;
13111  std::string body = remainder.substr(address.size() + 1);
13112  if (body.empty())
13113  return true;
13114  boost::split(arguments, body, boost::is_any_of("&"));
13115  std::set<std::string> have_arg;
13116  for (const auto &arg: arguments)
13117  {
13118  std::vector<std::string> kv;
13119  boost::split(kv, arg, boost::is_any_of("="));
13120  if (kv.size() != 2)
13121  {
13122  error = std::string("URI has wrong parameter: ") + arg;
13123  return false;
13124  }
13125  if (have_arg.find(kv[0]) != have_arg.end())
13126  {
13127  error = std::string("URI has more than one instance of " + kv[0]);
13128  return false;
13129  }
13130  have_arg.insert(kv[0]);
13131 
13132  if (kv[0] == "tx_amount")
13133  {
13134  amount = 0;
13135  if (!cryptonote::parse_amount(amount, kv[1]))
13136  {
13137  error = std::string("URI has invalid amount: ") + kv[1];
13138  return false;
13139  }
13140  }
13141  else if (kv[0] == "tx_payment_id")
13142  {
13143  if (info.has_payment_id)
13144  {
13145  error = "Separate payment id given with an integrated address";
13146  return false;
13147  }
13151  {
13152  error = "Invalid payment id: " + kv[1];
13153  return false;
13154  }
13155  payment_id = kv[1];
13156  }
13157  else if (kv[0] == "recipient_name")
13158  {
13159  recipient_name = epee::net_utils::convert_from_url_format(kv[1]);
13160  }
13161  else if (kv[0] == "tx_description")
13162  {
13163  tx_description = epee::net_utils::convert_from_url_format(kv[1]);
13164  }
13165  else
13166  {
13167  unknown_parameters.push_back(arg);
13168  }
13169  }
13170  return true;
13171 }
bool parse_amount(uint64_t &amount, const std::string &str_amount_)
Here is the call graph for this function:

◆ path()

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

Definition at line 5917 of file wallet2.cpp.

5918 {
5919  return m_wallet_file;
5920 }

◆ 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 6539 of file wallet2.cpp.

6540 {
6541  return pop_best_value_from(m_transfers, unused_indices, selected_transfers, smallest);
6542 }
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:6490

◆ 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 6490 of file wallet2.cpp.

6491 {
6492  std::vector<size_t> candidates;
6493  float best_relatedness = 1.0f;
6494  for (size_t n = 0; n < unused_indices.size(); ++n)
6495  {
6496  const transfer_details &candidate = transfers[unused_indices[n]];
6497  float relatedness = 0.0f;
6498  for (std::vector<size_t>::const_iterator i = selected_transfers.begin(); i != selected_transfers.end(); ++i)
6499  {
6500  float r = get_output_relatedness(candidate, transfers[*i]);
6501  if (r > relatedness)
6502  {
6503  relatedness = r;
6504  if (relatedness == 1.0f)
6505  break;
6506  }
6507  }
6508 
6509  if (relatedness < best_relatedness)
6510  {
6511  best_relatedness = relatedness;
6512  candidates.clear();
6513  }
6514 
6515  if (relatedness == best_relatedness)
6516  candidates.push_back(n);
6517  }
6518 
6519  // we have all the least related outputs in candidates, so we can pick either
6520  // the smallest, or a random one, depending on request
6521  size_t idx;
6522  if (smallest)
6523  {
6524  idx = 0;
6525  for (size_t n = 0; n < candidates.size(); ++n)
6526  {
6527  const transfer_details &td = transfers[unused_indices[candidates[n]]];
6528  if (td.amount() < transfers[unused_indices[candidates[idx]]].amount())
6529  idx = n;
6530  }
6531  }
6532  else
6533  {
6534  idx = crypto::rand_idx(candidates.size());
6535  }
6536  return pop_index (unused_indices, candidates[idx]);
6537 }
Here is the call graph for this function:

◆ print_ring_members() [1/2]

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

Definition at line 1059 of file wallet2.h.

1059 { return m_print_ring_members; }

◆ print_ring_members() [2/2]

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

Definition at line 1060 of file wallet2.h.

1060 { m_print_ring_members = value; }

◆ public_transactions_required()

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

Definition at line 892 of file wallet2.h.

892 { return nettype() == cryptonote::network_type::MAINNET ? get_blockchain_current_height() >= (1175315 - CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS) : get_blockchain_current_height() >= (1165235 - 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:

◆ 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 4697 of file wallet2.cpp.

4698 {
4700  wallet2::keys_file_data keys_file_data;
4701  std::string buf;
4702  bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
4704 
4705  // Decrypt the contents
4706  r = ::serialization::parse_binary(buf, keys_file_data);
4707  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
4708  crypto::chacha_key key;
4709  crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
4710  std::string account_data;
4711  account_data.resize(keys_file_data.account_data.size());
4712  crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4713  if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject())
4714  crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4715 
4716  device_type = hw::device::device_type::SOFTWARE;
4717  // The contents should be JSON if the wallet follows the new format.
4718  if (json.Parse(account_data.c_str()).HasParseError())
4719  {
4720  // old format before JSON wallet key file format
4721  }
4722  else
4723  {
4724  account_data = std::string(json["key_data"].GetString(), json["key_data"].GetString() +
4725  json["key_data"].GetStringLength());
4726 
4727  if (json.HasMember("key_on_device"))
4728  {
4729  GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, key_on_device, int, Int, false, hw::device::device_type::SOFTWARE);
4730  device_type = static_cast<hw::device::device_type>(field_key_on_device);
4731  }
4732  }
4733 
4734  cryptonote::account_base account_data_check;
4735 
4736  r = epee::serialization::load_t_from_binary(account_data_check, account_data);
4737  if (!r) return false;
4738  return true;
4739 }
bool key_on_device() const
Definition: wallet2.h:824
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2512
#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 1389 of file wallet2.cpp.

1390 {
1391  bool r = true;
1392  hw::device &hwdev = lookup_device(m_device_name);
1393  hwdev.set_name(m_device_name);
1394  hwdev.set_network_type(m_nettype);
1395  hwdev.set_derivation_path(m_device_derivation_path);
1396  hwdev.set_callback(get_device_callback());
1397  r = hwdev.init();
1398  if (!r){
1399  MERROR("Could not init device");
1400  return false;
1401  }
1402 
1403  r = hwdev.connect();
1404  if (!r){
1405  MERROR("Could not connect to the device");
1406  return false;
1407  }
1408 
1409  m_account.set_device(hwdev);
1410  return true;
1411 }
void set_device(hw::device &hwdev)
Definition: account.h:92
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 3043 of file wallet2.cpp.

3044 {
3045  uint64_t blocks_fetched = 0;
3046  refresh(trusted_daemon, 0, blocks_fetched);
3047 }
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 3741 of file wallet2.cpp.

3742 {
3743  try
3744  {
3745  refresh(trusted_daemon, 0, blocks_fetched, received_etn);
3746  ok = true;
3747  }
3748  catch (...)
3749  {
3750  ok = false;
3751  }
3752  return ok;
3753 }

◆ refresh() [3/4]

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

Definition at line 3049 of file wallet2.cpp.

3050 {
3051  bool received_etn = false;
3052  refresh(trusted_daemon, start_height, blocks_fetched, received_etn);
3053 }

◆ 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 3476 of file wallet2.cpp.

3477 {
3478  if (m_offline)
3479  {
3480  blocks_fetched = 0;
3481  received_etn = 0;
3482  return;
3483  }
3484 
3485  if(m_light_wallet) {
3486 
3487  // MyMonero get_address_info needs to be called occasionally to trigger wallet sync.
3488  // This call is not really needed for other purposes and can be removed if mymonero changes their backend.
3490 
3491  // Get basic info
3493  // Last stored block height
3494  uint64_t prev_height = m_light_wallet_blockchain_height;
3495  // Update lw heights
3496  m_light_wallet_scanned_block_height = res.scanned_block_height;
3497  m_light_wallet_blockchain_height = res.blockchain_height;
3498  // If new height - call new_block callback
3499  if(m_light_wallet_blockchain_height != prev_height)
3500  {
3501  MDEBUG("new block since last time!");
3502  m_callback->on_lw_new_block(m_light_wallet_blockchain_height - 1);
3503  }
3504  m_light_wallet_connected = true;
3505  MDEBUG("lw scanned block height: " << m_light_wallet_scanned_block_height);
3506  MDEBUG("lw blockchain height: " << m_light_wallet_blockchain_height);
3507  MDEBUG(m_light_wallet_blockchain_height-m_light_wallet_scanned_block_height << " blocks behind");
3508  // TODO: add wallet created block info
3509 
3511  } else
3512  m_light_wallet_connected = false;
3513 
3514  // Lighwallet refresh done
3515  return;
3516  }
3517  received_etn = false;
3518  blocks_fetched = 0;
3519  uint64_t added_blocks = 0;
3520  size_t try_count = 0;
3521  crypto::hash last_tx_hash_id = m_transfers.size() ? m_transfers.back().m_txid : null_hash;
3522  std::list<crypto::hash> short_chain_history;
3525  uint64_t blocks_start_height;
3526  std::vector<cryptonote::block_complete_entry> blocks;
3527  std::vector<parsed_block> parsed_blocks;
3528  bool refreshed = false;
3529  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
3530  hw::device &hwdev = m_account.get_device();
3531 
3532  // pull the first set of blocks
3533  get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
3534  m_run.store(true, std::memory_order_relaxed);
3535  if (start_height > m_blockchain.size() || m_refresh_from_block_height > m_blockchain.size()) {
3536  if (!start_height)
3537  start_height = m_refresh_from_block_height;
3538  // we can shortcut by only pulling hashes up to the start_height
3539  fast_refresh(start_height, blocks_start_height, short_chain_history);
3540  // regenerate the history now that we've got a full set of hashes
3541  short_chain_history.clear();
3542  get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
3543  start_height = 0;
3544  // and then fall through to regular refresh processing
3545  }
3546 
3547  // If stop() is called during fast refresh we don't need to continue
3548  if(!m_run.load(std::memory_order_relaxed))
3549  return;
3550  // always reset start_height to 0 to force short_chain_ history to be used on
3551  // subsequent pulls in this refresh.
3552  start_height = 0;
3553 
3554  auto keys_reencryptor = epee::misc_utils::create_scope_leave_handler([&, this]() {
3555  if (m_encrypt_keys_after_refresh)
3556  {
3557  encrypt_keys(*m_encrypt_keys_after_refresh);
3558  m_encrypt_keys_after_refresh = boost::none;
3559  }
3560  });
3561 
3562  auto scope_exit_handler_hwdev = epee::misc_utils::create_scope_leave_handler([&](){hwdev.computing_key_images(false);});
3563  bool first = true;
3564  while(m_run.load(std::memory_order_relaxed))
3565  {
3566  uint64_t next_blocks_start_height;
3567  std::vector<cryptonote::block_complete_entry> next_blocks;
3568  std::vector<parsed_block> next_parsed_blocks;
3569  bool error;
3570  try
3571  {
3572  // pull the next set of blocks while we're processing the current one
3573  error = false;
3574  next_blocks.clear();
3575  next_parsed_blocks.clear();
3576  added_blocks = 0;
3577  if (!first && blocks.empty())
3578  {
3579  refreshed = false;
3580  break;
3581  }
3582  tpool.submit(&waiter, [&]{pull_and_parse_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks, parsed_blocks, next_blocks, next_parsed_blocks, error);});
3583 
3584  if (!first)
3585  {
3586  try
3587  {
3588  process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks, output_tracker_cache.get());
3589  }
3591  {
3592  MINFO("Daemon claims next refresh block is out of hash chain bounds, resetting hash chain");
3593  uint64_t stop_height = m_blockchain.offset();
3594  std::vector<crypto::hash> tip(m_blockchain.size() - m_blockchain.offset());
3595  for (size_t i = m_blockchain.offset(); i < m_blockchain.size(); ++i)
3596  tip[i - m_blockchain.offset()] = m_blockchain[i];
3598  generate_genesis(b);
3599  m_blockchain.clear();
3600  m_blockchain.push_back(get_block_hash(b));
3601  short_chain_history.clear();
3602  get_short_chain_history(short_chain_history);
3603  fast_refresh(stop_height, blocks_start_height, short_chain_history, true);
3604  THROW_WALLET_EXCEPTION_IF((m_blockchain.size() == stop_height || (m_blockchain.size() == 1 && stop_height == 0) ? false : true), error::wallet_internal_error, "Unexpected hashchain size");
3605  THROW_WALLET_EXCEPTION_IF(m_blockchain.offset() != 0, error::wallet_internal_error, "Unexpected hashchain offset");
3606  for (const auto &h: tip)
3607  m_blockchain.push_back(h);
3608  short_chain_history.clear();
3609  get_short_chain_history(short_chain_history);
3610  start_height = stop_height;
3611  throw std::runtime_error(""); // loop again
3612  }
3613  catch (const std::exception &e)
3614  {
3615  MERROR("Error parsing blocks: " << e.what());
3616  error = true;
3617  }
3618  blocks_fetched += added_blocks;
3619  }
3620  waiter.wait(&tpool);
3621  if(!first && blocks_start_height == next_blocks_start_height)
3622  {
3623  m_node_rpc_proxy.set_height(m_blockchain.size());
3624  refreshed = true;
3625  break;
3626  }
3627 
3628  first = false;
3629 
3630  // handle error from async fetching thread
3631  if (error)
3632  {
3633  throw std::runtime_error("proxy exception in refresh thread");
3634  }
3635 
3636  // if we've got at least 10 blocks to refresh, assume we're starting
3637  // a long refresh, and setup a tracking output cache if we need to
3638  // We hit create_output_tracker_cache before doing processing our blocks in process_parsed_blocks above( see 'first' variable)
3639  if (m_track_uses && (!output_tracker_cache || (output_tracker_cache->first.empty() && output_tracker_cache->second.empty())) && next_blocks.size() >= 10)
3640  output_tracker_cache = create_output_tracker_cache();
3641 
3642  // switch to the new blocks from the daemon
3643  blocks_start_height = next_blocks_start_height;
3644  blocks = std::move(next_blocks);
3645  parsed_blocks = std::move(next_parsed_blocks);
3646  }
3647  catch (const tools::error::password_needed&)
3648  {
3649  blocks_fetched += added_blocks;
3650  waiter.wait(&tpool);
3651  throw;
3652  }
3653  catch (const std::exception&)
3654  {
3655  blocks_fetched += added_blocks;
3656  waiter.wait(&tpool);
3657  if(try_count < 3)
3658  {
3659  LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
3660  first = true;
3661  start_height = 0;
3662  blocks.clear();
3663  parsed_blocks.clear();
3664  short_chain_history.clear();
3665  get_short_chain_history(short_chain_history, 1);
3666  ++try_count;
3667  }
3668  else
3669  {
3670  LOG_ERROR("pull_blocks failed, try_count=" << try_count);
3671  throw;
3672  }
3673  }
3674  }
3675  if(last_tx_hash_id != (m_transfers.size() ? m_transfers.back().m_txid : null_hash))
3676  received_etn = true;
3677 
3678  try
3679  {
3680  // If stop() is called we don't need to check pending transactions
3681  if (check_pool && m_run.load(std::memory_order_relaxed))
3682  update_pool_state(refreshed);
3683  }
3684  catch (...)
3685  {
3686  LOG_PRINT_L1("Failed to check pending transactions");
3687  }
3688 
3689  m_first_refresh_done = true;
3690 
3691  LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", pre v10 balance (all accounts): " << print_etn(balance_all(false)) << ", unlocked: " << print_etn(unlocked_balance_all(false)) << ", post v10 balance (all accounts): " << print_etn(balance_all(true)) << ", unlocked: " << print_etn(unlocked_balance_all(true)));
3692 
3693  try {
3694  // V9-->V10 PUBLIC MIGRATIONS
3695  // 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)
3696  //todo: write function for wallet that gets the b.major version for a given *local* blockchain height, to save hardcoding heights.
3697  uint64_t migration_minheight = this->nettype() == TESTNET ? 1165235 + 5 : 1175315 + 5;
3698  if (this->get_blockchain_current_height() > migration_minheight && this->unlocked_balance_all(false) != 0) {
3699  LOG_PRINT_L0("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.");
3700  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))
3701  // for each account, grab all of the subaddress info (index, (balance, unlock))
3702  for (uint32_t account_index = 0; account_index < this->get_num_subaddress_accounts(); ++account_index) {
3703  unlocked_balance_per_subaddress_per_account[account_index] = this->unlocked_balance_per_subaddress(
3704  account_index, false);
3705  }
3706  for (uint32_t i = 0; i < this->get_num_subaddress_accounts(); i++) {
3708  index.major = i;
3709  for (auto subaddress: unlocked_balance_per_subaddress_per_account[i]) {
3710  index.minor = subaddress.first;
3711 
3712  if (subaddress.second.first != 0 &&
3713  subaddress.second.second == 0/*is there a fully unlocked nonzero balance /sanity check*/) {
3715  std::set <uint32_t> subaddress_source{index.minor};
3716  std::vector <wallet2::pending_tx> ptx_vector = this->create_transactions_all(0,
3717  address /*dest address*/,
3718  index.major != 0 ||
3719  index.minor !=
3720  0 /*is dest a subaddress*/,
3721  1 /*one output only*/,
3722  0 /* don't mix*/,
3723  0 /*default unlock time*/,
3724  4 /*highest priority*/,
3725  vector<uint8_t>() /*empty tx extra */,
3726  index.major /*account index*/,
3727  subaddress_source /*source subaddr index*/,
3728  true /*migrate*/);
3729  this->commit_tx(ptx_vector);
3730  }
3731  }
3732  }
3733  LOG_PRINT_L0("Migration completed.");
3734  }
3735  }
3736  catch(...){
3737  THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Overall migration failed but some balances may have migrated ok. Please restart the wallet and try again and contact Electroneum if the issue persists.");
3738  }
3739 }
virtual void computing_key_images(bool started)
Definition: device.hpp:247
void set_height(uint64_t h)
virtual void on_lw_new_block(uint64_t height)
Definition: wallet2.h:134
void wait(threadpool *tpool)
Definition: threadpool.cpp:115
A global thread pool.
Definition: threadpool.h:43
static threadpool & getInstance()
Definition: threadpool.h:45
void submit(waiter *waiter, std::function< void()> f, bool leaf=false)
Definition: threadpool.cpp:69
void light_wallet_get_address_txs()
Definition: wallet2.cpp:9244
void update_pool_state(bool refreshed=false)
Definition: wallet2.cpp:3147
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)
Definition: wallet2.cpp:10149
bool light_wallet_get_address_info(tools::COMMAND_RPC_GET_ADDRESS_INFO::response &response)
Definition: wallet2.cpp:9228
uint64_t unlocked_balance_all(bool public_blockchain, uint64_t *blocks_to_unlock=NULL) const
Definition: wallet2.cpp:6190
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
#define FIRST_REFRESH_GRANULARITY
Definition: wallet2.cpp:131

◆ remove_obsolete_pool_txs()

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

Definition at line 3119 of file wallet2.cpp.

3120 {
3121  // remove pool txes to us that aren't in the pool anymore
3122  std::unordered_multimap<crypto::hash, wallet2::pool_payment_details>::iterator uit = m_unconfirmed_payments.begin();
3123  while (uit != m_unconfirmed_payments.end())
3124  {
3125  const crypto::hash &txid = uit->second.m_pd.m_tx_hash;
3126  bool found = false;
3127  for (const auto &it2: tx_hashes)
3128  {
3129  if (it2 == txid)
3130  {
3131  found = true;
3132  break;
3133  }
3134  }
3135  auto pit = uit++;
3136  if (!found)
3137  {
3138  MDEBUG("Removing " << txid << " from unconfirmed payments, not found in pool");
3139  m_unconfirmed_payments.erase(pit);
3140  if (0 != m_callback)
3141  m_callback->on_pool_tx_removed(txid);
3142  }
3143  }
3144 }
virtual void on_pool_tx_removed(const crypto::hash &txid)
Definition: wallet2.h:145

◆ rescan_blockchain()

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

Definition at line 6339 of file wallet2.cpp.

6340 {
6341  CHECK_AND_ASSERT_THROW_MES(!hard || !keep_key_images, "Cannot preserve key images on hard rescan");
6342  const size_t transfers_cnt = m_transfers.size();
6343  crypto::hash transfers_hash{};
6344 
6345  if(hard)
6346  {
6347  clear();
6348  setup_new_blockchain();
6349  }
6350  else
6351  {
6352  if (keep_key_images && refresh)
6353  hash_m_transfers((int64_t) transfers_cnt, transfers_hash);
6354  clear_soft(keep_key_images);
6355  }
6356 
6357  if (refresh)
6358  this->refresh(false);
6359 
6360  if (refresh && keep_key_images)
6361  finish_rescan_bc_keep_key_images(transfers_cnt, transfers_hash);
6362 }
void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash)
Definition: wallet2.cpp:13514

◆ rescan_spent()

void tools::wallet2::rescan_spent ( )

Definition at line 6287 of file wallet2.cpp.

6288 {
6289  // This is RPC call that can take a long time if there are many outputs,
6290  // so we call it several times, in stripes, so we don't time out spuriously
6291  std::vector<int> spent_status;
6292  spent_status.reserve(m_transfers.size());
6293  const size_t chunk_size = 1000;
6294  for (size_t start_offset = 0; start_offset < m_transfers.size(); start_offset += chunk_size)
6295  {
6296  const size_t n_outputs = std::min<size_t>(chunk_size, m_transfers.size() - start_offset);
6297  MDEBUG("Calling is_key_image_spent on " << start_offset << " - " << (start_offset + n_outputs - 1) << ", out of " << m_transfers.size());
6299  COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
6300  for (size_t n = start_offset; n < start_offset + n_outputs; ++n)
6301  req.key_images.push_back(string_tools::pod_to_hex(m_transfers[n].m_key_image));
6302  m_daemon_rpc_mutex.lock();
6303  bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout);
6304  m_daemon_rpc_mutex.unlock();
6305  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
6306  THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
6307  THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, get_rpc_status(daemon_resp.status));
6308  THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != n_outputs, error::wallet_internal_error,
6309  "daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
6310  std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(n_outputs));
6311  std::copy(daemon_resp.spent_status.begin(), daemon_resp.spent_status.end(), std::back_inserter(spent_status));
6312  }
6313 
6314  // update spent status
6315  for (size_t i = 0; i < m_transfers.size(); ++i)
6316  {
6317  transfer_details& td = m_transfers[i];
6318  // a view wallet may not know about key images
6319  if (!td.m_key_image_known || td.m_key_image_partial)
6320  continue;
6321  if (td.m_spent != (spent_status[i] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT))
6322  {
6323  if (td.m_spent)
6324  {
6325  LOG_PRINT_L0("Marking output " << i << "(" << td.m_key_image << ") as unspent, it was marked as spent");
6326  set_unspent(i);
6327  td.m_spent_height = 0;
6328  }
6329  else
6330  {
6331  LOG_PRINT_L0("Marking output " << i << "(" << td.m_key_image << ") as spent, it was marked as unspent");
6332  set_spent(i, td.m_spent_height);
6333  // unknown height, if this gets reorged, it might still be missed
6334  }
6335  }
6336  }
6337 }
void copy(key &AA, const key &A)
Definition: rctOps.h:79
Here is the call 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 5000 of file wallet2.cpp.

5001 {
5002  clear();
5003  prepare_file_names(wallet_);
5004 
5005  boost::system::error_code ignored_ec;
5006  if (!wallet_.empty()) {
5007  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
5008  THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
5009  }
5010 
5011  auto &hwdev = lookup_device(device_name);
5012  hwdev.set_name(device_name);
5013  hwdev.set_network_type(m_nettype);
5014  hwdev.set_derivation_path(m_device_derivation_path);
5015  hwdev.set_callback(get_device_callback());
5016 
5017  m_account.create_from_device(hwdev);
5018  init_type(m_account.get_device().get_type());
5019  setup_keys(password);
5020  m_device_name = device_name;
5021 
5022  create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
5023  if (m_subaddress_lookahead_major == SUBADDRESS_LOOKAHEAD_MAJOR && m_subaddress_lookahead_minor == SUBADDRESS_LOOKAHEAD_MINOR)
5024  {
5025  // the default lookahead setting (50:200) is clearly too much for hardware wallet
5026  m_subaddress_lookahead_major = 5;
5027  m_subaddress_lookahead_minor = 20;
5028  }
5029  setup_new_blockchain();
5030  if (!wallet_.empty()) {
5031  store();
5032  }
5033 }
void create_from_device(const std::string &device_name)
Definition: account.cpp:209
Here is the call 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 5560 of file wallet2.cpp.

5561 {
5562  if (wallet_name.empty())
5563  return;
5564  prepare_file_names(wallet_name);
5565  boost::system::error_code ignored_ec;
5566  THROW_WALLET_EXCEPTION_IF(!boost::filesystem::exists(m_keys_file, ignored_ec), error::file_not_found, m_keys_file);
5567  bool r = store_keys(m_keys_file, password, m_watch_only);
5569 }

◆ 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 10070 of file wallet2.cpp.

10071  {
10072  MDEBUG("sanity_check: " << ptx_vector.size() << " txes, " << dsts.size() << " destinations");
10073 
10074  hw::device &hwdev = m_account.get_device();
10075 
10076  THROW_WALLET_EXCEPTION_IF(ptx_vector.empty(), error::wallet_internal_error, "No transactions");
10077 
10078  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
10079  // check every party in there does receive at least the required amount
10080  std::unordered_map<account_public_address, std::pair<uint64_t, bool>> required;
10081  for (const auto &d: dsts) {
10082  required[d.addr].first += d.amount;
10083  required[d.addr].second = d.is_subaddress;
10084  }
10085 
10086  // add change
10087  uint64_t change = 0;
10088  for (const auto &ptx: ptx_vector) {
10089  for (size_t idx: ptx.selected_transfers) //1:add the amount you're spending
10090  change += m_transfers[idx].amount();
10091  change -= ptx.fee; //2: take off the fee
10092  }
10093  for (const auto &r: required)
10094  change -= r.second.first; // 3: subtract the destination required amount
10095  MDEBUG("Adding " << cryptonote::print_etn(change) << " expected change");
10096 
10097  // for all txes that have actual change, check change is coming back to the sending wallet
10098  for (const pending_tx &ptx: ptx_vector) {
10099  if (ptx.change_dts.amount == 0)
10100  continue;
10102  m_subaddresses.find(ptx.change_dts.addr.m_spend_public_key) == m_subaddresses.end(),
10103  error::wallet_internal_error, "Change address is not ours");
10104  required[ptx.change_dts.addr].first += ptx.change_dts.amount;
10105  required[ptx.change_dts.addr].second = ptx.change_dts.is_subaddress;
10106  }
10107 
10108 
10109  for (const auto &r: required) {
10110  const account_public_address &address = r.first;
10111  const crypto::public_key &view_pkey = address.m_view_public_key;
10112 
10113  uint64_t total_received = 0;
10114 
10115  for (const auto &ptx: ptx_vector) {
10116  uint64_t received = 0;
10117  try {
10118  std::string proof = get_tx_proof(ptx.tx, ptx.tx_key, ptx.additional_tx_keys, address,
10119  r.second.second,
10120  "automatic-sanity-check");
10121  check_tx_proof(ptx.tx, address, r.second.second, "automatic-sanity-check", proof, received);
10122  }
10123  catch (const std::exception &e) { received = 0; }
10124  total_received += received;
10125  }
10126 
10127  std::stringstream ss;
10128  ss << "Total received by "
10129  << cryptonote::get_account_address_as_str(m_nettype, r.second.second, address)
10130  << ": "
10131  << cryptonote::print_etn(total_received) << ", expected " << cryptonote::print_etn(r.second.first);
10132  MDEBUG(ss.str());
10133  THROW_WALLET_EXCEPTION_IF(total_received < r.second.first, error::wallet_internal_error, ss.str());
10134  }
10135  } // end of v1 sanity check
10136  else {
10137  // for all txes that have actual change, check change is coming back to the sending wallet
10138  for (const pending_tx &ptx: ptx_vector) {
10139  if (ptx.change_dts.amount == 0)
10140  continue;
10142  m_subaddresses.find(ptx.change_dts.addr.m_spend_public_key) == m_subaddresses.end(),
10143  error::wallet_internal_error, "Change address is not ours");
10144  }
10145  }
10146  return true;
10147 }
Here is the call 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 7268 of file wallet2.cpp.

7269 {
7270  std::string ciphertext = save_multisig_tx(txs);
7271  if (ciphertext.empty())
7272  return false;
7273  return epee::file_io_utils::save_string_to_file(filename, ciphertext);
7274 }
std::string save_multisig_tx(multisig_tx_set txs)
Definition: wallet2.cpp:7230
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 7291 of file wallet2.cpp.

7292 {
7293  return save_multisig_tx(make_multisig_tx_set(ptx_vector));
7294 }
multisig_tx_set make_multisig_tx_set(const std::vector< pending_tx > &ptx_vector) const
Definition: wallet2.cpp:7276

◆ 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 7296 of file wallet2.cpp.

7297 {
7298  std::string ciphertext = save_multisig_tx(ptx_vector);
7299  if (ciphertext.empty())
7300  return false;
7301  return epee::file_io_utils::save_string_to_file(filename, ciphertext);
7302 }
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 7230 of file wallet2.cpp.

7231 {
7232  LOG_PRINT_L0("saving " << txs.m_ptx.size() << " multisig transactions");
7233 
7234  // txes generated, get rid of used k values
7235  for (size_t n = 0; n < txs.m_ptx.size(); ++n)
7236  for (size_t idx: txs.m_ptx[n].construction_data.selected_transfers)
7237  m_transfers[idx].m_multisig_k.clear();
7238 
7239  // zero out some data we don't want to share
7240  for (auto &ptx: txs.m_ptx)
7241  {
7242  for (auto &e: ptx.construction_data.sources)
7243  e.multisig_kLRki.k = rct::zero();
7244  }
7245 
7246  for (auto &ptx: txs.m_ptx)
7247  {
7248  // Get decrypted payment id from pending_tx
7249  ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx, m_account.get_device());
7250  }
7251 
7252  // save as binary
7253  std::ostringstream oss;
7255  try
7256  {
7257  ar << txs;
7258  }
7259  catch (...)
7260  {
7261  return std::string();
7262  }
7263  LOG_PRINT_L2("Saving multisig unsigned tx data: " << oss.str());
7264  std::string ciphertext = encrypt_with_view_secret_key(oss.str());
7265  return std::string(MULTISIG_UNSIGNED_TX_PREFIX) + ciphertext;
7266 }
Here is the call 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 6774 of file wallet2.cpp.

6775 {
6776  LOG_PRINT_L0("saving " << ptx_vector.size() << " transactions");
6777  std::string ciphertext = dump_tx_to_str(ptx_vector);
6778  if (ciphertext.empty())
6779  return false;
6780  return epee::file_io_utils::save_string_to_file(filename, ciphertext);
6781 }
std::string dump_tx_to_str(const std::vector< pending_tx > &ptx_vector) const
Definition: wallet2.cpp:6783
Here is the call graph for this function:

◆ segregate_pre_fork_outputs() [1/2]

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

Definition at line 1087 of file wallet2.h.

1087 { 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 1088 of file wallet2.h.

1088 { m_segregate_pre_fork_outputs = value; }

◆ segregation_height() [1/2]

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

Definition at line 1091 of file wallet2.h.

1091 { return m_segregation_height; }

◆ segregation_height() [2/2]

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

Definition at line 1092 of file wallet2.h.

1092 { m_segregation_height = height; }

◆ select_available_mixable_outputs()

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

Definition at line 10654 of file wallet2.cpp.

10655 {
10656  // request all outputs with at least as many instances as the min ring size
10657  return select_available_outputs_from_histogram(get_min_ring_size(), true, true, true);
10658 }
std::vector< size_t > select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct)
Definition: wallet2.cpp:10582

◆ 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 10545 of file wallet2.cpp.

10546 {
10547  std::vector<size_t> outputs;
10548  size_t n = 0;
10549  for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i, ++n)
10550  {
10551  if (i->m_spent)
10552  continue;
10553  if (i->m_frozen)
10554  continue;
10555  if (i->m_key_image_partial)
10556  continue;
10557  if (!is_transfer_unlocked(*i))
10558  continue;
10559  if (f(*i))
10560  outputs.push_back(n);
10561  }
10562  return outputs;
10563 }

◆ 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 10582 of file wallet2.cpp.

10583 {
10586  m_daemon_rpc_mutex.lock();
10587  if (is_trusted_daemon())
10588  req_t.amounts = get_unspent_amounts_vector();
10589  req_t.min_count = count;
10590  req_t.max_count = 0;
10591  req_t.unlocked = unlocked;
10592  req_t.recent_cutoff = 0;
10593  bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
10594  m_daemon_rpc_mutex.unlock();
10595  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_outputs_from_histogram");
10596  THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
10597  THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status);
10598 
10599  std::set<uint64_t> mixable;
10600  for (const auto &i: resp_t.histogram)
10601  {
10602  mixable.insert(i.amount);
10603  }
10604 
10605  return select_available_outputs([mixable, atleast, allow_rct](const transfer_details &td) {
10606  if (!allow_rct && td.is_rct())
10607  return false;
10608  const uint64_t amount = td.is_rct() ? 0 : td.amount();
10609  if (atleast) {
10610  if (mixable.find(amount) != mixable.end())
10611  return true;
10612  }
10613  else {
10614  if (mixable.find(amount) == mixable.end())
10615  return true;
10616  }
10617  return false;
10618  });
10619 }
std::vector< size_t > select_available_outputs(const std::function< bool(const transfer_details &td)> &f) const
Definition: wallet2.cpp:10545
Here is the call graph for this function:

◆ select_available_unmixable_outputs()

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

Definition at line 10648 of file wallet2.cpp.

10649 {
10650  // request all outputs with less instances than the min ring size
10651  return select_available_outputs_from_histogram(get_min_ring_size(), false, true, false);
10652 }

◆ serialize()

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

Definition at line 902 of file wallet2.h.

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

◆ 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 11846 of file wallet2.cpp.

11847 {
11848  for (uint32_t account_index : account_indices)
11849  {
11850  THROW_WALLET_EXCEPTION_IF(account_index >= get_num_subaddress_accounts(), error::wallet_internal_error, "Account index out of bound");
11851  if (m_account_tags.second[account_index] == tag)
11852  MDEBUG("This tag is already assigned to this account");
11853  else
11854  m_account_tags.second[account_index] = tag;
11855  }
11856  get_account_tags();
11857 }

◆ 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 11859 of file wallet2.cpp.

11860 {
11861  THROW_WALLET_EXCEPTION_IF(tag.empty(), error::wallet_internal_error, "Tag must not be empty");
11862  THROW_WALLET_EXCEPTION_IF(m_account_tags.first.count(tag) == 0, error::wallet_internal_error, "Tag is unregistered");
11863  m_account_tags.first[tag] = description;
11864 }

◆ set_attribute()

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

Definition at line 11803 of file wallet2.cpp.

11804 {
11805  m_attributes[key] = value;
11806 }

◆ 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 7973 of file wallet2.cpp.

7974 {
7975  if (!m_ringdb)
7976  return false;
7977  try
7978  {
7979  bool ret = true;
7980  if (!add)
7981  ret &= m_ringdb->clear_blackballs();
7982  ret &= m_ringdb->blackball(outputs);
7983  return ret;
7984  }
7985  catch (const std::exception &e) { return false; }
7986 }

◆ set_confirm_backlog_threshold()

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

Definition at line 1081 of file wallet2.h.

1081 { 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 1267 of file wallet2.cpp.

1268 {
1269  boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
1270 
1271  if(m_http_client.is_connected())
1272  m_http_client.disconnect();
1273  m_daemon_address = std::move(daemon_address);
1274  m_daemon_login = std::move(daemon_login);
1275  m_trusted_daemon = trusted_daemon;
1276 
1277  MINFO("setting daemon to " << get_daemon_address());
1278  return m_http_client.set_server(get_daemon_address(), get_daemon_login(), std::move(ssl_options));
1279 }
bool set_server(const std::string &address, boost::optional< login > user, ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect)
Definition: http_client.h:302
const boost::optional< epee::net_utils::http::login > & get_daemon_login() const
Definition: wallet2.h:1157
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 1066 of file wallet2.h.

1066 { m_default_priority = p; }

◆ set_description()

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

Definition at line 11816 of file wallet2.cpp.

11817 {
11818  set_attribute(ATTRIBUTE_DESCRIPTION, description);
11819 }
void set_attribute(const std::string &key, const std::string &value)
Definition: wallet2.cpp:11803

◆ set_light_wallet()

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

Definition at line 772 of file wallet2.h.

772 { 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:771
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 1073 of file wallet2.h.

1073 { m_min_output_count = count; }
Here is the call graph for this function:

◆ set_min_output_value()

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

Definition at line 1075 of file wallet2.h.

1075 { m_min_output_value = value; }

◆ set_offline()

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

Definition at line 5700 of file wallet2.cpp.

5701 {
5702  m_offline = offline;
5703  m_http_client.set_auto_connect(!offline);
5704  if (offline)
5705  {
5706  boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
5707  if(m_http_client.is_connected())
5708  m_http_client.disconnect();
5709  }
5710 }

◆ set_refresh_from_block_height()

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

Definition at line 736 of file wallet2.h.

736 {m_refresh_from_block_height = height;}

◆ set_refresh_type()

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

Definition at line 815 of file wallet2.h.

815 { 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 7853 of file wallet2.cpp.

7854 {
7855  if (!m_ringdb)
7856  return false;
7857 
7858  try { return m_ringdb->set_ring(get_ringdb_key(), key_image, outs, relative); }
7859  catch (const std::exception &e) { return false; }
7860 }

◆ set_ring_database()

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

Definition at line 7746 of file wallet2.cpp.

7747 {
7748  m_ring_database = filename;
7749  MINFO("ringdb path set to " << filename);
7750  m_ringdb.reset();
7751  if (!m_ring_database.empty())
7752  {
7753  try
7754  {
7756  generate_genesis(b);
7757  m_ringdb.reset(new tools::ringdb(m_ring_database, epee::string_tools::pod_to_hex(get_block_hash(b))));
7758  }
7759  catch (const std::exception &e)
7760  {
7761  MERROR("Failed to initialize ringdb: " << e.what());
7762  m_ring_database = "";
7763  return false;
7764  }
7765  }
7766  return true;
7767 }
Here is the call 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 1424 of file wallet2.cpp.

1425 {
1426  seed_language = language;
1427 }

◆ set_subaddress_label()

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

Definition at line 1527 of file wallet2.cpp.

1528 {
1529  THROW_WALLET_EXCEPTION_IF(index.major >= m_subaddress_labels.size(), error::account_index_outofbound);
1530  THROW_WALLET_EXCEPTION_IF(index.minor >= m_subaddress_labels[index.major].size(), error::address_index_outofbound);
1531  m_subaddress_labels[index.major][index.minor] = label;
1532 }
Here is the caller graph for this function:

◆ set_subaddress_lookahead()

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

Definition at line 1534 of file wallet2.cpp.

1535 {
1536  THROW_WALLET_EXCEPTION_IF(major > 0xffffffff, error::wallet_internal_error, "Subaddress major lookahead is too large");
1537  THROW_WALLET_EXCEPTION_IF(minor > 0xffffffff, error::wallet_internal_error, "Subaddress minor lookahead is too large");
1538  m_subaddress_lookahead_major = major;
1539  m_subaddress_lookahead_minor = minor;
1540 }
Here is the caller graph for this function:

◆ set_trusted_daemon()

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

Definition at line 760 of file wallet2.h.

760 { 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 11790 of file wallet2.cpp.

11791 {
11792  m_tx_device[txid] = aux;
11793 }

◆ 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 10790 of file wallet2.cpp.

10791 {
10792  // fetch tx from daemon and check if secret keys agree with corresponding public keys
10794  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
10795  req.decode_as_json = false;
10796  req.prune = true;
10798  bool r;
10799  {
10800  const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
10801  r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
10802  }
10803  THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
10804  THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
10805  THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions");
10806  THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
10807  "daemon returned wrong response for gettransactions, wrong txs count = " +
10808  std::to_string(res.txs.size()) + ", expected 1");
10810  crypto::hash tx_hash;
10811  THROW_WALLET_EXCEPTION_IF(!get_pruned_tx(res.txs[0], tx, tx_hash), error::wallet_internal_error,
10812  "Failed to get transaction from daemon");
10813  THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "txid mismatch");
10814  std::vector<tx_extra_field> tx_extra_fields;
10815  THROW_WALLET_EXCEPTION_IF(!parse_tx_extra(tx.extra, tx_extra_fields), error::wallet_internal_error, "Transaction extra has unsupported format");
10816  tx_extra_pub_key pub_key_field;
10817  bool found = false;
10818  size_t index = 0;
10819  while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, index++))
10820  {
10821  crypto::public_key calculated_pub_key;
10822  crypto::secret_key_to_public_key(tx_key, calculated_pub_key);
10823  if (calculated_pub_key == pub_key_field.pub_key)
10824  {
10825  found = true;
10826  break;
10827  }
10828  }
10829  THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error, "Given tx secret key doesn't agree with the tx public key in the blockchain");
10830  tx_extra_additional_pub_keys additional_tx_pub_keys;
10831  find_tx_extra_field_by_type(tx_extra_fields, additional_tx_pub_keys);
10832  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" );
10833  m_tx_keys.insert(std::make_pair(txid, tx_key));
10834  m_additional_tx_keys.insert(std::make_pair(txid, additional_tx_keys));
10835 }
std::vector< crypto::public_key > data
Definition: tx_extra.h:167
Here is the call graph for this function:

◆ set_tx_note()

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

Definition at line 11777 of file wallet2.cpp.

11778 {
11779  m_tx_notes[txid] = note;
11780 }

◆ set_tx_notify()

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

Definition at line 1369 of file wallet2.h.

1369 { m_tx_notify = notify; }

◆ setup_background_mining() [1/2]

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

Definition at line 1099 of file wallet2.h.

1099 { return m_setup_background_mining; }

◆ setup_background_mining() [2/2]

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

Definition at line 1100 of file wallet2.h.

1100 { m_setup_background_mining = value; }

◆ sign()

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

Definition at line 11866 of file wallet2.cpp.

11867 {
11869  crypto::cn_fast_hash(data.data(), data.size(), hash);
11870  const cryptonote::account_keys &keys = m_account.get_keys();
11873  return std::string("SigV1") + tools::base58::encode(std::string((const char *)&signature, sizeof(signature)));
11874 }
Here is the call 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 11899 of file wallet2.cpp.

11900 {
11901  CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
11902 
11904  crypto::cn_fast_hash(data.data(), data.size(), hash);
11905  const cryptonote::account_keys &keys = m_account.get_keys();
11908  return MULTISIG_SIGNATURE_MAGIC + tools::base58::encode(std::string((const char *)&signature, sizeof(signature)));
11909 }
Here is the call 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 7406 of file wallet2.cpp.

7407 {
7408  THROW_WALLET_EXCEPTION_IF(exported_txs.m_ptx.empty(), error::wallet_internal_error, "No tx found");
7409 
7410  const crypto::public_key local_signer = get_multisig_signer_public_key();
7411 
7412  THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.find(local_signer) != exported_txs.m_signers.end(),
7413  error::wallet_internal_error, "Transaction already signed by this private key");
7414  THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.size() > m_multisig_threshold,
7415  error::wallet_internal_error, "Transaction was signed by too many signers");
7416  THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.size() == m_multisig_threshold,
7417  error::wallet_internal_error, "Transaction is already fully signed");
7418 
7419  txids.clear();
7420 
7421  // sign the transactions
7422  for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
7423  {
7424  tools::wallet2::pending_tx &ptx = exported_txs.m_ptx[n];
7425  THROW_WALLET_EXCEPTION_IF(ptx.multisig_sigs.empty(), error::wallet_internal_error, "No signatures found in multisig tx");
7427  LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, mixin " << (sd.sources[0].outputs.size()-1) <<
7428  ", signed by " << exported_txs.m_signers.size() << "/" << m_multisig_threshold);
7430  rct::multisig_out msout = ptx.multisig_sigs.front().msout;
7431  auto sources = sd.sources;
7432  rct::RCTConfig rct_config = sd.rct_config;
7433  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);
7434  THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
7435 
7437  error::wallet_internal_error, "Transaction prefix does not match data");
7438 
7439  // Tests passed, sign
7440  std::vector<unsigned int> indices;
7441  for (const auto &source: sources)
7442  indices.push_back(source.real_output);
7443 
7444  for (auto &sig: ptx.multisig_sigs)
7445  {
7446  if (sig.ignore.find(local_signer) == sig.ignore.end())
7447  {
7448  ptx.tx.rct_signatures = sig.sigs;
7449 
7450  rct::keyV k;
7451  for (size_t idx: sd.selected_transfers)
7452  k.push_back(get_multisig_k(idx, sig.used_L));
7453 
7454  rct::key skey = rct::zero();
7455  for (const auto &msk: get_account().get_multisig_keys())
7456  {
7458 
7459  if (sig.signing_keys.find(pmsk) == sig.signing_keys.end())
7460  {
7461  sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes);
7462  sig.signing_keys.insert(pmsk);
7463  }
7464  }
7465  THROW_WALLET_EXCEPTION_IF(!rct::signMultisig(ptx.tx.rct_signatures, indices, k, sig.msout, skey),
7466  error::wallet_internal_error, "Failed signing, transaction likely malformed");
7467 
7468  sig.sigs = ptx.tx.rct_signatures;
7469  }
7470  }
7471 
7472  const bool is_last = exported_txs.m_signers.size() + 1 >= m_multisig_threshold;
7473  if (is_last)
7474  {
7475  // when the last signature on a multisig tx is made, we select the right
7476  // signature to plug into the final tx
7477  bool found = false;
7478  for (const auto &sig: ptx.multisig_sigs)
7479  {
7480  if (sig.ignore.find(local_signer) == sig.ignore.end() && !keys_intersect(sig.ignore, exported_txs.m_signers))
7481  {
7482  THROW_WALLET_EXCEPTION_IF(found, error::wallet_internal_error, "More than one transaction is final");
7483  ptx.tx.rct_signatures = sig.sigs;
7484  found = true;
7485  }
7486  }
7487  THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error,
7488  "Final signed transaction not found: this transaction was likely made without our export data, so we cannot sign it");
7489  const crypto::hash txid = get_transaction_hash(ptx.tx);
7490  if (store_tx_info())
7491  {
7492  m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
7493  m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
7494  }
7495  txids.push_back(txid);
7496  }
7497  }
7498 
7499  // txes generated, get rid of used k values
7500  for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
7501  for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers)
7502  m_transfers[idx].m_multisig_k.clear();
7503 
7504  exported_txs.m_signers.insert(get_multisig_signer_public_key());
7505 
7506  return true;
7507 }
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:471
crypto::secret_key tx_key
Definition: wallet2.h:466
std::vector< multisig_sig > multisig_sigs
Definition: wallet2.h:469
cryptonote::transaction tx
Definition: wallet2.h:460
std::vector< crypto::secret_key > additional_tx_keys
Definition: wallet2.h:467
cryptonote::tx_destination_entry change_dts
Definition: wallet2.h:463
std::vector< uint8_t > extra
Definition: wallet2.h:420
std::vector< cryptonote::tx_source_entry > sources
Definition: wallet2.h:416
std::vector< cryptonote::tx_destination_entry > splitted_dsts
Definition: wallet2.h:418
std::vector< size_t > selected_transfers
Definition: wallet2.h:419
Here is the call 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 7517 of file wallet2.cpp.

7518 {
7519  multisig_tx_set exported_txs;
7520  if(!load_multisig_tx_from_file(filename, exported_txs))
7521  return false;
7522 
7523  if (accept_func && !accept_func(exported_txs))
7524  {
7525  LOG_PRINT_L1("Transactions rejected by callback");
7526  return false;
7527  }
7528  return sign_multisig_tx_to_file(exported_txs, filename, txids);
7529 }
bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector< crypto::hash > &txids)
Definition: wallet2.cpp:7509
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:7382

◆ 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 7509 of file wallet2.cpp.

7510 {
7511  bool r = sign_multisig_tx(exported_txs, txids);
7512  if (!r)
7513  return false;
7514  return save_multisig_tx(exported_txs, filename);
7515 }
bool sign_multisig_tx(multisig_tx_set &exported_txs, std::vector< crypto::hash > &txids)
Definition: wallet2.cpp:7406

◆ 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 
)

Definition at line 6901 of file wallet2.cpp.

6902 {
6903  unsigned_tx_set exported_txs;
6904  if(!load_unsigned_tx(unsigned_filename, exported_txs))
6905  return false;
6906 
6907  if (accept_func && !accept_func(exported_txs))
6908  {
6909  LOG_PRINT_L1("Transactions rejected by callback");
6910  return false;
6911  }
6912  return sign_tx(exported_txs, signed_filename, txs, export_raw);
6913 }
bool load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs) const
Definition: wallet2.cpp:6813
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)
Definition: wallet2.cpp:6901
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 
)

Definition at line 7061 of file wallet2.cpp.

7062 {
7063  // sign the transactions
7064  signed_tx_set signed_txes;
7065  std::string ciphertext = sign_tx_dump_to_str(exported_txs, txs, signed_txes);
7066  if (ciphertext.empty())
7067  {
7068  LOG_PRINT_L0("Failed to sign unsigned_tx_set");
7069  return false;
7070  }
7071 
7072  if (!epee::file_io_utils::save_string_to_file(signed_filename, ciphertext))
7073  {
7074  LOG_PRINT_L0("Failed to save file to " << signed_filename);
7075  return false;
7076  }
7077  // export signed raw tx without encryption
7078  if (export_raw)
7079  {
7080  for (size_t i = 0; i < signed_txes.ptx.size(); ++i)
7081  {
7082  std::string tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(signed_txes.ptx[i].tx));
7083  std::string raw_filename = signed_filename + "_raw" + (signed_txes.ptx.size() == 1 ? "" : ("_" + std::to_string(i)));
7084  if (!epee::file_io_utils::save_string_to_file(raw_filename, tx_as_hex))
7085  {
7086  LOG_PRINT_L0("Failed to save file to " << raw_filename);
7087  return false;
7088  }
7089  }
7090  }
7091  return true;
7092 }
std::string sign_tx_dump_to_str(unsigned_tx_set &exported_txs, std::vector< wallet2::pending_tx > &ptx, signed_tx_set &signed_txes)
Definition: wallet2.cpp:7094
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 6915 of file wallet2.cpp.

6916 {
6917  import_outputs(exported_txs.transfers);
6918 
6919  // sign the transactions
6920  for (size_t n = 0; n < exported_txs.txes.size(); ++n)
6921  {
6922  tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
6923  THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources");
6924  LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
6925  signed_txes.ptx.push_back(pending_tx());
6926  tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
6927  rct::RCTConfig rct_config = sd.rct_config;
6928  crypto::secret_key tx_key;
6929  std::vector<crypto::secret_key> additional_tx_keys;
6930  rct::multisig_out msout;
6931 
6932  // 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.
6933  // todo: 4.0.0.0 Migrate vs send regular tx.
6935  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);
6936  THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
6937  // we don't test tx size, because we don't know the current limit, due to not having a blockchain,
6938  // and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
6939  // and if we really go over limit, the daemon will reject when it gets submitted. Chances are it's
6940  // OK anyway since it was generated in the first place, and rerolling should be within a few bytes.
6941 
6942  // normally, the tx keys are saved in commit_tx, when the tx is actually sent to the daemon.
6943  // we can't do that here since the tx will be sent from the compromised wallet, which we don't want
6944  // to see that info, so we save it here
6945  if (store_tx_info())
6946  {
6947  const crypto::hash txid = get_transaction_hash(ptx.tx);
6948  m_tx_keys.insert(std::make_pair(txid, tx_key));
6949  m_additional_tx_keys.insert(std::make_pair(txid, additional_tx_keys));
6950  }
6951 
6952  std::string key_images;
6953 
6954  if(ptx.tx.version < 3) {
6955  bool all_are_txin_to_key = std::all_of(ptx.tx.vin.begin(), ptx.tx.vin.end(), [&](const txin_v &s_e) -> bool {
6956  CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false);
6957  key_images += boost::to_string(in.k_image) + " ";
6958  return true;
6959  });
6960  THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, ptx.tx);
6961  }else{
6962  bool all_are_txin_to_key_public = std::all_of(ptx.tx.vin.begin(), ptx.tx.vin.end(), [&](const txin_v &s_e) -> bool {
6963  CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key_public, in, false);
6964  return true;
6965  });
6966  THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key_public, error::unexpected_txin_type, ptx.tx);
6967  }
6968  if(ptx.tx.version > 1) {
6969  bool all_are_txout_to_key_public = std::all_of(ptx.tx.vout.begin(), ptx.tx.vout.end(), [&](const tx_out &s_e) -> bool {
6970  CHECKED_GET_SPECIFIC_VARIANT(s_e.target, const txout_to_key_public, in, false);
6971  return true;
6972  });
6973  THROW_WALLET_EXCEPTION_IF(!all_are_txout_to_key_public, error::unexpected_txout_type, ptx.tx);
6974  }
6975  ptx.key_images = key_images;
6976  ptx.fee = 0;
6977  for (const auto &i: sd.sources) ptx.fee += i.amount;
6978  for (const auto &i: sd.splitted_dsts) ptx.fee -= i.amount;
6979  ptx.dust = 0;
6980  ptx.dust_added_to_fee = false;
6981  ptx.change_dts = sd.change_dts;
6983  ptx.tx_key = rct::rct2sk(rct::identity()); // don't send it back to the untrusted view wallet
6984  ptx.dests = sd.dests;
6985  ptx.construction_data = sd;
6986 
6987  txs.push_back(ptx);
6988 
6989  // add tx keys only to ptx
6990  txs.back().tx_key = tx_key;
6991  txs.back().additional_tx_keys = additional_tx_keys;
6992  }
6993 
6994  // add key image mapping for these txes
6995  const account_keys &keys = get_account().get_keys();
6996  hw::device &hwdev = m_account.get_device();
6997  for (size_t n = 0; n < exported_txs.txes.size(); ++n)
6998  {
6999  const cryptonote::transaction &tx = signed_txes.ptx[n].tx;
7000 
7001  crypto::key_derivation derivation;
7002  std::vector<crypto::key_derivation> additional_derivations;
7003 
7004  // compute public keys from out secret keys
7005  crypto::public_key tx_pub_key;
7006  crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key);
7007  std::vector<crypto::public_key> additional_tx_pub_keys;
7008  for (const crypto::secret_key &skey: txs[n].additional_tx_keys)
7009  {
7010  additional_tx_pub_keys.resize(additional_tx_pub_keys.size() + 1);
7011  crypto::secret_key_to_public_key(skey, additional_tx_pub_keys.back());
7012  }
7013 
7014  // compute derivations
7016  if (!hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation))
7017  {
7018  MWARNING("Failed to generate key derivation from tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
7019  static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key");
7020  memcpy(&derivation, rct::identity().bytes, sizeof(derivation));
7021  }
7022  for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
7023  {
7024  additional_derivations.push_back({});
7025  if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
7026  {
7027  MWARNING("Failed to generate key derivation from additional tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
7028  memcpy(&additional_derivations.back(), rct::identity().bytes, sizeof(crypto::key_derivation));
7029  }
7030  }
7031 
7032  for (size_t i = 0; i < tx.vout.size(); ++i)
7033  {
7034  if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
7035  continue;
7036  const cryptonote::txout_to_key &out = boost::get<cryptonote::txout_to_key>(tx.vout[i].target);
7037  // if this output is back to this wallet, we can calculate its key image already
7038  if (!is_out_to_acc_precomp(m_subaddresses, out.key, derivation, additional_derivations, i, hwdev))
7039  continue;
7040  crypto::key_image ki;
7041  cryptonote::keypair in_ephemeral;
7042  if (generate_key_image_helper(keys, m_subaddresses, out.key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev))
7043  signed_txes.tx_key_images[out.key] = ki;
7044  else
7045  MERROR("Failed to calculate key image");
7046  }
7047  }
7048 
7049  // add key images
7050  signed_txes.key_images.resize(m_transfers.size());
7051  for (size_t i = 0; i < m_transfers.size(); ++i)
7052  {
7053  if (!m_transfers[i].m_key_image_known || m_transfers[i].m_key_image_partial)
7054  LOG_PRINT_L0("WARNING: key image not known in signing wallet at index " << i);
7055  signed_txes.key_images[i] = m_transfers[i].m_key_image;
7056  }
7057 
7058  return true;
7059 }
@ 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)
std::vector< size_t > selected_transfers
Definition: wallet2.h:464
std::vector< cryptonote::tx_destination_entry > dests
Definition: wallet2.h:468
std::string key_images
Definition: wallet2.h:465
std::vector< cryptonote::tx_destination_entry > dests
Definition: wallet2.h:424
cryptonote::tx_destination_entry change_dts
Definition: wallet2.h:417
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 7094 of file wallet2.cpp.

7095 {
7096  // sign the transactions
7097  bool r = sign_tx(exported_txs, ptx, signed_txes);
7098  if (!r)
7099  {
7100  LOG_PRINT_L0("Failed to sign unsigned_tx_set");
7101  return std::string();
7102  }
7103 
7104  // save as binary
7105  std::ostringstream oss;
7107  try
7108  {
7109  ar << signed_txes;
7110  }
7111  catch(...)
7112  {
7113  return std::string();
7114  }
7115  LOG_PRINT_L3("Saving signed tx data (with encryption): " << oss.str());
7116  std::string ciphertext = encrypt_with_view_secret_key(oss.str());
7117  return std::string(SIGNED_TX_PREFIX) + ciphertext;
7118 }
#define LOG_PRINT_L3(x)
Definition: misc_log_ex.h:102

◆ stop()

void tools::wallet2::stop ( )
inline

Definition at line 754 of file wallet2.h.

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

◆ store()

void tools::wallet2::store ( )

Definition at line 5922 of file wallet2.cpp.

5923 {
5924  if (!m_wallet_file.empty())
5926 }
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:5928
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 5928 of file wallet2.cpp.

5929 {
5930  trim_hashchain();
5931 
5932  // if file is the same, we do:
5933  // 1. save wallet to the *.new file
5934  // 2. remove old wallet file
5935  // 3. rename *.new to wallet_name
5936 
5937  // handle if we want just store wallet state to current files (ex store() replacement);
5938  bool same_file = true;
5939  if (!path.empty())
5940  {
5941  std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string();
5942  size_t pos = canonical_path.find(path);
5943  same_file = pos != std::string::npos;
5944  }
5945 
5946 
5947  if (!same_file)
5948  {
5949  // check if we want to store to directory which doesn't exists yet
5950  boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
5951 
5952  // if path is not exists, try to create it
5953  if (!parent_path.empty() && !boost::filesystem::exists(parent_path))
5954  {
5955  boost::system::error_code ec;
5956  if (!boost::filesystem::create_directories(parent_path, ec))
5957  {
5958  throw std::logic_error(ec.message());
5959  }
5960  }
5961  }
5962  // preparing wallet data
5963  std::stringstream oss;
5965  ar << *this;
5966 
5967  wallet2::cache_file_data cache_file_data = boost::value_initialized<wallet2::cache_file_data>();
5968  cache_file_data.cache_data = oss.str();
5969  std::string cipher;
5970  cipher.resize(cache_file_data.cache_data.size());
5971  cache_file_data.iv = crypto::rand<crypto::chacha_iv>();
5972  crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cipher[0]);
5973  cache_file_data.cache_data = cipher;
5974 
5975  const std::string new_file = same_file ? m_wallet_file + ".new" : path;
5976  const std::string old_file = m_wallet_file;
5977  const std::string old_keys_file = m_keys_file;
5978  const std::string old_address_file = m_wallet_file + ".address.txt";
5979  const std::string old_mms_file = m_mms_file;
5980 
5981  // save keys to the new file
5982  // if we here, main wallet file is saved and we only need to save keys and address files
5983  if (!same_file) {
5984  prepare_file_names(path);
5985  bool r = store_keys(m_keys_file, password, false);
5987  if (boost::filesystem::exists(old_address_file))
5988  {
5989  // save address to the new file
5990  const std::string address_file = m_wallet_file + ".address.txt";
5991  r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_nettype));
5993  }
5994  // remove old wallet file
5995  r = boost::filesystem::remove(old_file);
5996  if (!r) {
5997  LOG_ERROR("error removing file: " << old_file);
5998  }
5999  // remove old keys file
6000  r = boost::filesystem::remove(old_keys_file);
6001  if (!r) {
6002  LOG_ERROR("error removing file: " << old_keys_file);
6003  }
6004  // remove old address file
6005  r = boost::filesystem::remove(old_address_file);
6006  if (!r) {
6007  LOG_ERROR("error removing file: " << old_address_file);
6008  }
6009  // remove old message store file
6010  if (boost::filesystem::exists(old_mms_file))
6011  {
6012  r = boost::filesystem::remove(old_mms_file);
6013  if (!r) {
6014  LOG_ERROR("error removing file: " << old_mms_file);
6015  }
6016  }
6017  } else {
6018  // save to new file
6019 #ifdef WIN32
6020  // On Windows avoid using std::ofstream which does not work with UTF-8 filenames
6021  // The price to pay is temporary higher memory consumption for string stream + binary archive
6022  std::ostringstream oss;
6023  binary_archive<true> oar(oss);
6024  bool success = ::serialization::serialize(oar, cache_file_data);
6025  if (success) {
6026  success = epee::file_io_utils::save_string_to_file(new_file, oss.str());
6027  }
6029 #else
6030  std::ofstream ostr;
6031  ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
6032  binary_archive<true> oar(ostr);
6033  bool success = ::serialization::serialize(oar, cache_file_data);
6034  ostr.close();
6035  THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
6036 #endif
6037 
6038  // here we have "*.new" file, we need to rename it to be without ".new"
6039  std::error_code e = tools::replace_file(new_file, m_wallet_file);
6040  THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
6041  }
6042 
6043  if (m_message_store.get_active())
6044  {
6045  // While the "m_message_store" object of course always exist, a file for the message
6046  // store should only exist if the MMS is really active
6047  m_message_store.write_to_file(get_multisig_wallet_state(), m_mms_file);
6048  }
6049 
6050 }
void write_to_file(const multisig_wallet_state &state, const std::string &filename)
bool get_active() const
std::string path() const
Definition: wallet2.cpp:5917
expect< void > success() noexcept
Definition: expect.h:397
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
void serialize(Archive &a, unsigned_tx_set &x, const boost::serialization::version_type ver)
Here is the call graph for this function:

◆ store_tx_info() [1/2]

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

Definition at line 1061 of file wallet2.h.

1061 { return m_store_tx_info; }

◆ store_tx_info() [2/2]

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

Definition at line 1062 of file wallet2.h.

1062 { 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 891 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 1609 of file wallet2.cpp.

1610 {
1612 }
void thaw(size_t idx)
Definition: wallet2.cpp:1590
Here is the call graph for this function:

◆ thaw() [2/2]

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

Definition at line 1590 of file wallet2.cpp.

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

◆ tr()

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

Definition at line 993 of file wallet2.cpp.

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

◆ track_uses() [1/2]

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

Definition at line 1097 of file wallet2.h.

1097 { return m_track_uses; }

◆ track_uses() [2/2]

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

Definition at line 1098 of file wallet2.h.

1098 { 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 8742 of file wallet2.cpp.

8745 {
8746  using namespace cryptonote;
8747  // throw if attempting a transaction with no destinations
8748  THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
8749 
8750  THROW_WALLET_EXCEPTION_IF(m_multisig, error::wallet_internal_error, "Multisig wallets cannot spend non rct outputs");
8751 
8752  uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit();
8753  uint64_t needed_etn = fee;
8754  LOG_PRINT_L2("transfer: starting with fee " << print_etn (needed_etn));
8755 
8756  // calculate total amount being sent to all destinations
8757  // throw if total amount overflows uint64_t
8758  for(auto& dt: dsts)
8759  {
8760  THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination);
8761  needed_etn += dt.amount;
8762  LOG_PRINT_L2("transfer: adding " << print_etn(dt.amount) << ", for a total of " << print_etn (needed_etn));
8763  THROW_WALLET_EXCEPTION_IF(needed_etn < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype);
8764  }
8765 
8766  uint64_t found_etn = 0;
8767  for(size_t idx: selected_transfers)
8768  {
8769  found_etn += m_transfers[idx].amount();
8770  }
8771 
8772  LOG_PRINT_L2("wanted " << print_etn(needed_etn) << ", found " << print_etn(found_etn) << ", fee " << print_etn(fee));
8773  THROW_WALLET_EXCEPTION_IF(found_etn < needed_etn, error::not_enough_unlocked_etn, found_etn, needed_etn - fee, fee);
8774 
8775  uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
8776  for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
8777  THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts");
8778 
8779  if (outs.empty())
8780  get_outs(outs, selected_transfers, fake_outputs_count, tx.version); // may throw
8781 
8782  //prepare inputs
8783  LOG_PRINT_L2("preparing outputs");
8784  typedef cryptonote::tx_source_entry::output_entry tx_output_entry;
8785  size_t i = 0, out_index = 0;
8786  std::vector<cryptonote::tx_source_entry> sources;
8787  for(size_t idx: selected_transfers)
8788  {
8789  sources.resize(sources.size()+1);
8790  cryptonote::tx_source_entry& src = sources.back();
8791  const transfer_details& td = m_transfers[idx];
8792  src.amount = td.amount();
8793  src.rct = td.is_rct();
8794  if(tx.version < 3) {
8795  //paste keys (fake and real)
8796  // adding pairs of global index & stealth address to our vector of source outs (needed forold ins only)
8797  for (size_t n = 0; n < fake_outputs_count + 1; ++n) {
8798  tx_output_entry oe;
8799  oe.first = std::get<0>(outs[out_index][n]);
8800  oe.second.dest = rct::pk2rct(std::get<1>(outs[out_index][n]));
8801  oe.second.mask = std::get<2>(outs[out_index][n]);
8802 
8803  src.outputs.push_back(oe);
8804  ++i;
8805  }
8806 
8807  //paste real transaction to the random index
8808  auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry &a) {
8809  return a.first == td.m_global_output_index;
8810  });
8811  THROW_WALLET_EXCEPTION_IF(it_to_replace == src.outputs.end(), error::wallet_internal_error,
8812  "real output not found");
8813 
8814  tx_output_entry real_oe;
8815  real_oe.first = td.m_global_output_index;
8816  real_oe.second.dest = rct::pk2rct(
8817  boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
8818  real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
8819  *it_to_replace = real_oe;
8820  src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
8822  src.real_output = it_to_replace - src.outputs.begin();
8824  }
8825  src.real_output_in_tx_index = td.m_internal_output_index; // these two are all we really need for v3 sources
8826  src.tx_hash = td.m_txid;
8827  src.subaddr_index = td.m_subaddr_index;
8829  ++out_index;
8830  }
8831  LOG_PRINT_L2("outputs prepared");
8832 
8833  cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
8834  if (needed_etn < found_etn)
8835  {
8836  // send change to the first input's address for v3+ tx
8837  uint32_t change_subaddress_minor = tx.version > 2 ? sources.front().subaddr_index.minor : 0;
8838  change_dts.addr = get_subaddress({subaddr_account, change_subaddress_minor});
8839  change_dts.is_subaddress = (subaddr_account != 0 || change_subaddress_minor != 0);
8840  change_dts.amount = found_etn - needed_etn;
8841  }
8842 
8843  std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts;
8844  uint64_t dust = 0;
8845  destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts);
8846  for(auto& d: dust_dsts) {
8847  THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " +
8848  std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold));
8849  }
8850  for(auto& d: dust_dsts) {
8851  if (!dust_policy.add_to_fee)
8852  splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust, d.is_subaddress));
8853  dust += d.amount;
8854  }
8855 
8856  crypto::secret_key tx_key;
8857  std::vector<crypto::secret_key> additional_tx_keys;
8858  rct::multisig_out msout;
8859 
8860  LOG_PRINT_L2("constructing tx");
8861  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);
8862  LOG_PRINT_L2("constructed tx, r="<<r);
8863  THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype);
8864  THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
8865 
8866  std::string key_images;
8867  bool are_ins_correct_type = tx.version >= 3 ?
8868  std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
8869  {
8870  CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key_public, in, false);
8871  return true;
8872  })
8873  :
8874  std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
8875  {
8876  CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false);
8877  key_images += boost::to_string(in.k_image) + " ";
8878  return true;
8879  });
8880 
8881  THROW_WALLET_EXCEPTION_IF(!are_ins_correct_type, error::unexpected_txin_type, tx);
8882 
8883 
8884  bool dust_sent_elsewhere = (dust_policy.addr_for_dust.m_view_public_key != change_dts.addr.m_view_public_key
8885  || dust_policy.addr_for_dust.m_spend_public_key != change_dts.addr.m_spend_public_key);
8886 
8887  if (dust_policy.add_to_fee || dust_sent_elsewhere) change_dts.amount -= dust;
8888 
8889  ptx.key_images = key_images;
8890  ptx.fee = (dust_policy.add_to_fee ? fee+dust : fee);
8891  ptx.dust = ((dust_policy.add_to_fee || dust_sent_elsewhere) ? dust : 0);
8892  ptx.dust_added_to_fee = dust_policy.add_to_fee;
8893  ptx.tx = tx;
8894  ptx.change_dts = change_dts;
8895  ptx.selected_transfers = selected_transfers;
8896  ptx.tx_key = tx_key;
8897  ptx.additional_tx_keys = additional_tx_keys;
8898  ptx.dests = dsts;
8899  ptx.construction_data.sources = sources;
8900  ptx.construction_data.change_dts = change_dts;
8901  ptx.construction_data.splitted_dsts = splitted_dsts;
8902  ptx.construction_data.selected_transfers = selected_transfers;
8903  ptx.construction_data.extra = tx.extra;
8904  ptx.construction_data.unlock_time = unlock_time;
8905  ptx.construction_data.use_rct = false;
8906  ptx.construction_data.rct_config = { rct::RangeProofBorromean, 0 };
8907  ptx.construction_data.dests = dsts;
8908  // record which subaddress indices are being used as inputs
8909  ptx.construction_data.subaddr_account = subaddr_account;
8910  ptx.construction_data.subaddr_indices.clear();
8911  for (size_t idx: selected_transfers)
8912  ptx.construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor);
8913  LOG_PRINT_L2("transfer_selected done");
8914 }
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val)
void print_source_entry(const cryptonote::tx_source_entry &src)
Definition: wallet2.h:2126
int bool
Definition: stdbool.h:36
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:

◆ unblackball_output()

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

Definition at line 7988 of file wallet2.cpp.

7989 {
7990  if (!m_ringdb)
7991  return false;
7992  try { return m_ringdb->unblackball(output); }
7993  catch (const std::exception &e) { return false; }
7994 }

◆ unlock_keys_file()

bool tools::wallet2::unlock_keys_file ( )

Definition at line 8015 of file wallet2.cpp.

8016 {
8017  if (!m_keys_file_locker)
8018  {
8019  MDEBUG(m_keys_file << " is already unlocked.");
8020  return false;
8021  }
8022  m_keys_file_locker.reset();
8023  return true;
8024 }

◆ 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 6062 of file wallet2.cpp.

6063 {
6064  uint64_t amount = 0;
6065  if (blocks_to_unlock)
6066  *blocks_to_unlock = 0;
6067  if(m_light_wallet)
6068  return m_light_wallet_balance;
6069  for (const auto& i : unlocked_balance_per_subaddress(index_major, public_blockchain))
6070  {
6071  amount += i.second.first;
6072  if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
6073  *blocks_to_unlock = i.second.second;
6074  }
6075  return amount;
6076 }
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 6190 of file wallet2.cpp.

6191 {
6192  uint64_t r = 0;
6193  if (blocks_to_unlock)
6194  *blocks_to_unlock = 0;
6195  for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
6196  {
6197  uint64_t local_blocks_to_unlock;
6198  r += unlocked_balance(index_major, public_blockchain ,blocks_to_unlock ? &local_blocks_to_unlock : NULL);
6199  if (blocks_to_unlock)
6200  *blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
6201  }
6202  return r;
6203 }

◆ 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 6139 of file wallet2.cpp.

6140 {
6141  std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr; //map of subaddr minor index : <amount,unlock t>
6142  const uint64_t blockchain_height = get_blockchain_current_height();
6143  //Figure out amount & blocks_to_unlock for the major subaddress index for each transfer
6144  for(const transfer_details& td: m_transfers)
6145  {
6146  if((public_blockchain && td.m_tx.version == 1) || (!public_blockchain && td.m_tx.version > 1))
6147  continue;
6148 
6149  if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
6150  {
6151  uint64_t amount = 0, blocks_to_unlock = 0;
6152  if (is_transfer_unlocked(td))
6153  {
6154  amount = td.amount();
6155  blocks_to_unlock = 0;
6156  }
6157  else
6158  {
6159 
6160  uint64_t v8height = m_nettype == TESTNET ? 446674 : 589169;
6161  uint16_t UNLOCK_WINDOW = td.m_block_height > v8height ? ETN_DEFAULT_TX_SPENDABLE_AGE_V8 : CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
6162  uint64_t unlock_height = td.m_block_height + std::max<uint64_t>(UNLOCK_WINDOW, CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);
6163  if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > unlock_height)
6164  unlock_height = td.m_tx.unlock_time;
6165  blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 0;
6166  amount = 0;
6167  }
6168  auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
6169  // if we don't have this subaddress index (key) in our map, create a new entry, otherwise just add a new pair
6170  if (found == amount_per_subaddr.end())
6171  amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, blocks_to_unlock);
6172  else
6173  {
6174  found->second.first += amount;
6175  found->second.second = std::max(found->second.second, blocks_to_unlock);
6176  }
6177  }
6178  }
6179  return amount_per_subaddr;
6180 }

◆ unset_ring() [1/2]

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

Definition at line 7871 of file wallet2.cpp.

7872 {
7873  if (!m_ringdb)
7874  return false;
7875 
7878  req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
7879  req.decode_as_json = false;
7880  req.prune = true;
7881  m_daemon_rpc_mutex.lock();
7882  bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
7883  m_daemon_rpc_mutex.unlock();
7884  THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to get transaction from daemon");
7885  if (res.txs.empty())
7886  return false;
7887  THROW_WALLET_EXCEPTION_IF(res.txs.size(), error::wallet_internal_error, "Failed to get transaction from daemon");
7888 
7890  crypto::hash tx_hash;
7891  if (!get_pruned_tx(res.txs.front(), tx, tx_hash))
7892  return false;
7893  THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
7894 
7895  try { return m_ringdb->remove_rings(get_ringdb_key(), tx); }
7896  catch (const std::exception &e) { return false; }
7897 }
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 7862 of file wallet2.cpp.

7863 {
7864  if (!m_ringdb)
7865  return false;
7866 
7867  try { return m_ringdb->remove_rings(get_ringdb_key(), key_images); }
7868  catch (const std::exception &e) { return false; }
7869 }

◆ update_pool_state()

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

Definition at line 3147 of file wallet2.cpp.

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

10511 {
10512  // TODO: How to get fork rule info from light wallet node?
10513  if(m_light_wallet)
10514  return true;
10515  uint64_t height, earliest_height;
10516  boost::optional<std::string> result = m_node_rpc_proxy.get_height(height);
10517  throw_on_rpc_response_error(result, "get_info");
10518  result = m_node_rpc_proxy.get_earliest_height(version, earliest_height);
10519  throw_on_rpc_response_error(result, "get_hard_fork_info");
10520 
10521  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
10522  if (close_enough)
10523  LOG_PRINT_L2("Using v" << (unsigned)version << " rules");
10524  else
10525  LOG_PRINT_L2("Not using v" << (unsigned)version << " rules");
10526  return close_enough;
10527 }

◆ verify()

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

Definition at line 11876 of file wallet2.cpp.

11877 {
11878  const size_t header_len = strlen("SigV1");
11879  if (signature.size() < header_len || signature.substr(0, header_len) != "SigV1") {
11880  LOG_PRINT_L0("Signature header check error");
11881  return false;
11882  }
11884  crypto::cn_fast_hash(data.data(), data.size(), hash);
11885  std::string decoded;
11886  if (!tools::base58::decode(signature.substr(header_len), decoded)) {
11887  LOG_PRINT_L0("Signature decoding error");
11888  return false;
11889  }
11891  if (sizeof(s) != decoded.size()) {
11892  LOG_PRINT_L0("Signature decoding error");
11893  return false;
11894  }
11895  memcpy(&s, decoded.data(), sizeof(s));
11896  return crypto::check_signature(hash, address.m_spend_public_key, s);
11897 }
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 5476 of file wallet2.cpp.

5477 {
5478  if (data.size() < MULTISIG_EXTRA_INFO_MAGIC.size() || data.substr(0, MULTISIG_EXTRA_INFO_MAGIC.size()) != MULTISIG_EXTRA_INFO_MAGIC)
5479  {
5480  MERROR("Multisig info header check error");
5481  return false;
5482  }
5483  std::string decoded;
5484  if (!tools::base58::decode(data.substr(MULTISIG_EXTRA_INFO_MAGIC.size()), decoded))
5485  {
5486  MERROR("Multisig info decoding error");
5487  return false;
5488  }
5489  if (decoded.size() < sizeof(crypto::public_key) + sizeof(crypto::signature))
5490  {
5491  MERROR("Multisig info is corrupt");
5492  return false;
5493  }
5494  if ((decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) % sizeof(crypto::public_key))
5495  {
5496  MERROR("Multisig info is corrupt");
5497  return false;
5498  }
5499 
5500  const size_t n_keys = (decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) / sizeof(crypto::public_key);
5501  size_t offset = 0;
5502  signer = *(const crypto::public_key*)(decoded.data() + offset);
5503  offset += sizeof(signer);
5504  const crypto::signature &signature = *(const crypto::signature*)(decoded.data() + offset + n_keys * sizeof(crypto::public_key));
5505 
5507  crypto::cn_fast_hash(decoded.data(), decoded.size() - sizeof(signature), hash);
5508  if (!crypto::check_signature(hash, signer, signature))
5509  {
5510  MERROR("Multisig info signature is invalid");
5511  return false;
5512  }
5513 
5514  for (size_t n = 0; n < n_keys; ++n)
5515  {
5516  crypto::public_key mspk = *(const crypto::public_key*)(decoded.data() + offset);
5517  pkeys.insert(mspk);
5518  offset += sizeof(mspk);
5519  }
5520 
5521  return true;
5522 }

◆ 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 5438 of file wallet2.cpp.

5439 {
5440  const size_t header_len = strlen("MultisigV1");
5441  if (data.size() < header_len || data.substr(0, header_len) != "MultisigV1")
5442  {
5443  MERROR("Multisig info header check error");
5444  return false;
5445  }
5446  std::string decoded;
5447  if (!tools::base58::decode(data.substr(header_len), decoded))
5448  {
5449  MERROR("Multisig info decoding error");
5450  return false;
5451  }
5452  if (decoded.size() != sizeof(crypto::secret_key) + sizeof(crypto::public_key) + sizeof(crypto::signature))
5453  {
5454  MERROR("Multisig info is corrupt");
5455  return false;
5456  }
5457 
5458  size_t offset = 0;
5459  skey = *(const crypto::secret_key*)(decoded.data() + offset);
5460  offset += sizeof(skey);
5461  pkey = *(const crypto::public_key*)(decoded.data() + offset);
5462  offset += sizeof(pkey);
5463  const crypto::signature &signature = *(const crypto::signature*)(decoded.data() + offset);
5464 
5466  crypto::cn_fast_hash(decoded.data(), decoded.size() - sizeof(signature), hash);
5467  if (!crypto::check_signature(hash, pkey, signature))
5468  {
5469  MERROR("Multisig info signature is invalid");
5470  return false;
5471  }
5472 
5473  return true;
5474 }
Here is the call 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 4567 of file wallet2.cpp.

4568 {
4569  // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
4570  unlock_keys_file();
4571  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);
4572  lock_keys_file();
4573  return r;
4574 }
virtual device_protocol_t device_protocol() const
Definition: device.hpp:135
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:4589

◆ 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 4589 of file wallet2.cpp.

4590 {
4592  wallet2::keys_file_data keys_file_data;
4593  std::string buf;
4594  bool encrypted_secret_keys = false;
4595  bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
4597 
4598  // Decrypt the contents
4599  r = ::serialization::parse_binary(buf, keys_file_data);
4600  THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
4601  crypto::chacha_key key;
4602  crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
4603  std::string account_data;
4604  account_data.resize(keys_file_data.account_data.size());
4605  crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4606  if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject())
4607  crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
4608 
4609  // The contents should be JSON if the wallet follows the new format.
4610  if (json.Parse(account_data.c_str()).HasParseError())
4611  {
4612  // old format before JSON wallet key file format
4613  }
4614  else
4615  {
4616  account_data = std::string(json["key_data"].GetString(), json["key_data"].GetString() +
4617  json["key_data"].GetStringLength());
4618  GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, encrypted_secret_keys, uint32_t, Uint, false, false);
4619  encrypted_secret_keys = field_encrypted_secret_keys;
4620  }
4621 
4622  cryptonote::account_base account_data_check;
4623 
4624  r = epee::serialization::load_t_from_binary(account_data_check, account_data);
4625 
4626  if (encrypted_secret_keys)
4627  account_data_check.decrypt_keys(key);
4628 
4629  const cryptonote::account_keys& keys = account_data_check.get_keys();
4631  if(!no_spend_key)
4633  return r;
4634 }
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 11911 of file wallet2.cpp.

11912 {
11913  if (signature.size() < MULTISIG_SIGNATURE_MAGIC.size() || signature.substr(0, MULTISIG_SIGNATURE_MAGIC.size()) != MULTISIG_SIGNATURE_MAGIC) {
11914  MERROR("Signature header check error");
11915  return false;
11916  }
11918  crypto::cn_fast_hash(data.data(), data.size(), hash);
11919  std::string decoded;
11920  if (!tools::base58::decode(signature.substr(MULTISIG_SIGNATURE_MAGIC.size()), decoded)) {
11921  MERROR("Signature decoding error");
11922  return false;
11923  }
11925  if (sizeof(s) != decoded.size()) {
11926  MERROR("Signature decoding error");
11927  return false;
11928  }
11929  memcpy(&s, decoded.data(), sizeof(s));
11931 }

◆ 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 5587 of file wallet2.cpp.

5588 {
5589  std::string keys_file, wallet_file, mms_file;
5590  do_prepare_file_names(file_path, keys_file, wallet_file, mms_file);
5591 
5592  boost::system::error_code ignore;
5593  keys_file_exists = boost::filesystem::exists(keys_file, ignore);
5594  wallet_file_exists = boost::filesystem::exists(wallet_file, ignore);
5595 }
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 5597 of file wallet2.cpp.

5598 {
5599  return !file_path.empty();
5600 }

◆ watch_only()

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

Definition at line 819 of file wallet2.h.

819 { return m_watch_only; }
Here is the caller graph for this function:

◆ 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 5576 of file wallet2.cpp.

5577 {
5578  prepare_file_names(wallet_name);
5579  boost::system::error_code ignored_ec;
5580  new_keys_filename = m_wallet_file + "-watchonly.keys";
5581  bool watch_only_keys_file_exists = boost::filesystem::exists(new_keys_filename, ignored_ec);
5582  THROW_WALLET_EXCEPTION_IF(watch_only_keys_file_exists, error::file_save_error, new_keys_filename);
5583  bool r = store_keys(new_keys_filename, password, true);
5584  THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, new_keys_filename);
5585 }

Friends And Related Function Documentation

◆ ::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 1301 of file wallet2.h.

◆ rpc_timeout

constexpr 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: