aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/pending_transaction.cpp10
-rw-r--r--src/wallet/api/pending_transaction.h1
-rw-r--r--src/wallet/api/wallet.cpp56
-rw-r--r--src/wallet/api/wallet.h5
-rw-r--r--src/wallet/api/wallet_manager.cpp153
-rw-r--r--src/wallet/api/wallet_manager.h1
-rw-r--r--src/wallet/wallet2.cpp128
-rw-r--r--src/wallet/wallet2.h10
-rw-r--r--src/wallet/wallet2_api.h37
9 files changed, 375 insertions, 26 deletions
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
index 26ce9fc7e..80fb0b9a4 100644
--- a/src/wallet/api/pending_transaction.cpp
+++ b/src/wallet/api/pending_transaction.cpp
@@ -69,6 +69,14 @@ string PendingTransactionImpl::errorString() const
return m_errorString;
}
+std::vector<std::string> PendingTransactionImpl::txid() const
+{
+ std::vector<std::string> txid;
+ for (const auto &pt: m_pending_tx)
+ txid.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(pt.tx)));
+ return txid;
+}
+
bool PendingTransactionImpl::commit()
{
@@ -128,7 +136,7 @@ uint64_t PendingTransactionImpl::dust() const
uint64_t PendingTransactionImpl::fee() const
{
uint64_t result = 0;
- for (const auto ptx : m_pending_tx) {
+ for (const auto &ptx : m_pending_tx) {
result += ptx.fee;
}
return result;
diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h
index 8e09bec91..2f06d2f6e 100644
--- a/src/wallet/api/pending_transaction.h
+++ b/src/wallet/api/pending_transaction.h
@@ -49,6 +49,7 @@ public:
uint64_t amount() const;
uint64_t dust() const;
uint64_t fee() const;
+ std::vector<std::string> txid() const;
// TODO: continue with interface;
private:
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 9a9638b40..3768a7998 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -545,6 +545,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
{
clearStatus();
+ // Pause refresh thread while creating transaction
+ pauseRefresh();
vector<cryptonote::tx_destination_entry> dsts;
cryptonote::tx_destination_entry de;
@@ -678,6 +680,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
transaction->m_status = m_status;
transaction->m_errorString = m_errorString;
+ // Resume refresh thread
+ startRefresh();
return transaction;
}
@@ -707,6 +711,46 @@ void WalletImpl::setDefaultMixin(uint32_t arg)
m_wallet->default_mixin(arg);
}
+bool WalletImpl::setUserNote(const std::string &txid, const std::string &note)
+{
+ cryptonote::blobdata txid_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data))
+ return false;
+ const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+
+ m_wallet->set_tx_note(htxid, note);
+ return true;
+}
+
+std::string WalletImpl::getUserNote(const std::string &txid) const
+{
+ cryptonote::blobdata txid_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data))
+ return "";
+ const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+
+ return m_wallet->get_tx_note(htxid);
+}
+
+std::string WalletImpl::getTxKey(const std::string &txid) const
+{
+ cryptonote::blobdata txid_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data))
+ {
+ return "";
+ }
+ const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+
+ crypto::secret_key tx_key;
+ if (m_wallet->get_tx_key(htxid, tx_key))
+ {
+ return epee::string_tools::pod_to_hex(tx_key);
+ }
+ else
+ {
+ return "";
+ }
+}
bool WalletImpl::connectToDaemon()
{
@@ -720,9 +764,15 @@ bool WalletImpl::connectToDaemon()
return result;
}
-bool WalletImpl::connected() const
+Wallet::ConnectionStatus WalletImpl::connected() const
{
- return m_wallet->check_connection();
+ bool same_version = false;
+ bool is_connected = m_wallet->check_connection(&same_version);
+ if (!is_connected)
+ return Wallet::ConnectionStatus_Disconnected;
+ if (!same_version)
+ return Wallet::ConnectionStatus_WrongVersion;
+ return Wallet::ConnectionStatus_Connected;
}
void WalletImpl::setTrustedDaemon(bool arg)
@@ -798,6 +848,7 @@ void WalletImpl::doRefresh()
void WalletImpl::startRefresh()
{
+ LOG_PRINT_L2(__FUNCTION__ << ": refresh started/resumed...");
if (!m_refreshEnabled) {
m_refreshEnabled = true;
m_refreshCV.notify_one();
@@ -818,6 +869,7 @@ void WalletImpl::stopRefresh()
void WalletImpl::pauseRefresh()
{
+ LOG_PRINT_L2(__FUNCTION__ << ": refresh paused...");
// TODO synchronize access
if (!m_refreshThreadDone) {
m_refreshEnabled = false;
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index c8a59f7c3..3f6d2ac7b 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -70,7 +70,7 @@ public:
bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
void initAsync(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
bool connectToDaemon();
- bool connected() const;
+ ConnectionStatus connected() const;
void setTrustedDaemon(bool arg);
bool trustedDaemon() const;
uint64_t balance() const;
@@ -97,6 +97,9 @@ public:
virtual void setListener(WalletListener * l);
virtual uint32_t defaultMixin() const;
virtual void setDefaultMixin(uint32_t arg);
+ virtual bool setUserNote(const std::string &txid, const std::string &note);
+ virtual std::string getUserNote(const std::string &txid) const;
+ virtual std::string getTxKey(const std::string &txid) const;
private:
void clearStatus();
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index d2395ace1..2d1c44d0e 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -31,6 +31,8 @@
#include "wallet_manager.h"
#include "wallet.h"
+#include "common_defines.h"
+#include "net/http_client.h"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
@@ -133,6 +135,157 @@ void WalletManagerImpl::setDaemonHost(const std::string &hostname)
}
+bool WalletManagerImpl::checkPayment(const std::string &address_text, const std::string &txid_text, const std::string &txkey_text, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const
+{
+ error = "";
+ cryptonote::blobdata txid_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txid_text, txid_data))
+ {
+ error = tr("failed to parse txid");
+ return false;
+ }
+ crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+
+ if (txkey_text.size() < 64 || txkey_text.size() % 64)
+ {
+ error = tr("failed to parse tx key");
+ return false;
+ }
+ crypto::secret_key tx_key;
+ cryptonote::blobdata tx_key_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(txkey_text, tx_key_data))
+ {
+ error = tr("failed to parse tx key");
+ return false;
+ }
+ tx_key = *reinterpret_cast<const crypto::secret_key*>(tx_key_data.data());
+
+ bool testnet = address_text[0] != '4';
+ cryptonote::account_public_address address;
+ bool has_payment_id;
+ crypto::hash8 payment_id;
+ if(!cryptonote::get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_text))
+ {
+ error = tr("failed to parse address");
+ return false;
+ }
+
+ cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req;
+ cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res;
+ req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
+ epee::net_utils::http::http_simple_client http_client;
+ if (!epee::net_utils::invoke_http_json_remote_command2(daemon_address + "/gettransactions", req, res, http_client) ||
+ (res.txs.size() != 1 && res.txs_as_hex.size() != 1))
+ {
+ error = tr("failed to get transaction from daemon");
+ return false;
+ }
+ cryptonote::blobdata tx_data;
+ bool ok;
+ if (res.txs.size() == 1)
+ ok = epee::string_tools::parse_hexstr_to_binbuff(res.txs.front().as_hex, tx_data);
+ else
+ ok = epee::string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
+ if (!ok)
+ {
+ error = tr("failed to parse transaction from daemon");
+ return false;
+ }
+ crypto::hash tx_hash, tx_prefix_hash;
+ cryptonote::transaction tx;
+ if (!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash))
+ {
+ error = tr("failed to validate transaction from daemon");
+ return false;
+ }
+ if (tx_hash != txid)
+ {
+ error = tr("failed to get the right transaction from daemon");
+ return false;
+ }
+
+ crypto::key_derivation derivation;
+ if (!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation))
+ {
+ error = tr("failed to generate key derivation from supplied parameters");
+ return false;
+ }
+
+ received = 0;
+ try {
+ for (size_t n = 0; n < tx.vout.size(); ++n)
+ {
+ if (typeid(cryptonote::txout_to_key) != tx.vout[n].target.type())
+ continue;
+ const cryptonote::txout_to_key tx_out_to_key = boost::get<cryptonote::txout_to_key>(tx.vout[n].target);
+ crypto::public_key pubkey;
+ derive_public_key(derivation, n, address.m_spend_public_key, pubkey);
+ if (pubkey == tx_out_to_key.key)
+ {
+ uint64_t amount;
+ if (tx.version == 1)
+ {
+ amount = tx.vout[n].amount;
+ }
+ else
+ {
+ try
+ {
+ rct::key Ctmp;
+ //rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key)));
+ crypto::key_derivation derivation;
+ bool r = crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation);
+ if (!r)
+ {
+ LOG_ERROR("Failed to generate key derivation to decode rct output " << n);
+ amount = 0;
+ }
+ else
+ {
+ crypto::secret_key scalar1;
+ crypto::derivation_to_scalar(derivation, n, scalar1);
+ rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
+ rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1));
+ rct::key C = tx.rct_signatures.outPk[n].mask;
+ rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H);
+ if (rct::equalKeys(C, Ctmp))
+ amount = rct::h2d(ecdh_info.amount);
+ else
+ amount = 0;
+ }
+ }
+ catch (...) { amount = 0; }
+ }
+ received += amount;
+ }
+ }
+ }
+ catch(const std::exception &e)
+ {
+ LOG_ERROR("error: " << e.what());
+ error = std::string(tr("error: ")) + e.what();
+ return false;
+ }
+
+ if (received > 0)
+ {
+ LOG_PRINT_L1(get_account_address_as_str(testnet, address) << " " << tr("received") << " " << cryptonote::print_money(received) << " " << tr("in txid") << " " << txid);
+ }
+ else
+ {
+ LOG_PRINT_L1(get_account_address_as_str(testnet, address) << " " << tr("received nothing in txid") << " " << txid);
+ }
+ if (res.txs.front().in_pool)
+ {
+ height = 0;
+ }
+ else
+ {
+ height = res.txs.front().block_height;
+ }
+
+ return true;
+}
///////////////////// WalletManagerFactory implementation //////////////////////
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 2e932a2a1..489abe764 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -46,6 +46,7 @@ public:
std::vector<std::string> findWallets(const std::string &path);
std::string errorString() const;
void setDaemonHost(const std::string &hostname);
+ bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const;
private:
WalletManagerImpl() {}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 06e12ebfe..ac8802ca4 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -80,6 +80,8 @@ using namespace cryptonote;
#define RECENT_OUTPUT_RATIO (0.25) // 25% of outputs are from the recent zone
#define RECENT_OUTPUT_ZONE (5 * 86400) // last 5 days are the recent zone
+#define FEE_ESTIMATE_GRACE_BLOCKS 10 // estimate fee valid for that many blocks
+
#define KILL_IOSERVICE() \
do { \
work.reset(); \
@@ -195,7 +197,7 @@ void wallet2::set_unspent(size_t idx)
td.m_spent_height = 0;
}
//----------------------------------------------------------------------------------------------------
-void wallet2::check_acc_out(const account_keys &acc, const tx_out &o, const crypto::public_key &tx_pub_key, size_t i, bool &received, uint64_t &money_transfered, bool &error) const
+void wallet2::check_acc_out_precomp(const crypto::public_key &spend_public_key, const tx_out &o, const crypto::key_derivation &derivation, size_t i, bool &received, uint64_t &money_transfered, bool &error) const
{
if (o.target.type() != typeid(txout_to_key))
{
@@ -203,7 +205,7 @@ void wallet2::check_acc_out(const account_keys &acc, const tx_out &o, const cryp
LOG_ERROR("wrong type id in transaction out");
return;
}
- received = is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, i);
+ received = is_out_to_acc_precomp(spend_public_key, boost::get<txout_to_key>(o.target), derivation, i);
if(received)
{
money_transfered = o.amount; // may be 0 for ringct outputs
@@ -306,6 +308,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
std::deque<uint64_t> amount(tx.vout.size());
std::deque<rct::key> mask(tx.vout.size());
int threads = tools::get_max_concurrency();
+ const cryptonote::account_keys& keys = m_account.get_keys();
+ crypto::key_derivation derivation;
+ generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
if (miner_tx && m_refresh_type == RefreshNoCoinbase)
{
// assume coinbase isn't for us
@@ -314,7 +319,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
{
uint64_t money_transfered = 0;
bool error = false, received = false;
- check_acc_out(m_account.get_keys(), tx.vout[0], tx_pub_key, 0, received, money_transfered, error);
+ check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[0], derivation, 0, received, money_transfered, error);
if (error)
{
r = false;
@@ -324,14 +329,13 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
// this assumes that the miner tx pays a single address
if (received)
{
- wallet_generate_key_image_helper(m_account.get_keys(), tx_pub_key, 0, in_ephemeral[0], ki[0]);
+ wallet_generate_key_image_helper(keys, tx_pub_key, 0, in_ephemeral[0], ki[0]);
THROW_WALLET_EXCEPTION_IF(in_ephemeral[0].pub != boost::get<cryptonote::txout_to_key>(tx.vout[0].target).key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
outs.push_back(0);
if (money_transfered == 0)
{
- const cryptonote::account_keys& keys = m_account.get_keys();
money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, 0, mask[0]);
}
amount[0] = money_transfered;
@@ -347,14 +351,13 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice));
}
- const account_keys &keys = m_account.get_keys();
std::vector<uint64_t> money_transfered(tx.vout.size());
std::deque<bool> error(tx.vout.size());
std::deque<bool> received(tx.vout.size());
// the first one was already checked
for (size_t i = 1; i < tx.vout.size(); ++i)
{
- ioservice.dispatch(boost::bind(&wallet2::check_acc_out, this, std::cref(keys), std::cref(tx.vout[i]), std::cref(tx_pub_key), i,
+ ioservice.dispatch(boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key), std::cref(tx.vout[i]), std::cref(derivation), i,
std::ref(received[i]), std::ref(money_transfered[i]), std::ref(error[i])));
}
KILL_IOSERVICE();
@@ -367,14 +370,13 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
}
if (received[i])
{
- wallet_generate_key_image_helper(m_account.get_keys(), tx_pub_key, i, in_ephemeral[i], ki[i]);
+ wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]);
THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
outs.push_back(i);
if (money_transfered[i] == 0)
{
- const cryptonote::account_keys& keys = m_account.get_keys();
money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]);
}
tx_money_got_in_outs += money_transfered[i];
@@ -395,13 +397,12 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice));
}
- const account_keys &keys = m_account.get_keys();
std::vector<uint64_t> money_transfered(tx.vout.size());
std::deque<bool> error(tx.vout.size());
std::deque<bool> received(tx.vout.size());
for (size_t i = 0; i < tx.vout.size(); ++i)
{
- ioservice.dispatch(boost::bind(&wallet2::check_acc_out, this, std::cref(keys), std::cref(tx.vout[i]), std::cref(tx_pub_key), i,
+ ioservice.dispatch(boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key), std::cref(tx.vout[i]), std::cref(derivation), i,
std::ref(received[i]), std::ref(money_transfered[i]), std::ref(error[i])));
}
KILL_IOSERVICE();
@@ -415,14 +416,13 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
}
if (received[i])
{
- wallet_generate_key_image_helper(m_account.get_keys(), tx_pub_key, i, in_ephemeral[i], ki[i]);
+ wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]);
THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
outs.push_back(i);
if (money_transfered[i] == 0)
{
- const cryptonote::account_keys& keys = m_account.get_keys();
money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]);
}
tx_money_got_in_outs += money_transfered[i];
@@ -437,7 +437,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
{
uint64_t money_transfered = 0;
bool error = false, received = false;
- check_acc_out(m_account.get_keys(), tx.vout[i], tx_pub_key, i, received, money_transfered, error);
+ check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[i], derivation, i, received, money_transfered, error);
if (error)
{
r = false;
@@ -447,14 +447,13 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
{
if (received)
{
- wallet_generate_key_image_helper(m_account.get_keys(), tx_pub_key, i, in_ephemeral[i], ki[i]);
+ wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]);
THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
outs.push_back(i);
if (money_transfered == 0)
{
- const cryptonote::account_keys& keys = m_account.get_keys();
money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]);
}
amount[i] = money_transfered;
@@ -2770,6 +2769,40 @@ uint64_t wallet2::get_fee_multiplier(uint32_t priority, bool use_new_fee) const
return 1;
}
//----------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_dynamic_per_kb_fee_estimate()
+{
+ epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request> req_t = AUTO_VAL_INIT(req_t);
+ epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
+
+ m_daemon_rpc_mutex.lock();
+ req_t.jsonrpc = "2.0";
+ req_t.id = epee::serialization::storage_entry(0);
+ req_t.method = "get_fee_estimate";
+ req_t.params.grace_blocks = FEE_ESTIMATE_GRACE_BLOCKS;
+ bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client);
+ m_daemon_rpc_mutex.unlock();
+ CHECK_AND_ASSERT_THROW_MES(r, "Failed to connect to daemon");
+ CHECK_AND_ASSERT_THROW_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, "Failed to connect to daemon");
+ CHECK_AND_ASSERT_THROW_MES(resp_t.result.status == CORE_RPC_STATUS_OK, "Failed to get fee estimate");
+ return resp_t.result.fee;
+}
+//----------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_per_kb_fee()
+{
+ bool use_dyn_fee = use_fork_rules(HF_VERSION_DYNAMIC_FEE, -720 * 14);
+ if (!use_dyn_fee)
+ return FEE_PER_KB;
+ try
+ {
+ return get_dynamic_per_kb_fee_estimate();
+ }
+ catch (...)
+ {
+ LOG_PRINT_L1("Failed to query per kB fee, using " << print_money(FEE_PER_KB));
+ return FEE_PER_KB;
+ }
+}
+//----------------------------------------------------------------------------------------------------
// separated the call(s) to wallet2::transfer into their own function
//
// this function will make multiple calls to wallet2::transfer if multiple
@@ -2779,7 +2812,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, trusted_daemon);
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_per_kb = get_per_kb_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee);
// failsafe split attempt counter
@@ -3500,7 +3533,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
const bool use_rct = 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_per_kb = get_per_kb_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee);
// throw if attempting a transaction with no destinations
@@ -3782,7 +3815,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
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_per_kb = get_per_kb_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee);
LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs");
@@ -4088,7 +4121,7 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD);
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_per_kb = get_per_kb_fee();
// may throw
std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs(trusted_daemon);
@@ -4416,6 +4449,61 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail
return m_transfers.size();
}
//----------------------------------------------------------------------------------------------------
+std::string wallet2::encrypt(const std::string &plaintext, const crypto::secret_key &skey, bool authenticated) const
+{
+ crypto::chacha8_key key;
+ crypto::generate_chacha8_key(&skey, sizeof(skey), key);
+ std::string ciphertext;
+ crypto::chacha8_iv iv = crypto::rand<crypto::chacha8_iv>();
+ ciphertext.resize(plaintext.size() + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0));
+ crypto::chacha8(plaintext.data(), plaintext.size(), key, iv, &ciphertext[sizeof(iv)]);
+ memcpy(&ciphertext[0], &iv, sizeof(iv));
+ if (authenticated)
+ {
+ crypto::hash hash;
+ crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash);
+ crypto::public_key pkey;
+ crypto::secret_key_to_public_key(skey, pkey);
+ crypto::signature &signature = *(crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)];
+ crypto::generate_signature(hash, pkey, skey, signature);
+ }
+ return std::move(ciphertext);
+}
+//----------------------------------------------------------------------------------------------------
+std::string wallet2::encrypt_with_view_secret_key(const std::string &plaintext, bool authenticated) const
+{
+ return encrypt(plaintext, get_account().get_keys().m_view_secret_key, authenticated);
+}
+//----------------------------------------------------------------------------------------------------
+std::string wallet2::decrypt(const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated) const
+{
+ THROW_WALLET_EXCEPTION_IF(ciphertext.size() < sizeof(chacha8_iv),
+ error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
+
+ crypto::chacha8_key key;
+ crypto::generate_chacha8_key(&skey, sizeof(skey), key);
+ const crypto::chacha8_iv &iv = *(const crypto::chacha8_iv*)&ciphertext[0];
+ std::string plaintext;
+ plaintext.resize(ciphertext.size() - sizeof(iv) - (authenticated ? sizeof(crypto::signature) : 0));
+ if (authenticated)
+ {
+ crypto::hash hash;
+ crypto::cn_fast_hash(ciphertext.data(), ciphertext.size() - sizeof(signature), hash);
+ crypto::public_key pkey;
+ crypto::secret_key_to_public_key(skey, pkey);
+ const crypto::signature &signature = *(const crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)];
+ THROW_WALLET_EXCEPTION_IF(!crypto::check_signature(hash, pkey, signature),
+ error::wallet_internal_error, "Failed to authenticate criphertext");
+ }
+ crypto::chacha8(ciphertext.data() + sizeof(iv), ciphertext.size() - sizeof(iv), key, iv, &plaintext[0]);
+ return std::move(plaintext);
+}
+//----------------------------------------------------------------------------------------------------
+std::string wallet2::decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated) const
+{
+ return decrypt(ciphertext, get_account().get_keys().m_view_secret_key, authenticated);
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet)
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 2b69dc64a..3c4b1015f 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -495,6 +495,12 @@ namespace tools
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent);
void update_pool_state();
+
+ std::string encrypt(const std::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;
+ std::string 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;
+
private:
/*!
* \brief Stores wallet information to wallet file.
@@ -530,11 +536,13 @@ namespace tools
void check_genesis(const crypto::hash& genesis_hash) const; //throws
bool generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const;
crypto::hash get_payment_id(const pending_tx &ptx) const;
- void check_acc_out(const cryptonote::account_keys &acc, const cryptonote::tx_out &o, const crypto::public_key &tx_pub_key, size_t i, bool &received, uint64_t &money_transfered, bool &error) const;
+ void check_acc_out_precomp(const crypto::public_key &spend_public_key, const cryptonote::tx_out &o, const crypto::key_derivation &derivation, size_t i, bool &received, uint64_t &money_transfered, bool &error) const;
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
uint64_t get_upper_tranaction_size_limit();
std::vector<uint64_t> get_unspent_amounts_vector();
uint64_t get_fee_multiplier(uint32_t priority, bool use_new_fee) const;
+ uint64_t get_dynamic_per_kb_fee_estimate();
+ uint64_t get_per_kb_fee();
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
std::vector<size_t> pick_prefered_rct_inputs(uint64_t needed_money) const;
void set_spent(size_t idx, uint64_t height);
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 8427ba250..da1dbd6e1 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -65,6 +65,7 @@ struct PendingTransaction
virtual uint64_t amount() const = 0;
virtual uint64_t dust() const = 0;
virtual uint64_t fee() const = 0;
+ virtual std::vector<std::string> txid() const = 0;
};
/**
@@ -159,6 +160,12 @@ struct Wallet
Status_Error
};
+ enum ConnectionStatus {
+ ConnectionStatus_Disconnected,
+ ConnectionStatus_Connected,
+ ConnectionStatus_WrongVersion
+ };
+
virtual ~Wallet() = 0;
virtual std::string seed() const = 0;
virtual std::string getSeedLanguage() const = 0;
@@ -243,7 +250,7 @@ struct Wallet
* @brief connected - checks if the wallet connected to the daemon
* @return - true if connected
*/
- virtual bool connected() const = 0;
+ virtual ConnectionStatus connected() const = 0;
virtual void setTrustedDaemon(bool arg) = 0;
virtual bool trustedDaemon() const = 0;
virtual uint64_t balance() const = 0;
@@ -340,6 +347,21 @@ struct Wallet
* \param arg
*/
virtual void setDefaultMixin(uint32_t arg) = 0;
+
+ /*!
+ * \brief setUserNote - attach an arbitrary string note to a txid
+ * \param txid - the transaction id to attach the note to
+ * \param note - the note
+ * \return true if succesful, false otherwise
+ */
+ virtual bool setUserNote(const std::string &txid, const std::string &note) = 0;
+ /*!
+ * \brief getUserNote - return an arbitrary string note attached to a txid
+ * \param txid - the transaction id to attach the note to
+ * \return the attached note, or empty string if there is none
+ */
+ virtual std::string getUserNote(const std::string &txid) const = 0;
+ virtual std::string getTxKey(const std::string &txid) const = 0;
};
/**
@@ -400,6 +422,19 @@ struct WalletManager
*/
virtual std::vector<std::string> findWallets(const std::string &path) = 0;
+ /*!
+ * \brief checkPayment - checks a payment was made using a txkey
+ * \param address - the address the payment was sent to
+ * \param txid - the transaction id for that payment
+ * \param txkey - the transaction's secret key
+ * \param daemon_address - the address (host and port) to the daemon to request transaction data
+ * \param received - if succesful, will hold the amount of monero received
+ * \param height - if succesful, will hold the height of the transaction (0 if only in the pool)
+ * \param error - if unsuccesful, will hold an error string with more information about the error
+ * \return - true is succesful, false otherwise
+ */
+ virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
+
//! returns verbose error string regarding last error;
virtual std::string errorString() const = 0;