aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/transaction_history.cpp2
-rw-r--r--src/wallet/api/wallet.cpp40
-rw-r--r--src/wallet/wallet2.cpp41
-rw-r--r--src/wallet/wallet2.h6
-rw-r--r--src/wallet/wallet2_api.h2
-rw-r--r--src/wallet/wallet_errors.h27
6 files changed, 97 insertions, 21 deletions
diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp
index e4a003b02..2ba5f3620 100644
--- a/src/wallet/api/transaction_history.cpp
+++ b/src/wallet/api/transaction_history.cpp
@@ -156,8 +156,8 @@ void TransactionHistoryImpl::refresh()
const crypto::hash &hash = i->first;
const tools::wallet2::confirmed_transfer_details &pd = i->second;
- uint64_t fee = pd.m_amount_in - pd.m_amount_out;
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
+ uint64_t fee = pd.m_amount_in - pd.m_amount_out - change;
std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id);
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index d1c849537..9a9638b40 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -158,8 +158,33 @@ std::string Wallet::genPaymentId()
bool Wallet::paymentIdValid(const string &paiment_id)
{
- crypto::hash8 pid;
- return tools::wallet2::parse_short_payment_id(paiment_id, pid);
+ crypto::hash8 pid8;
+ if (tools::wallet2::parse_short_payment_id(paiment_id, pid8))
+ return true;
+ crypto::hash pid;
+ if (tools::wallet2::parse_long_payment_id(paiment_id, pid))
+ return true;
+ return false;
+}
+
+bool Wallet::addressValid(const std::string &str, bool testnet)
+{
+ bool has_payment_id;
+ cryptonote::account_public_address address;
+ crypto::hash8 pid;
+ return get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str);
+}
+
+std::string Wallet::paymentIdFromAddress(const std::string &str, bool testnet)
+{
+ bool has_payment_id;
+ cryptonote::account_public_address address;
+ crypto::hash8 pid;
+ if (!get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str))
+ return "";
+ if (!has_payment_id)
+ return "";
+ return epee::string_tools::pod_to_hex(pid);
}
uint64_t Wallet::maximumAllowedAmount()
@@ -360,7 +385,7 @@ std::string WalletImpl::integratedAddress(const std::string &payment_id) const
{
crypto::hash8 pid;
if (!tools::wallet2::parse_short_payment_id(payment_id, pid)) {
- pid = crypto::rand<crypto::hash8>();
+ return "";
}
return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet());
}
@@ -595,6 +620,15 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
m_status = Status_Error;
std::ostringstream writer;
+ writer << boost::format(tr("not enough money to transfer, available only %s, sent amount %s")) %
+ print_money(e.available()) %
+ print_money(e.tx_amount());
+ m_errorString = writer.str();
+
+ } catch (const tools::error::tx_not_possible& e) {
+ m_status = Status_Error;
+ std::ostringstream writer;
+
writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) %
print_money(e.available()) %
print_money(e.tx_amount() + e.fee()) %
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index d691793cd..23e016f7b 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1517,8 +1517,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
}
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, watch_only, int, Int, false, false);
m_watch_only = field_watch_only;
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, always_confirm_transfers, int, Int, false, false);
- m_always_confirm_transfers = field_always_confirm_transfers_found && field_always_confirm_transfers;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, always_confirm_transfers, int, Int, false, true);
+ m_always_confirm_transfers = field_always_confirm_transfers;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, store_tx_keys, int, Int, false, true);
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, store_tx_info, int, Int, false, true);
m_store_tx_info = ((field_store_tx_keys != 0) || (field_store_tx_info != 0));
@@ -1549,10 +1549,9 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
LOG_PRINT_L0("Unknown refresh-type value (" << field_refresh_type << "), using default");
}
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, refresh_height, uint64_t, Uint64, false, 0);
- if (field_refresh_height_found)
- m_refresh_from_block_height = field_refresh_height;
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_missing_payment_id, int, Int, false, false);
- m_confirm_missing_payment_id = !field_confirm_missing_payment_id_found || field_confirm_missing_payment_id;
+ m_refresh_from_block_height = field_refresh_height;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_missing_payment_id, int, Int, false, true);
+ m_confirm_missing_payment_id = field_confirm_missing_payment_id;
}
const cryptonote::account_keys& keys = m_account.get_keys();
@@ -2287,9 +2286,9 @@ size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::ve
{
const transfer_details &candidate = transfers[unused_indices[n]];
float relatedness = 0.0f;
- for (size_t i = 0; i < selected_transfers.size(); ++i)
+ for (std::list<size_t>::const_iterator i = selected_transfers.begin(); i != selected_transfers.end(); ++i)
{
- float r = get_output_relatedness(candidate, transfers[i]);
+ float r = get_output_relatedness(candidate, transfers[*i]);
if (r > relatedness)
{
relatedness = r;
@@ -2880,8 +2879,10 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
COMMAND_RPC_GET_OUTPUTS::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_GET_OUTPUTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
+ size_t num_selected_transfers = 0;
for(size_t idx: selected_transfers)
{
+ ++num_selected_transfers;
const transfer_details &td = m_transfers[idx];
const uint64_t amount = td.is_rct() ? 0 : td.amount();
std::unordered_set<uint64_t> seen_indices;
@@ -2998,7 +2999,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
std::unordered_map<uint64_t, uint64_t> scanty_outs;
size_t base = 0;
- outs.reserve(selected_transfers.size());
+ outs.reserve(num_selected_transfers);
for(size_t idx: selected_transfers)
{
const transfer_details &td = m_transfers[idx];
@@ -3496,6 +3497,12 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs");
+ // early out if we know we can't make it anyway
+ // we could also check for being within FEE_PER_KB, but if the fee calculation
+ // ever changes, this might be missed, so let this go through
+ THROW_WALLET_EXCEPTION_IF(needed_money > unlocked_balance(), error::not_enough_money,
+ unlocked_balance(), needed_money, 0);
+
if (unused_dust_indices.empty() && unused_transfers_indices.empty())
return std::vector<wallet2::pending_tx>();
@@ -3536,7 +3543,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// if we need to spend money and don't have any left, we fail
if (unused_dust_indices.empty() && unused_transfers_indices.empty()) {
LOG_PRINT_L2("No more outputs to choose from");
- THROW_WALLET_EXCEPTION_IF(1, error::not_enough_money, unlocked_balance(), needed_money, accumulated_fee + needed_fee);
+ THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(), needed_money, accumulated_fee + needed_fee);
}
// get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
@@ -3676,7 +3683,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
if (adding_fee)
{
LOG_PRINT_L1("We ran out of outputs while trying to gather final fee");
- THROW_WALLET_EXCEPTION_IF(1, error::not_enough_money, unlocked_balance(), needed_money, accumulated_fee + needed_fee);
+ THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(), needed_money, accumulated_fee + needed_fee);
}
LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_fee) <<
@@ -3736,7 +3743,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
uint64_t needed_fee, available_for_fee = 0;
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
- const bool use_rct = use_fork_rules(4, 0);
+ const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
const bool use_new_fee = use_fork_rules(3, -720 * 14);
const uint64_t fee_per_kb = use_new_fee ? FEE_PER_KB : FEE_PER_KB_OLD;
const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee);
@@ -4017,17 +4024,23 @@ uint64_t wallet2::get_num_rct_outputs()
return resp_t.result.histogram[0].total_instances;
}
//----------------------------------------------------------------------------------------------------
+const wallet2::transfer_details &wallet2::get_transfer_details(size_t idx) const
+{
+ THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Bad transfer index");
+ return m_transfers[idx];
+}
+//----------------------------------------------------------------------------------------------------
std::vector<size_t> wallet2::select_available_unmixable_outputs(bool trusted_daemon)
{
// request all outputs with less than 3 instances
- const size_t min_mixin = use_fork_rules(5, 10) ? 2 : 4; // v5 increases min mixin from 2 to 4
+ const size_t min_mixin = use_fork_rules(5, 10) ? 4 : 2; // v5 increases min mixin from 2 to 4
return select_available_outputs_from_histogram(min_mixin + 1, false, true, trusted_daemon);
}
//----------------------------------------------------------------------------------------------------
std::vector<size_t> wallet2::select_available_mixable_outputs(bool trusted_daemon)
{
// request all outputs with at least 3 instances, so we can use mixin 2 with
- const size_t min_mixin = use_fork_rules(5, 10) ? 2 : 4; // v5 increases min mixin from 2 to 4
+ const size_t min_mixin = use_fork_rules(5, 10) ? 4 : 2; // v5 increases min mixin from 2 to 4
return select_available_outputs_from_histogram(min_mixin + 1, true, true, trusted_daemon);
}
//----------------------------------------------------------------------------------------------------
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index a039c92d6..fa9797219 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -92,10 +92,10 @@ namespace tools
};
private:
- wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true) {}
+ wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers(true), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true) {}
public:
- wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true) {}
+ wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_restricted(restricted), is_old_file_format(false) {}
struct transfer_details
{
uint64_t m_block_height;
@@ -422,7 +422,6 @@ namespace tools
* \return Whether path is valid format
*/
static bool wallet_valid_path_format(const std::string& file_path);
-
static bool parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id);
static bool parse_short_payment_id(const std::string& payment_id_str, crypto::hash8& payment_id);
static bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id);
@@ -447,6 +446,7 @@ namespace tools
bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const;
uint64_t get_num_rct_outputs();
+ const transfer_details &get_transfer_details(size_t idx) const;
void get_hard_fork_info(uint8_t version, uint64_t &earliest_height);
bool use_fork_rules(uint8_t version, int64_t early_blocks = 0);
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 0f622c26c..8427ba250 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -280,6 +280,8 @@ struct Wallet
static uint64_t amountFromDouble(double amount);
static std::string genPaymentId();
static bool paymentIdValid(const std::string &paiment_id);
+ static bool addressValid(const std::string &str, bool testnet);
+ static std::string paymentIdFromAddress(const std::string &str, bool testnet);
static uint64_t maximumAllowedAmount();
/**
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index c5590d79c..93e7c2ec3 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -68,6 +68,7 @@ namespace tools
// transfer_error *
// get_random_outs_general_error
// not_enough_money
+ // tx_not_possible
// not_enough_outs_to_mix
// tx_not_constructed
// tx_rejected
@@ -351,6 +352,32 @@ namespace tools
: transfer_error(std::move(loc), "not enough money")
, m_available(availbable)
, m_tx_amount(tx_amount)
+ {
+ }
+
+ uint64_t available() const { return m_available; }
+ uint64_t tx_amount() const { return m_tx_amount; }
+
+ std::string to_string() const
+ {
+ std::ostringstream ss;
+ ss << transfer_error::to_string() <<
+ ", available = " << cryptonote::print_money(m_available) <<
+ ", tx_amount = " << cryptonote::print_money(m_tx_amount);
+ return ss.str();
+ }
+
+ private:
+ uint64_t m_available;
+ uint64_t m_tx_amount;
+ };
+ //----------------------------------------------------------------------------------------------------
+ struct tx_not_possible : public transfer_error
+ {
+ explicit tx_not_possible(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee)
+ : transfer_error(std::move(loc), "tx not possible")
+ , m_available(availbable)
+ , m_tx_amount(tx_amount)
, m_fee(fee)
{
}