aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt24
-rw-r--r--src/crypto/CMakeLists.txt2
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h3
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h39
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp6
-rw-r--r--src/cryptonote_basic/miner.cpp14
-rw-r--r--src/cryptonote_basic/miner.h2
-rw-r--r--src/cryptonote_core/blockchain.cpp4
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp4
-rw-r--r--src/cryptonote_core/cryptonote_core.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp5
-rw-r--r--src/cryptonote_core/tx_pool.h3
-rw-r--r--src/daemon/command_parser_executor.cpp15
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp5
-rw-r--r--src/daemon/rpc_command_executor.cpp32
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/ringct/rctTypes.h7
-rw-r--r--src/rpc/core_rpc_server.cpp48
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h25
-rw-r--r--src/simplewallet/simplewallet.cpp238
-rw-r--r--src/wallet/CMakeLists.txt7
-rw-r--r--src/wallet/api/unsigned_transaction.cpp14
-rw-r--r--src/wallet/wallet2.cpp32
-rw-r--r--src/wallet/wallet2.h3
-rw-r--r--src/wallet/wallet_rpc_server.cpp420
-rw-r--r--src/wallet/wallet_rpc_server.h18
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h56
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h1
31 files changed, 686 insertions, 352 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7cf03db71..d83242a3c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -101,18 +101,24 @@ add_subdirectory(crypto)
add_subdirectory(ringct)
add_subdirectory(cryptonote_basic)
add_subdirectory(cryptonote_core)
-add_subdirectory(blockchain_db)
+if(NOT IOS)
+ add_subdirectory(blockchain_db)
+endif()
add_subdirectory(mnemonics)
-add_subdirectory(rpc)
+if(NOT IOS)
+ add_subdirectory(rpc)
+endif()
add_subdirectory(wallet)
-add_subdirectory(p2p)
+if(NOT IOS)
+ add_subdirectory(p2p)
+endif()
add_subdirectory(cryptonote_protocol)
-
-add_subdirectory(simplewallet)
-add_subdirectory(daemonizer)
-add_subdirectory(daemon)
-
-add_subdirectory(blockchain_utilities)
+if(NOT IOS)
+ add_subdirectory(simplewallet)
+ add_subdirectory(daemonizer)
+ add_subdirectory(daemon)
+ add_subdirectory(blockchain_utilities)
+endif()
if(PER_BLOCK_CHECKPOINT)
add_subdirectory(blocks)
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index c047b0042..277ee64c2 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -93,7 +93,7 @@ endif()
# Because of the way Qt works on android with JNI, the code does not live in the main android thread
# So this code runs with a 1 MB default stack size.
# This will force the use of the heap for the allocation of the scratchpad
-if (ANDROID)
+if (ANDROID OR IOS)
if( BUILD_GUI_DEPS )
add_definitions(-DFORCE_USE_HEAP=1)
endif()
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index dab0d9f26..c4adf1fcb 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -44,7 +44,6 @@
#include "serialization/debug_archive.h"
#include "serialization/crypto.h"
#include "serialization/keyvalue_serialization.h" // eepe named serialization
-#include "string_tools.h"
#include "cryptonote_config.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
@@ -208,7 +207,7 @@ namespace cryptonote
void invalidate_hashes();
bool is_hash_valid() const { return hash_valid.load(std::memory_order_acquire); }
void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
- bool is_blob_size_valid() const { return hash_valid.load(std::memory_order_acquire); }
+ bool is_blob_size_valid() const { return blob_size_valid.load(std::memory_order_acquire); }
void set_blob_size_valid(bool v) const { blob_size_valid.store(v,std::memory_order_release); }
BEGIN_SERIALIZE_OBJECT()
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index 4e1468510..14c03ac4c 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -33,6 +33,8 @@
#include "cryptonote_basic.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
+#include "hex.h"
+#include "span.h"
namespace cryptonote {
@@ -123,23 +125,28 @@ namespace cryptonote {
bool operator ==(const cryptonote::block& a, const cryptonote::block& b);
}
-template <class T>
-std::ostream &print256(std::ostream &o, const T &v) {
- return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
-}
-template <class T>
-std::ostream &print64(std::ostream &o, const T &v) {
- return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
-}
-
bool parse_hash256(const std::string str_hash, crypto::hash& hash);
namespace crypto {
- inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); }
- inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); }
- inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); }
- inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); }
- inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); }
- inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); }
- inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { return print64(o, v); }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index edea8862f..745dfb72e 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -658,8 +658,6 @@ namespace cryptonote
//---------------------------------------------------------------
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
{
- return calculate_transaction_hash(t, res, blob_size);
-#if 0
if (t.is_hash_valid())
{
#ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
@@ -690,7 +688,6 @@ namespace cryptonote
t.set_blob_size_valid(true);
}
return true;
-#endif
}
//---------------------------------------------------------------
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size)
@@ -736,8 +733,6 @@ namespace cryptonote
//---------------------------------------------------------------
bool get_block_hash(const block& b, crypto::hash& res)
{
- return calculate_block_hash(b, res);
-#if 0
if (b.is_hash_valid())
{
#ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
@@ -754,7 +749,6 @@ namespace cryptonote
b.hash = res;
b.set_hash_valid(true);
return true;
-#endif
}
//---------------------------------------------------------------
crypto::hash get_block_hash(const block& b)
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 4c84e7eee..eeb7b6094 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -122,13 +122,15 @@ namespace cryptonote
block bl = AUTO_VAL_INIT(bl);
difficulty_type di = AUTO_VAL_INIT(di);
uint64_t height = AUTO_VAL_INIT(height);
+ uint64_t expected_reward; //only used for RPC calls - could possibly be useful here too?
+
cryptonote::blobdata extra_nonce;
if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
{
extra_nonce = m_extra_messages[m_config.current_extra_message_index];
}
- if(!m_phandler->get_block_template(bl, m_mine_address, di, height, extra_nonce))
+ if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce))
{
LOG_ERROR("Failed to get_block_template(), stopping mining");
return false;
@@ -377,6 +379,7 @@ namespace cryptonote
void miner::pause()
{
CRITICAL_REGION_LOCAL(m_miners_count_lock);
+ MDEBUG("miner::pause: " << m_pausers_count << " -> " << (m_pausers_count + 1));
++m_pausers_count;
if(m_pausers_count == 1 && is_mining())
MDEBUG("MINING PAUSED");
@@ -385,6 +388,7 @@ namespace cryptonote
void miner::resume()
{
CRITICAL_REGION_LOCAL(m_miners_count_lock);
+ MDEBUG("miner::resume: " << m_pausers_count << " -> " << (m_pausers_count - 1));
--m_pausers_count;
if(m_pausers_count < 0)
{
@@ -812,9 +816,11 @@ namespace cryptonote
const std::string POWER_SUPPLY_STATUS_PATHS[] =
{
"/sys/class/power_supply/ACAD/online",
- "/sys/class/power_supply/AC/online"
+ "/sys/class/power_supply/AC/online",
+ "/sys/class/power_supply/AC0/online",
+ "/sys/class/power_supply/ADP0/online"
};
-
+
for(const std::string& path : POWER_SUPPLY_STATUS_PATHS)
{
if( epee::file_io_utils::is_file_exist(path) )
@@ -823,7 +829,7 @@ namespace cryptonote
break;
}
}
-
+
if( power_supply_path.empty() )
{
LOG_ERROR("Couldn't find battery/power status file, can't determine if plugged in!");
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
index 8ab4b2855..964ee6a36 100644
--- a/src/cryptonote_basic/miner.h
+++ b/src/cryptonote_basic/miner.h
@@ -51,7 +51,7 @@ namespace cryptonote
struct i_miner_handler
{
virtual bool handle_block_found(block& b) = 0;
- virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) = 0;
+ virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce) = 0;
protected:
~i_miner_handler(){};
};
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 0d5a8d46f..8fe7da6b4 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -1072,7 +1072,7 @@ uint64_t Blockchain::get_current_cumulative_blocksize_limit() const
// in a lot of places. That flag is not referenced in any of the code
// nor any of the makefiles, howeve. Need to look into whether or not it's
// necessary at all.
-bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce)
+bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
{
LOG_PRINT_L3("Blockchain::" << __func__);
size_t median_size;
@@ -1096,7 +1096,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
size_t txs_size;
uint64_t fee;
- if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee, m_hardfork->get_current_version()))
+ if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee, expected_reward, m_hardfork->get_current_version()))
{
return false;
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 9dacba363..46f7ac682 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -323,11 +323,12 @@ namespace cryptonote
* @param miner_address address new coins for the block will go to
* @param di return-by-reference tells the miner what the difficulty target is
* @param height return-by-reference tells the miner what height it's mining against
+ * @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees
* @param ex_nonce extra data to be added to the miner transaction's extra
*
* @return true if block template filled in successfully, else false
*/
- bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce);
+ bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce);
/**
* @brief checks if a block is known about with a given hash
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 4d4b9d4d2..9c122f511 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -827,9 +827,9 @@ namespace cryptonote
m_mempool.set_relayed(txs);
}
//-----------------------------------------------------------------------------------------------
- bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce)
+ bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
{
- return m_blockchain_storage.create_block_template(b, adr, diffic, height, ex_nonce);
+ return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce);
}
//-----------------------------------------------------------------------------------------------
bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 24b0f0614..e56c2dcf1 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -180,7 +180,7 @@ namespace cryptonote
*
* @note see Blockchain::create_block_template
*/
- virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce);
+ virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce);
/**
* @brief called when a transaction is relayed
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index da5e6636a..f78f673c7 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -258,7 +258,7 @@ namespace cryptonote
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)blob_size, receive_time), id);
- MINFO("Transaction " << id << " added to pool");
+ MINFO("Transaction added to pool: txid " << id << " bytes: " << blob_size << " fee/byte: " << (fee / (double)blob_size));
return true;
}
//---------------------------------------------------------------------------------
@@ -613,7 +613,7 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate
- bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint8_t version)
+ bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
{
// Warning: This function takes already_generated_
// coins as an argument and appears to do nothing
@@ -705,6 +705,7 @@ namespace cryptonote
LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase));
}
+ expected_reward = best_coinbase;
LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, size "
<< total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase)
<< " (including " << print_money(fee) << " in fees)");
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index d19f83b2e..f68bc0bb9 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -220,11 +220,12 @@ namespace cryptonote
* @param already_generated_coins the current total number of coins "minted"
* @param total_size return-by-reference the total size of the new block
* @param fee return-by-reference the total of fees from the included transactions
+ * @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees
* @param version hard fork version to use for consensus rules
*
* @return true
*/
- bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint8_t version);
+ bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t &expected_reward, uint8_t version);
/**
* @brief get a list of all transactions in the pool
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 4e6e83eb5..a7caeeffc 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -563,4 +563,19 @@ bool t_command_parser_executor::update(const std::vector<std::string>& args)
return m_executor.update(args.front());
}
+bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args)
+{
+ if (args.size() != 1) return false;
+
+ std::string txid;
+ crypto::hash hash;
+ if (!parse_hash256(args[0], hash))
+ {
+ std::cout << "failed to parse tx id" << std::endl;
+ return true;
+ }
+ txid = args[0];
+ return m_executor.relay_tx(txid);
+}
+
} // namespace daemonize
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index 0a5ca8dd9..a453553f1 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -132,6 +132,8 @@ public:
bool print_blockchain_dynamic_stats(const std::vector<std::string>& args);
bool update(const std::vector<std::string>& args);
+
+ bool relay_tx(const std::vector<std::string>& args);
};
} // namespace daemonize
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 0081e00dc..21f550a85 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -248,6 +248,11 @@ t_command_server::t_command_server(
, std::bind(&t_command_parser_executor::update, &m_parser, p::_1)
, "subcommands: check (check if an update is available), download (download it is there is), update (not implemented)"
);
+ m_command_lookup.set_handler(
+ "relay_tx"
+ , std::bind(&t_command_parser_executor::relay_tx, &m_parser, p::_1)
+ , "Relay a given transaction by its txid"
+ );
}
bool t_command_server::process_command_str(const std::string& cmd)
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index c5b17268d..31f432918 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -813,6 +813,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() {
<< tx_info.tx_json << std::endl
<< "blob_size: " << tx_info.blob_size << std::endl
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
+ << "fee/byte: " << cryptonote::print_money(tx_info.fee / (double)tx_info.blob_size) << std::endl
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
<< "relayed: " << [&](const cryptonote::tx_info &tx_info)->std::string { if (!tx_info.relayed) return "no"; return boost::lexical_cast<std::string>(tx_info.last_relayed_time) + " (" + get_human_time_ago(tx_info.last_relayed_time, now) + ")"; } (tx_info) << std::endl
<< "do_not_relay: " << (tx_info.do_not_relay ? 'T' : 'F') << std::endl
@@ -894,6 +895,7 @@ bool t_rpc_command_executor::print_transaction_pool_short() {
tools::msg_writer() << "id: " << tx_info.id_hash << std::endl
<< "blob_size: " << tx_info.blob_size << std::endl
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
+ << "fee/byte: " << cryptonote::print_money(tx_info.fee / (double)tx_info.blob_size) << std::endl
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
<< "relayed: " << [&](const cryptonote::tx_info &tx_info)->std::string { if (!tx_info.relayed) return "no"; return boost::lexical_cast<std::string>(tx_info.last_relayed_time) + " (" + get_human_time_ago(tx_info.last_relayed_time, now) + ")"; } (tx_info) << std::endl
<< "do_not_relay: " << (tx_info.do_not_relay ? 'T' : 'F') << std::endl
@@ -958,7 +960,7 @@ bool t_rpc_command_executor::print_transaction_pool_stats() {
size_t avg_bytes = n_transactions ? bytes / n_transactions : 0;
tools::msg_writer() << n_transactions << " tx(es), " << bytes << " bytes total (min " << min_bytes << ", max " << max_bytes << ", avg " << avg_bytes << ")" << std::endl
- << "fees " << cryptonote::print_money(fee) << " (avg " << cryptonote::print_money(n_transactions ? fee / n_transactions : 0) << " per tx)" << std::endl
+ << "fees " << cryptonote::print_money(fee) << " (avg " << cryptonote::print_money(n_transactions ? fee / n_transactions : 0) << " per tx" << ", " << cryptonote::print_money(bytes ? fee / bytes : 0) << " per byte )" << std::endl
<< n_not_relayed << " not relayed, " << n_failing << " failing, " << n_10m << " older than 10 minutes (oldest " << (oldest == 0 ? "-" : get_human_time_ago(oldest, now)) << ")" << std::endl;
return true;
@@ -1646,4 +1648,32 @@ bool t_rpc_command_executor::update(const std::string &command)
return true;
}
+bool t_rpc_command_executor::relay_tx(const std::string &txid)
+{
+ cryptonote::COMMAND_RPC_RELAY_TX::request req;
+ cryptonote::COMMAND_RPC_RELAY_TX::response res;
+ std::string fail_message = "Unsuccessful";
+ epee::json_rpc::error error_resp;
+
+ req.txids.push_back(txid);
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->json_rpc_request(req, res, "relay_tx", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_relay_tx(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, res.status);
+ return true;
+ }
+ }
+
+ return true;
+}
+
}// namespace daemonize
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index a015c83ea..3f551bd14 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -153,6 +153,8 @@ public:
bool print_blockchain_dynamic_stats(uint64_t nblocks);
bool update(const std::string &command);
+
+ bool relay_tx(const std::string &txid);
};
} // namespace daemonize
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 0c27745e1..c820fb297 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -47,6 +47,8 @@ extern "C" {
#include "crypto/generic-ops.h"
#include "crypto/crypto.h"
+#include "hex.h"
+#include "span.h"
#include "serialization/serialization.h"
#include "serialization/debug_archive.h"
#include "serialization/binary_archive.h"
@@ -443,8 +445,9 @@ namespace cryptonote {
static inline bool operator!=(const crypto::secret_key &k0, const rct::key &k1) { return memcmp(&k0, &k1, 32); }
}
-template<typename T> std::ostream &print256(std::ostream &o, const T &v);
-inline std::ostream &operator <<(std::ostream &o, const rct::key &v) { return print256(o, v); }
+inline std::ostream &operator <<(std::ostream &o, const rct::key &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+}
BLOB_SERIALIZER(rct::key);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index a800dbb35..76a69fbf6 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -883,7 +883,7 @@ namespace cryptonote
block b = AUTO_VAL_INIT(b);
cryptonote::blobdata blob_reserve;
blob_reserve.resize(req.reserve_size, 0);
- if(!m_core.get_block_template(b, acc, res.difficulty, res.height, blob_reserve))
+ if(!m_core.get_block_template(b, acc, res.difficulty, res.height, res.expected_reward, blob_reserve))
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
error_resp.message = "Internal error: failed to create block template";
@@ -1588,6 +1588,52 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_relay_tx(const COMMAND_RPC_RELAY_TX::request& req, COMMAND_RPC_RELAY_TX::response& res, epee::json_rpc::error& error_resp)
+ {
+ if(!check_core_busy())
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
+ error_resp.message = "Core is busy.";
+ return false;
+ }
+
+ bool failed = false;
+ for (const auto &str: req.txids)
+ {
+ cryptonote::blobdata txid_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(str, txid_data))
+ {
+ res.status = std::string("Invalid transaction id: ") + str;
+ failed = true;
+ }
+ crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+
+ cryptonote::transaction tx;
+ bool r = m_core.get_pool_transaction(txid, tx);
+ if (r)
+ {
+ cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
+ NOTIFY_NEW_TRANSACTIONS::request r;
+ r.txs.push_back(cryptonote::tx_to_blob(tx));
+ m_core.get_protocol()->relay_transactions(r, fake_context);
+ //TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
+ }
+ else
+ {
+ res.status = std::string("Transaction not found in pool: ") + str;
+ failed = true;
+ }
+ }
+
+ if (failed)
+ {
+ return false;
+ }
+
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_bind_port = {
"rpc-bind-port"
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index f8eff5f8c..0aa222c87 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -121,6 +121,7 @@ namespace cryptonote
MAP_JON_RPC_WE("get_coinbase_tx_sum", on_get_coinbase_tx_sum, COMMAND_RPC_GET_COINBASE_TX_SUM)
MAP_JON_RPC_WE("get_fee_estimate", on_get_per_kb_fee_estimate, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE)
MAP_JON_RPC_WE_IF("get_alternate_chains",on_get_alternate_chains, COMMAND_RPC_GET_ALTERNATE_CHAINS, !m_restricted)
+ MAP_JON_RPC_WE_IF("relay_tx", on_relay_tx, COMMAND_RPC_RELAY_TX, !m_restricted)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -174,6 +175,7 @@ namespace cryptonote
bool on_get_coinbase_tx_sum(const COMMAND_RPC_GET_COINBASE_TX_SUM::request& req, COMMAND_RPC_GET_COINBASE_TX_SUM::response& res, epee::json_rpc::error& error_resp);
bool on_get_per_kb_fee_estimate(const COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp);
bool on_get_alternate_chains(const COMMAND_RPC_GET_ALTERNATE_CHAINS::request& req, COMMAND_RPC_GET_ALTERNATE_CHAINS::response& res, epee::json_rpc::error& error_resp);
+ bool on_relay_tx(const COMMAND_RPC_RELAY_TX::request& req, COMMAND_RPC_RELAY_TX::response& res, epee::json_rpc::error& error_resp);
//-----------------------
private:
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 6f60093ac..9bdadf0d1 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -49,7 +49,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 1
-#define CORE_RPC_VERSION_MINOR 8
+#define CORE_RPC_VERSION_MINOR 10
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -692,6 +692,7 @@ namespace cryptonote
uint64_t difficulty;
uint64_t height;
uint64_t reserved_offset;
+ uint64_t expected_reward;
std::string prev_hash;
blobdata blocktemplate_blob;
blobdata blockhashing_blob;
@@ -701,6 +702,7 @@ namespace cryptonote
KV_SERIALIZE(difficulty)
KV_SERIALIZE(height)
KV_SERIALIZE(reserved_offset)
+ KV_SERIALIZE(expected_reward)
KV_SERIALIZE(prev_hash)
KV_SERIALIZE(blocktemplate_blob)
KV_SERIALIZE(blockhashing_blob)
@@ -1495,4 +1497,25 @@ namespace cryptonote
END_KV_SERIALIZE_MAP()
};
};
+
+ struct COMMAND_RPC_RELAY_TX
+ {
+ struct request
+ {
+ std::list<std::string> txids;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(txids)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index f5a469af4..e925e81b5 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -101,6 +101,7 @@ enum TransferType {
namespace
{
+ const auto allowed_priority_strings = {"default", "unimportant", "normal", "elevated", "priority"};
const auto arg_wallet_file = wallet_args::arg_wallet_file();
const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""};
@@ -559,12 +560,6 @@ bool simple_wallet::set_refresh_type(const std::vector<std::string> &args/* = st
bool simple_wallet::set_confirm_missing_payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
- if (m_wallet->watch_only())
- {
- fail_msg_writer() << tr("wallet is watch-only and cannot transfer");
- return true;
- }
-
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
@@ -685,7 +680,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, _1), tr("payments <PID_1> [<PID_2> ... <PID_N>] - Show payments for given payment ID[s]"));
m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), tr("Show blockchain height"));
m_cmd_binder.set_handler("transfer_original", boost::bind(&simple_wallet::transfer, this, _1), tr("Same as transfer, but using an older transaction building algorithm"));
- m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer_new, this, _1), tr("transfer [<mixin_count>] <address> <amount> [<payment_id>] - Transfer <amount> to <address>. <mixin_count> is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer_new, this, _1), tr("transfer [<priority>] [<mixin_count>] <address> <amount> [<payment_id>] - Transfer <amount> to <address>. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <mixin_count> is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_transfer", boost::bind(&simple_wallet::locked_transfer, this, _1), tr("locked_transfer [<mixin_count>] <addr> <amount> <lockblocks>(Number of blocks to lock the transaction for, max 1000000) [<payment_id>]"));
m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::sweep_unmixable, this, _1), tr("Send all unmixable outputs to yourself with mixin 0"));
m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1), tr("sweep_all [mixin] address [payment_id] - Send all unlocked balance to an address"));
@@ -744,6 +739,21 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
}
else
{
+
+#define CHECK_SIMPLE_VARIABLE(name, f, help) do \
+ if (args[0] == name) { \
+ if (args.size() <= 1) \
+ { \
+ fail_msg_writer() << "set " << #name << ": " << tr("needs an argument") << " (" << help << ")"; \
+ return true; \
+ } \
+ else \
+ { \
+ f(args); \
+ return true; \
+ } \
+ } while(0)
+
if (args[0] == "seed")
{
if (args.size() == 1)
@@ -757,176 +767,19 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
return true;
}
}
- else if (args[0] == "always-confirm-transfers")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set always-confirm-transfers: needs an argument (0 or 1)");
- return true;
- }
- else
- {
- set_always_confirm_transfers(args);
- return true;
- }
- }
- else if (args[0] == "print-ring-members")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set print-ring-members: needs an argument (0 or 1)");
- return true;
- }
- else
- {
- set_print_ring_members(args);
- return true;
- }
- }
- else if (args[0] == "store-tx-info")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set store-tx-info: needs an argument (0 or 1)");
- return true;
- }
- else
- {
- set_store_tx_info(args);
- return true;
- }
- }
- else if (args[0] == "default-mixin")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set default-mixin: needs an argument (integer >= 2)");
- return true;
- }
- else
- {
- set_default_mixin(args);
- return true;
- }
- }
- else if (args[0] == "auto-refresh")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set auto-refresh: needs an argument (0 or 1)");
- return true;
- }
- else
- {
- set_auto_refresh(args);
- return true;
- }
- }
- else if (args[0] == "refresh-type")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set refresh-type: needs an argument:") <<
- tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)");
- return true;
- }
- else
- {
- set_refresh_type(args);
- return true;
- }
- }
- else if (args[0] == "priority")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set priority: needs an argument: 0, 1, 2, 3, or 4");
- return true;
- }
- else
- {
- set_default_priority(args);
- return true;
- }
- }
- else if (args[0] == "confirm-missing-payment-id")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set confirm-missing-payment-id: needs an argument (0 or 1)");
- return true;
- }
- else
- {
- set_confirm_missing_payment_id(args);
- return true;
- }
- }
- else if (args[0] == "ask-password")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set ask-password: needs an argument (0 or 1)");
- return true;
- }
- else
- {
- set_ask_password(args);
- return true;
- }
- }
- else if (args[0] == "unit")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set unit: needs an argument (monero, millinero, micronero, nanop, piconero)");
- return true;
- }
- else
- {
- set_unit(args);
- return true;
- }
- }
- else if (args[0] == "min-outputs-count")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set min-outputs-count: needs an argument (unsigned integer)");
- return true;
- }
- else
- {
- set_min_output_count(args);
- return true;
- }
- }
- else if (args[0] == "min-outputs-value")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set min-outputs-value: needs an argument (unsigned integer)");
- return true;
- }
- else
- {
- set_min_output_value(args);
- return true;
- }
- }
- else if (args[0] == "merge-destinations")
- {
- if (args.size() <= 1)
- {
- fail_msg_writer() << tr("set merge-destinations: needs an argument (0 or 1)");
- return true;
- }
- else
- {
- set_merge_destinations(args);
- return true;
- }
- }
+ CHECK_SIMPLE_VARIABLE("always-confirm-transfers", set_always_confirm_transfers, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("print-ring-members", set_print_ring_members, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("store-tx-info", set_store_tx_info, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("default-mixin", set_default_mixin, tr("integer >= 2"));
+ CHECK_SIMPLE_VARIABLE("auto-refresh", set_auto_refresh, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)"));
+ CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4"));
+ CHECK_SIMPLE_VARIABLE("confirm-missing-payment-id", set_confirm_missing_payment_id, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("monero, millinero, micronero, nanop, piconero"));
+ CHECK_SIMPLE_VARIABLE("min-outputs-count", set_min_output_count, tr("unsigned integer"));
+ CHECK_SIMPLE_VARIABLE("min-outputs-value", set_min_output_value, tr("amount"));
+ CHECK_SIMPLE_VARIABLE("merge-destinations", set_merge_destinations, tr("0 or 1"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
return true;
@@ -2205,6 +2058,18 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
std::vector<std::string> local_args = args_;
+ int priority = 0;
+ if(local_args.size() > 0) {
+ auto priority_pos = std::find(
+ allowed_priority_strings.begin(),
+ allowed_priority_strings.end(),
+ local_args[0]);
+ if(priority_pos != allowed_priority_strings.end()) {
+ local_args.erase(local_args.begin());
+ priority = std::distance(allowed_priority_strings.begin(), priority_pos);
+ }
+ }
+
size_t fake_outs_count;
if(local_args.size() > 0) {
if(!epee::string_tools::get_xtype_from_string(fake_outs_count, local_args[0]))
@@ -2356,15 +2221,15 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
return true;
}
unlock_block = bc_height + locked_blocks;
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon);
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_trusted_daemon);
break;
case TransferNew:
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon);
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_trusted_daemon);
break;
default:
LOG_ERROR("Unknown transfer method, using original");
case TransferOriginal:
- ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon);
+ ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_trusted_daemon);
break;
}
@@ -2993,7 +2858,6 @@ bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::donate(const std::vector<std::string> &args_)
{
- if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
std::vector<std::string> local_args = args_;
if(local_args.empty() || local_args.size() > 3)
{
@@ -3041,6 +2905,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
size_t min_mixin = ~0;
std::unordered_map<std::string, uint64_t> dests;
const std::string wallet_address = m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+ int first_known_non_zero_change_index = -1;
for (size_t n = 0; n < get_num_txes(); ++n)
{
const tools::wallet2::tx_construction_data &cd = get_tx(n);
@@ -3075,10 +2940,15 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
fail_msg_writer() << tr("Claimed change is larger than payment to the change address");
return false;
}
- if (memcmp(&cd.change_dts.addr, &get_tx(0).change_dts.addr, sizeof(cd.change_dts.addr)))
+ if (cd.change_dts.amount > 0)
{
- fail_msg_writer() << tr("Change does to more than one address");
- return false;
+ if (first_known_non_zero_change_index == -1)
+ first_known_non_zero_change_index = n;
+ if (memcmp(&cd.change_dts.addr, &get_tx(first_known_non_zero_change_index).change_dts.addr, sizeof(cd.change_dts.addr)))
+ {
+ fail_msg_writer() << tr("Change goes to more than one address");
+ return false;
+ }
}
change += cd.change_dts.amount;
it->second -= cd.change_dts.amount;
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index aed021b9c..2e7610b64 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -132,8 +132,13 @@ if (BUILD_GUI_DEPS)
list(APPEND objlibs $<TARGET_OBJECTS:obj_${lib}>) # matches naming convention in src/CMakeLists.txt
endforeach()
add_library(wallet_merged STATIC ${objlibs})
+ if(IOS)
+ set(lib_folder lib-${ARCH})
+ else()
+ set(lib_folder lib)
+ endif()
install(TARGETS wallet_merged
- ARCHIVE DESTINATION lib)
+ ARCHIVE DESTINATION ${lib_folder})
install(FILES ${wallet_api_headers}
DESTINATION include/wallet)
diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp
index b412084b0..1d9ef5d7c 100644
--- a/src/wallet/api/unsigned_transaction.cpp
+++ b/src/wallet/api/unsigned_transaction.cpp
@@ -104,6 +104,7 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu
size_t min_mixin = ~0;
std::unordered_map<std::string, uint64_t> dests;
const std::string wallet_address = m_wallet.m_wallet->get_account().get_public_address_str(m_wallet.m_wallet->testnet());
+ int first_known_non_zero_change_index = -1;
for (size_t n = 0; n < get_num_txes(); ++n)
{
const tools::wallet2::tx_construction_data &cd = get_tx(n);
@@ -140,11 +141,16 @@ bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_nu
m_errorString = tr("Claimed change is larger than payment to the change address");
return false;
}
- if (memcmp(&cd.change_dts.addr, &get_tx(0).change_dts.addr, sizeof(cd.change_dts.addr)))
+ if (cd.change_dts.amount > 0)
{
- m_status = Status_Error;
- m_errorString = tr("Change does to more than one address");
- return false;
+ if (first_known_non_zero_change_index == -1)
+ first_known_non_zero_change_index = n;
+ if (memcmp(&cd.change_dts.addr, &get_tx(first_known_non_zero_change_index).change_dts.addr, sizeof(cd.change_dts.addr)))
+ {
+ m_status = Status_Error;
+ m_errorString = tr("Change goes to more than one address");
+ return false;
+ }
}
change += cd.change_dts.amount;
it->second -= cd.change_dts.amount;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index a31236d86..6ecafd645 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -105,7 +105,7 @@ namespace
struct options {
const command_line::arg_descriptor<std::string> daemon_address = {"daemon-address", tools::wallet2::tr("Use daemon instance at <host>:<port>"), ""};
const command_line::arg_descriptor<std::string> daemon_host = {"daemon-host", tools::wallet2::tr("Use daemon instance at host <arg> instead of localhost"), ""};
- const command_line::arg_descriptor<std::string> password = {"password", tools::wallet2::tr("Wallet password"), "", true};
+ const command_line::arg_descriptor<std::string> password = {"password", tools::wallet2::tr("Wallet password (escape/quote as needed)"), "", true};
const command_line::arg_descriptor<std::string> password_file = {"password-file", tools::wallet2::tr("Wallet password file"), "", true};
const command_line::arg_descriptor<int> daemon_port = {"daemon-port", tools::wallet2::tr("Use daemon instance at port <arg> instead of 18081"), 0};
const command_line::arg_descriptor<std::string> daemon_login = {"daemon-login", tools::wallet2::tr("Specify username[:password] for daemon RPC client"), "", true};
@@ -498,6 +498,12 @@ std::pair<std::unique_ptr<wallet2>, password_container> wallet2::make_new(const
return {make_basic(vm, opts), std::move(*pwd)};
}
+std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::variables_map& vm)
+{
+ const options opts{};
+ return make_basic(vm, opts);
+}
+
//----------------------------------------------------------------------------------------------------
bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_size_limit)
{
@@ -4102,6 +4108,14 @@ static size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs)
return size;
}
+static size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs)
+{
+ if (use_rct)
+ return estimate_rct_tx_size(n_inputs, mixin, n_outputs + 1);
+ else
+ return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES;
+}
+
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money) const
{
std::vector<size_t> picks;
@@ -4420,7 +4434,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
else
{
- while (!dsts.empty() && dsts[0].amount <= available_amount)
+ while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()) < TX_SIZE_TARGET(upper_transaction_size_limit))
{
// we can fully pay that destination
LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_testnet, dsts[0].addr) <<
@@ -4432,7 +4446,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
++original_output_index;
}
- if (available_amount > 0 && !dsts.empty()) {
+ if (available_amount > 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) {
// we can partially fill that destination
LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_testnet, dsts[0].addr) <<
" for " << print_money(available_amount) << "/" << print_money(dsts[0].amount));
@@ -4453,11 +4467,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
else
{
- size_t estimated_rct_tx_size;
- if (use_rct)
- estimated_rct_tx_size = estimate_rct_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1);
- else
- estimated_rct_tx_size = tx.selected_transfers.size() * (fake_outs_count+1) * APPROXIMATE_INPUT_BYTES;
+ const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size());
try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
}
@@ -4645,11 +4655,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
// here, check if we need to sent tx and start a new one
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
<< upper_transaction_size_limit);
- size_t estimated_rct_tx_size;
- if (use_rct)
- estimated_rct_tx_size = estimate_rct_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1);
- else
- estimated_rct_tx_size = tx.selected_transfers.size() * (fake_outs_count+1) * APPROXIMATE_INPUT_BYTES;
+ const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1);
bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
if (try_tx) {
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 6d7bca2a5..e228dac4f 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -126,6 +126,9 @@ namespace tools
//! Uses stdin and stdout. Returns a wallet2 and password for wallet with no file if no errors.
static std::pair<std::unique_ptr<wallet2>, password_container> make_new(const boost::program_options::variables_map& vm);
+ //! Just parses variables.
+ static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm);
+
wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(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), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
struct transfer_details
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index f96b1f51e..5a7325a06 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -45,6 +45,7 @@ using namespace epee;
#include "string_coding.h"
#include "string_tools.h"
#include "crypto/hash.h"
+#include "mnemonics/electrum-words.h"
#include "rpc/rpc_args.h"
#include "rpc/core_rpc_server_commands_defs.h"
@@ -56,6 +57,7 @@ namespace
const command_line::arg_descriptor<std::string, true> arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"};
const command_line::arg_descriptor<bool> arg_disable_rpc_login = {"disable-rpc-login", "Disable HTTP authentication for RPC connections served by this process"};
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", "Enable commands which rely on a trusted daemon", false};
+ const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"};
constexpr const char default_rpc_username[] = "monero";
}
@@ -68,8 +70,9 @@ namespace tools
}
//------------------------------------------------------------------------------------------------------------------------------
- wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w), rpc_login_filename(), m_stop(false), m_trusted_daemon(false)
- {}
+ wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_filename(), m_stop(false), m_trusted_daemon(false)
+ {
+ }
//------------------------------------------------------------------------------------------------------------------------------
wallet_rpc_server::~wallet_rpc_server()
{
@@ -81,12 +84,17 @@ namespace tools
catch (...) {}
}
//------------------------------------------------------------------------------------------------------------------------------
+ void wallet_rpc_server::set_wallet(wallet2 *cr)
+ {
+ m_wallet = cr;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::run()
{
m_stop = false;
m_net_server.add_idle_handler([this](){
try {
- m_wallet.refresh();
+ if (m_wallet) m_wallet->refresh();
} catch (const std::exception& ex) {
LOG_ERROR("Exception at while refreshing, what=" << ex.what());
}
@@ -105,24 +113,55 @@ namespace tools
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::run(1, true);
}
//------------------------------------------------------------------------------------------------------------------------------
- bool wallet_rpc_server::init(const boost::program_options::variables_map& vm)
+ void wallet_rpc_server::stop()
{
- auto rpc_config = cryptonote::rpc_args::process(vm);
+ if (m_wallet)
+ {
+ m_wallet->store();
+ delete m_wallet;
+ m_wallet = NULL;
+ }
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::init(const boost::program_options::variables_map *vm)
+ {
+ auto rpc_config = cryptonote::rpc_args::process(*vm);
if (!rpc_config)
return false;
+ m_vm = vm;
+ tools::wallet2 *walvars;
+ std::unique_ptr<tools::wallet2> tmpwal;
+
+ if (m_wallet)
+ walvars = m_wallet;
+ else
+ {
+ tmpwal = tools::wallet2::make_dummy(*m_vm);
+ walvars = tmpwal.get();
+ }
boost::optional<epee::net_utils::http::login> http_login{};
- std::string bind_port = command_line::get_arg(vm, arg_rpc_bind_port);
- const bool disable_auth = command_line::get_arg(vm, arg_disable_rpc_login);
- m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon);
- if (!command_line::has_arg(vm, arg_trusted_daemon))
+ std::string bind_port = command_line::get_arg(*m_vm, arg_rpc_bind_port);
+ const bool disable_auth = command_line::get_arg(*m_vm, arg_disable_rpc_login);
+ m_trusted_daemon = command_line::get_arg(*m_vm, arg_trusted_daemon);
+ if (!command_line::has_arg(*m_vm, arg_trusted_daemon))
{
- if (tools::is_local_address(m_wallet.get_daemon_address()))
+ if (tools::is_local_address(walvars->get_daemon_address()))
{
MINFO(tr("Daemon is local, assuming trusted"));
m_trusted_daemon = true;
}
}
+ if (command_line::has_arg(*m_vm, arg_wallet_dir))
+ {
+ m_wallet_dir = command_line::get_arg(*m_vm, arg_wallet_dir);
+#ifdef _WIN32
+#define MKDIR(path, mode) mkdir(path)
+#else
+#define MKDIR(path, mode) mkdir(path, mode)
+#endif
+ MKDIR(m_wallet_dir.c_str(), 0700);
+ }
if (disable_auth)
{
@@ -173,7 +212,7 @@ namespace tools
LOG_PRINT_L0(tr("RPC username/password is stored in file ") << temp);
} // end auth enabled
- m_http_client.set_server(m_wallet.get_daemon_address(), m_wallet.get_daemon_login());
+ m_http_client.set_server(walvars->get_daemon_address(), walvars->get_daemon_login());
m_net_server.set_threads_prefix("RPC");
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
@@ -181,6 +220,13 @@ namespace tools
);
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::not_open(epee::json_rpc::error& er)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NOT_OPEN;
+ er.message = "No wallet file";
+ return false;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd)
{
entry.txid = string_tools::pod_to_hex(pd.m_tx_hash);
@@ -191,7 +237,7 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
entry.fee = 0; // TODO
- entry.note = m_wallet.get_tx_note(pd.m_tx_hash);
+ entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "in";
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -206,13 +252,13 @@ namespace tools
entry.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
entry.amount = pd.m_amount_in - change - entry.fee;
- entry.note = m_wallet.get_tx_note(txid);
+ entry.note = m_wallet->get_tx_note(txid);
for (const auto &d: pd.m_dests) {
entry.destinations.push_back(wallet_rpc::transfer_destination());
wallet_rpc::transfer_destination &td = entry.destinations.back();
td.amount = d.amount;
- td.address = get_account_address_as_str(m_wallet.testnet(), d.addr);
+ td.address = get_account_address_as_str(m_wallet->testnet(), d.addr);
}
entry.type = "out";
@@ -230,7 +276,7 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.fee = pd.m_amount_in - pd.m_amount_out;
entry.amount = pd.m_amount_in - pd.m_change - entry.fee;
- entry.note = m_wallet.get_tx_note(txid);
+ entry.note = m_wallet->get_tx_note(txid);
entry.type = is_failed ? "failed" : "pending";
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -244,16 +290,17 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
entry.fee = 0; // TODO
- entry.note = m_wallet.get_tx_note(pd.m_tx_hash);
+ entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "pool";
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
try
{
- res.balance = m_wallet.balance();
- res.unlocked_balance = m_wallet.unlocked_balance();
+ res.balance = m_wallet->balance();
+ res.unlocked_balance = m_wallet->unlocked_balance();
}
catch (const std::exception& e)
{
@@ -266,9 +313,10 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getaddress(const wallet_rpc::COMMAND_RPC_GET_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
try
{
- res.address = m_wallet.get_account().get_public_address_str(m_wallet.testnet());
+ res.address = m_wallet->get_account().get_public_address_str(m_wallet->testnet());
}
catch (const std::exception& e)
{
@@ -281,9 +329,10 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
try
{
- res.height = m_wallet.get_blockchain_current_height();
+ res.height = m_wallet->get_blockchain_current_height();
}
catch (const std::exception& e)
{
@@ -303,7 +352,7 @@ namespace tools
cryptonote::tx_destination_entry de;
bool has_payment_id;
crypto::hash8 new_payment_id;
- if(!get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet.testnet(), it->address, false))
+ if(!get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), it->address, false))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + it->address;
@@ -374,7 +423,8 @@ namespace tools
std::vector<uint8_t> extra;
LOG_PRINT_L3("on_transfer_split starts");
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -390,11 +440,11 @@ namespace tools
try
{
uint64_t mixin = req.mixin;
- if (mixin < 2 && m_wallet.use_fork_rules(2, 10)) {
+ if (mixin < 2 && m_wallet->use_fork_rules(2, 10)) {
LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2");
mixin = 2;
}
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
// reject proposed transactions if there are more than one. see on_transfer_split below.
if (ptx_vector.size() != 1)
@@ -404,7 +454,7 @@ namespace tools
return false;
}
- m_wallet.commit_tx(ptx_vector);
+ m_wallet->commit_tx(ptx_vector);
// populate response with tx hash
res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx_vector.back().tx));
@@ -442,7 +492,8 @@ namespace tools
std::vector<cryptonote::tx_destination_entry> dsts;
std::vector<uint8_t> extra;
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -458,17 +509,17 @@ namespace tools
try
{
uint64_t mixin = req.mixin;
- if (mixin < 2 && m_wallet.use_fork_rules(2, 10)) {
+ if (mixin < 2 && m_wallet->use_fork_rules(2, 10)) {
LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2");
mixin = 2;
}
std::vector<wallet2::pending_tx> ptx_vector;
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
- ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
+ ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
LOG_PRINT_L2("on_transfer_split calling commit_txyy");
- m_wallet.commit_tx(ptx_vector);
+ m_wallet->commit_tx(ptx_vector);
LOG_PRINT_L2("on_transfer_split called commit_txyy");
// populate response with tx hashes
@@ -507,7 +558,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -516,9 +568,9 @@ namespace tools
try
{
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_unmixable_sweep_transactions(m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
- m_wallet.commit_tx(ptx_vector);
+ m_wallet->commit_tx(ptx_vector);
// populate response with tx hashes
for (auto & ptx : ptx_vector)
@@ -559,7 +611,8 @@ namespace tools
std::vector<cryptonote::tx_destination_entry> dsts;
std::vector<uint8_t> extra;
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -578,9 +631,9 @@ namespace tools
try
{
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
- m_wallet.commit_tx(ptx_vector);
+ m_wallet->commit_tx(ptx_vector);
// populate response with tx hashes
for (auto & ptx : ptx_vector)
@@ -618,6 +671,7 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_make_integrated_address(const wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
try
{
crypto::hash8 payment_id;
@@ -635,7 +689,7 @@ namespace tools
}
}
- res.integrated_address = m_wallet.get_account().get_public_integrated_address_str(payment_id, m_wallet.testnet());
+ res.integrated_address = m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet());
res.payment_id = epee::string_tools::pod_to_hex(payment_id);
return true;
}
@@ -650,13 +704,14 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_split_integrated_address(const wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
try
{
cryptonote::account_public_address address;
crypto::hash8 payment_id;
bool has_payment_id;
- if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet.testnet(), req.integrated_address))
+ if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet->testnet(), req.integrated_address))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "Invalid address";
@@ -668,7 +723,7 @@ namespace tools
er.message = "Address is not an integrated address";
return false;
}
- res.standard_address = get_account_address_as_str(m_wallet.testnet(),address);
+ res.standard_address = get_account_address_as_str(m_wallet->testnet(),address);
res.payment_id = epee::string_tools::pod_to_hex(payment_id);
return true;
}
@@ -683,7 +738,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -692,7 +748,7 @@ namespace tools
try
{
- m_wallet.store();
+ m_wallet->store();
}
catch (const std::exception& e)
{
@@ -705,6 +761,7 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
crypto::hash payment_id;
crypto::hash8 payment_id8;
cryptonote::blobdata payment_id_blob;
@@ -734,7 +791,7 @@ namespace tools
res.payments.clear();
std::list<wallet2::payment_details> payment_list;
- m_wallet.get_payments(payment_id, payment_list);
+ m_wallet->get_payments(payment_id, payment_list);
for (auto & payment : payment_list)
{
wallet_rpc::payment_details rpc_payment;
@@ -752,12 +809,13 @@ namespace tools
bool wallet_rpc_server::on_get_bulk_payments(const wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::response& res, epee::json_rpc::error& er)
{
res.payments.clear();
+ if (!m_wallet) return not_open(er);
/* If the payment ID list is empty, we get payments to any payment ID (or lack thereof) */
if (req.payment_ids.empty())
{
std::list<std::pair<crypto::hash,wallet2::payment_details>> payment_list;
- m_wallet.get_payments(payment_list, req.min_block_height);
+ m_wallet->get_payments(payment_list, req.min_block_height);
for (auto & payment : payment_list)
{
@@ -806,7 +864,7 @@ namespace tools
}
std::list<wallet2::payment_details> payment_list;
- m_wallet.get_payments(payment_id, payment_list, req.min_block_height);
+ m_wallet->get_payments(payment_id, payment_list, req.min_block_height);
for (auto & payment : payment_list)
{
@@ -825,6 +883,7 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_incoming_transfers(const wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
if(req.transfer_type.compare("all") != 0 && req.transfer_type.compare("available") != 0 && req.transfer_type.compare("unavailable") != 0)
{
er.code = WALLET_RPC_ERROR_CODE_TRANSFER_TYPE;
@@ -846,7 +905,7 @@ namespace tools
}
wallet2::transfer_container transfers;
- m_wallet.get_transfers(transfers);
+ m_wallet->get_transfers(transfers);
bool transfers_found = false;
for (const auto& td : transfers)
@@ -873,7 +932,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -882,7 +942,7 @@ namespace tools
if (req.key_type.compare("mnemonic") == 0)
{
- if (!m_wallet.get_seed(res.key))
+ if (!m_wallet->get_seed(res.key))
{
er.message = "The wallet is non-deterministic. Cannot display seed.";
return false;
@@ -890,7 +950,7 @@ namespace tools
}
else if(req.key_type.compare("view_key") == 0)
{
- res.key = string_tools::pod_to_hex(m_wallet.get_account().get_keys().m_view_secret_key);
+ res.key = string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key);
}
else
{
@@ -903,7 +963,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_rescan_blockchain(const wallet_rpc::COMMAND_RPC_RESCAN_BLOCKCHAIN::request& req, wallet_rpc::COMMAND_RPC_RESCAN_BLOCKCHAIN::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -912,7 +973,7 @@ namespace tools
try
{
- m_wallet.rescan_blockchain();
+ m_wallet->rescan_blockchain();
}
catch (const std::exception& e)
{
@@ -925,20 +986,22 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
- res.signature = m_wallet.sign(req.data);
+ res.signature = m_wallet->sign(req.data);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -948,20 +1011,21 @@ namespace tools
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 payment_id;
- if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet.testnet(), req.address, false))
+ if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), req.address, false))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "";
return false;
}
- res.good = m_wallet.verify(req.data, address, req.signature);
+ res.good = m_wallet->verify(req.data, address, req.signature);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_stop_wallet(const wallet_rpc::COMMAND_RPC_STOP_WALLET::request& req, wallet_rpc::COMMAND_RPC_STOP_WALLET::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -970,7 +1034,7 @@ namespace tools
try
{
- m_wallet.store();
+ m_wallet->store();
m_stop.store(true, std::memory_order_relaxed);
}
catch (const std::exception& e)
@@ -984,7 +1048,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_set_tx_notes(const wallet_rpc::COMMAND_RPC_SET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_SET_TX_NOTES::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -1018,7 +1083,7 @@ namespace tools
std::list<std::string>::const_iterator in = req.notes.begin();
while (il != txids.end())
{
- m_wallet.set_tx_note(*il++, *in++);
+ m_wallet->set_tx_note(*il++, *in++);
}
return true;
@@ -1027,6 +1092,7 @@ namespace tools
bool wallet_rpc_server::on_get_tx_notes(const wallet_rpc::COMMAND_RPC_GET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_GET_TX_NOTES::response& res, epee::json_rpc::error& er)
{
res.notes.clear();
+ if (!m_wallet) return not_open(er);
std::list<crypto::hash> txids;
std::list<std::string>::const_iterator i = req.txids.begin();
@@ -1047,14 +1113,15 @@ namespace tools
std::list<crypto::hash>::const_iterator il = txids.begin();
while (il != txids.end())
{
- res.notes.push_back(m_wallet.get_tx_note(*il++));
+ res.notes.push_back(m_wallet->get_tx_note(*il++));
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -1071,7 +1138,7 @@ namespace tools
if (req.in)
{
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
- m_wallet.get_payments(payments, min_height, max_height);
+ m_wallet->get_payments(payments, min_height, max_height);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
res.in.push_back(wallet_rpc::transfer_entry());
fill_transfer_entry(res.in.back(), i->second.m_tx_hash, i->first, i->second);
@@ -1081,7 +1148,7 @@ namespace tools
if (req.out)
{
std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments;
- m_wallet.get_payments_out(payments, min_height, max_height);
+ m_wallet->get_payments_out(payments, min_height, max_height);
for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
res.out.push_back(wallet_rpc::transfer_entry());
fill_transfer_entry(res.out.back(), i->first, i->second);
@@ -1090,7 +1157,7 @@ namespace tools
if (req.pending || req.failed) {
std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments;
- m_wallet.get_unconfirmed_payments_out(upayments);
+ m_wallet->get_unconfirmed_payments_out(upayments);
for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
const tools::wallet2::unconfirmed_transfer_details &pd = i->second;
bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed;
@@ -1104,10 +1171,10 @@ namespace tools
if (req.pool)
{
- m_wallet.update_pool_state();
+ m_wallet->update_pool_state();
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
- m_wallet.get_unconfirmed_payments(payments);
+ m_wallet->get_unconfirmed_payments(payments);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
res.pool.push_back(wallet_rpc::transfer_entry());
fill_transfer_entry(res.pool.back(), i->first, i->second);
@@ -1119,7 +1186,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_transfer_by_txid(const wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -1147,7 +1215,7 @@ namespace tools
}
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
- m_wallet.get_payments(payments, 0);
+ m_wallet->get_payments(payments, 0);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
if (i->second.m_tx_hash == txid)
{
@@ -1157,7 +1225,7 @@ namespace tools
}
std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments_out;
- m_wallet.get_payments_out(payments_out, 0);
+ m_wallet->get_payments_out(payments_out, 0);
for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) {
if (i->first == txid)
{
@@ -1167,7 +1235,7 @@ namespace tools
}
std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments;
- m_wallet.get_unconfirmed_payments_out(upayments);
+ m_wallet->get_unconfirmed_payments_out(upayments);
for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
if (i->first == txid)
{
@@ -1176,10 +1244,10 @@ namespace tools
}
}
- m_wallet.update_pool_state();
+ m_wallet->update_pool_state();
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> pool_payments;
- m_wallet.get_unconfirmed_payments(pool_payments);
+ m_wallet->get_unconfirmed_payments(pool_payments);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) {
if (i->second.m_tx_hash == txid)
{
@@ -1195,9 +1263,10 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
try
{
- std::vector<std::pair<crypto::key_image, crypto::signature>> ski = m_wallet.export_key_images();
+ std::vector<std::pair<crypto::key_image, crypto::signature>> ski = m_wallet->export_key_images();
res.signed_key_images.resize(ski.size());
for (size_t n = 0; n < ski.size(); ++n)
{
@@ -1218,7 +1287,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_import_key_images(const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -1250,7 +1320,7 @@ namespace tools
ski[n].second = *reinterpret_cast<const crypto::signature*>(bd.data());
}
uint64_t spent = 0, unspent = 0;
- uint64_t height = m_wallet.import_key_images(ski, spent, unspent);
+ uint64_t height = m_wallet->import_key_images(ski, spent, unspent);
res.spent = spent;
res.unspent = unspent;
res.height = height;
@@ -1269,7 +1339,7 @@ namespace tools
bool wallet_rpc_server::on_make_uri(const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response& res, epee::json_rpc::error& er)
{
std::string error;
- std::string uri = m_wallet.make_uri(req.address, req.payment_id, req.amount, req.tx_description, req.recipient_name, error);
+ std::string uri = m_wallet->make_uri(req.address, req.payment_id, req.amount, req.tx_description, req.recipient_name, error);
if (uri.empty())
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_URI;
@@ -1283,8 +1353,9 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_parse_uri(const wallet_rpc::COMMAND_RPC_PARSE_URI::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
std::string error;
- if (!m_wallet.parse_uri(req.uri, res.uri.address, res.uri.payment_id, res.uri.amount, res.uri.tx_description, res.uri.recipient_name, res.unknown_parameters, error))
+ if (!m_wallet->parse_uri(req.uri, res.uri.address, res.uri.payment_id, res.uri.amount, res.uri.tx_description, res.uri.recipient_name, res.unknown_parameters, error))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_URI;
er.message = "Error parsing URI: " + error;
@@ -1295,12 +1366,13 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_address_book(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er)
{
- const auto ab = m_wallet.get_address_book();
+ if (!m_wallet) return not_open(er);
+ const auto ab = m_wallet->get_address_book();
if (req.entries.empty())
{
uint64_t idx = 0;
for (const auto &entry: ab)
- res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx++, get_account_address_as_str(m_wallet.testnet(), entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description});
+ res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx++, get_account_address_as_str(m_wallet->testnet(), entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description});
}
else
{
@@ -1313,7 +1385,7 @@ namespace tools
return false;
}
const auto &entry = ab[idx];
- res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx, get_account_address_as_str(m_wallet.testnet(), entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description});
+ res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx, get_account_address_as_str(m_wallet->testnet(), entry.m_address), epee::string_tools::pod_to_hex(entry.m_payment_id), entry.m_description});
}
}
return true;
@@ -1321,7 +1393,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_add_address_book(const wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -1332,7 +1405,7 @@ namespace tools
bool has_payment_id;
crypto::hash8 payment_id8;
crypto::hash payment_id = cryptonote::null_hash;
- if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet.testnet(), req.address, false))
+ if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), req.address, false))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
@@ -1370,33 +1443,34 @@ namespace tools
}
}
}
- if (!m_wallet.add_address_book_row(address, payment_id, req.description))
+ if (!m_wallet->add_address_book_row(address, payment_id, req.description))
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "Failed to add address book entry";
return false;
}
- res.index = m_wallet.get_address_book().size();
+ res.index = m_wallet->get_address_book().size();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_delete_address_book(const wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_DELETE_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
- const auto ab = m_wallet.get_address_book();
+ const auto ab = m_wallet->get_address_book();
if (req.index >= ab.size())
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_INDEX;
er.message = "Index out of range: " + std::to_string(req.index);
return false;
}
- if (!m_wallet.delete_address_book_row(req.index))
+ if (!m_wallet->delete_address_book_row(req.index))
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "Failed to delete address book entry";
@@ -1407,7 +1481,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_rescan_spent(const wallet_rpc::COMMAND_RPC_RESCAN_SPENT::request& req, wallet_rpc::COMMAND_RPC_RESCAN_SPENT::response& res, epee::json_rpc::error& er)
{
- if (m_wallet.restricted())
+ if (!m_wallet) return not_open(er);
+ if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
@@ -1415,7 +1490,7 @@ namespace tools
}
try
{
- m_wallet.rescan_spent();
+ m_wallet->rescan_spent();
return true;
}
catch (const std::exception &e)
@@ -1429,6 +1504,7 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_start_mining(const wallet_rpc::COMMAND_RPC_START_MINING::request& req, wallet_rpc::COMMAND_RPC_START_MINING::response& res, epee::json_rpc::error& er)
{
+ if (!m_wallet) return not_open(er);
if (!m_trusted_daemon)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
@@ -1445,7 +1521,7 @@ namespace tools
}
cryptonote::COMMAND_RPC_START_MINING::request daemon_req = AUTO_VAL_INIT(daemon_req);
- daemon_req.miner_address = m_wallet.get_account().get_public_address_str(m_wallet.testnet());
+ daemon_req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->testnet());
daemon_req.threads_count = req.threads_count;
daemon_req.do_background_mining = req.do_background_mining;
daemon_req.ignore_battery = req.ignore_battery;
@@ -1475,6 +1551,152 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_get_languages(const wallet_rpc::COMMAND_RPC_GET_LANGUAGES::request& req, wallet_rpc::COMMAND_RPC_GET_LANGUAGES::response& res, epee::json_rpc::error& er)
+ {
+ crypto::ElectrumWords::get_language_list(res.languages);
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_create_wallet(const wallet_rpc::COMMAND_RPC_CREATE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CREATE_WALLET::response& res, epee::json_rpc::error& er)
+ {
+ if (m_wallet_dir.empty())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "No wallet dir configured";
+ return false;
+ }
+
+ namespace po = boost::program_options;
+ po::variables_map vm2;
+ const char *ptr = strchr(req.filename.c_str(), '/');
+#ifdef _WIN32
+ if (!ptr)
+ ptr = strchr(req.filename.c_str(), '\\');
+ if (!ptr)
+ ptr = strchr(req.filename.c_str(), ':');
+#endif
+ if (ptr)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Invalid filename";
+ return false;
+ }
+ std::string wallet_file = m_wallet_dir + "/" + req.filename;
+ {
+ std::vector<std::string> languages;
+ crypto::ElectrumWords::get_language_list(languages);
+ std::vector<std::string>::iterator it;
+ std::string wallet_file;
+ char *ptr;
+
+ it = std::find(languages.begin(), languages.end(), req.language);
+ if (it == languages.end())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Unknown language";
+ return false;
+ }
+ }
+ {
+ po::options_description desc("dummy");
+ const command_line::arg_descriptor<std::string, true> arg_password = {"password", "password"};
+ const char *argv[4];
+ int argc = 3;
+ argv[0] = "wallet-rpc";
+ argv[1] = "--password";
+ argv[2] = req.password.c_str();
+ argv[3] = NULL;
+ vm2 = *m_vm;
+ command_line::add_arg(desc, arg_password);
+ po::store(po::parse_command_line(argc, argv, desc), vm2);
+ }
+ std::unique_ptr<tools::wallet2> wal = tools::wallet2::make_new(vm2).first;
+ if (!wal)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to create wallet";
+ return false;
+ }
+ wal->set_seed_language(req.language);
+ cryptonote::COMMAND_RPC_GET_HEIGHT::request hreq;
+ cryptonote::COMMAND_RPC_GET_HEIGHT::response hres;
+ hres.height = 0;
+ bool r = net_utils::invoke_http_json("/getheight", hreq, hres, m_http_client);
+ wal->set_refresh_from_block_height(hres.height);
+ crypto::secret_key dummy_key;
+ try {
+ wal->generate(wallet_file, req.password, dummy_key, false, false);
+ }
+ catch (const std::exception& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to generate wallet";
+ return false;
+ }
+ if (m_wallet)
+ delete m_wallet;
+ m_wallet = wal.release();
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_open_wallet(const wallet_rpc::COMMAND_RPC_OPEN_WALLET::request& req, wallet_rpc::COMMAND_RPC_OPEN_WALLET::response& res, epee::json_rpc::error& er)
+ {
+ if (m_wallet_dir.empty())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "No wallet dir configured";
+ return false;
+ }
+
+ namespace po = boost::program_options;
+ po::variables_map vm2;
+ const char *ptr = strchr(req.filename.c_str(), '/');
+#ifdef _WIN32
+ if (!ptr)
+ ptr = strchr(req.filename.c_str(), '\\');
+ if (!ptr)
+ ptr = strchr(req.filename.c_str(), ':');
+#endif
+ if (ptr)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Invalid filename";
+ return false;
+ }
+ std::string wallet_file = m_wallet_dir + "/" + req.filename;
+ {
+ po::options_description desc("dummy");
+ const command_line::arg_descriptor<std::string, true> arg_password = {"password", "password"};
+ const char *argv[4];
+ int argc = 3;
+ argv[0] = "wallet-rpc";
+ argv[1] = "--password";
+ argv[2] = req.password.c_str();
+ argv[3] = NULL;
+ vm2 = *m_vm;
+ command_line::add_arg(desc, arg_password);
+ po::store(po::parse_command_line(argc, argv, desc), vm2);
+ }
+ std::unique_ptr<tools::wallet2> wal;
+ try {
+ wal = tools::wallet2::make_from_file(vm2, wallet_file).first;
+ }
+ catch (const std::exception& e)
+ {
+ wal = nullptr;
+ }
+ if (!wal)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to open wallet";
+ return false;
+ }
+ if (m_wallet)
+ delete m_wallet;
+ m_wallet = wal.release();
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
}
int main(int argc, char** argv) {
@@ -1491,11 +1713,12 @@ int main(int argc, char** argv) {
cryptonote::rpc_args::init_options(desc_params);
command_line::add_arg(desc_params, arg_wallet_file);
command_line::add_arg(desc_params, arg_from_json);
+ command_line::add_arg(desc_params, arg_wallet_dir);
const auto vm = wallet_args::main(
argc, argv,
- "monero-wallet-rpc [--wallet-file=<file>|--generate-from-json=<file>] [--rpc-bind-port=<port>]",
+ "monero-wallet-rpc [--wallet-file=<file>|--generate-from-json=<file>|--wallet-dir=<directory>] [--rpc-bind-port=<port>]",
desc_params,
po::positional_options_description(),
"monero-wallet-rpc.log",
@@ -1511,6 +1734,7 @@ int main(int argc, char** argv) {
{
const auto wallet_file = command_line::get_arg(*vm, arg_wallet_file);
const auto from_json = command_line::get_arg(*vm, arg_from_json);
+ const auto wallet_dir = command_line::get_arg(*vm, arg_wallet_dir);
if(!wallet_file.empty() && !from_json.empty())
{
@@ -1518,9 +1742,15 @@ int main(int argc, char** argv) {
return 1;
}
+ if (!wallet_dir.empty())
+ {
+ wal = NULL;
+ goto just_dir;
+ }
+
if (wallet_file.empty() && from_json.empty())
{
- LOG_ERROR(tools::wallet_rpc_server::tr("Must specify --wallet-file or --generate-from-json"));
+ LOG_ERROR(tools::wallet_rpc_server::tr("Must specify --wallet-file or --generate-from-json or --wallet-dir"));
return 1;
}
@@ -1561,8 +1791,10 @@ int main(int argc, char** argv) {
LOG_ERROR(tools::wallet_rpc_server::tr("Wallet initialization failed: ") << e.what());
return 1;
}
- tools::wallet_rpc_server wrpc(*wal);
- bool r = wrpc.init(*vm);
+just_dir:
+ tools::wallet_rpc_server wrpc;
+ if (wal) wrpc.set_wallet(wal.release());
+ bool r = wrpc.init(&(vm.get()));
CHECK_AND_ASSERT_MES(r, 1, tools::wallet_rpc_server::tr("Failed to initialize wallet rpc server"));
tools::signal_handler::install([&wrpc, &wal](int) {
wrpc.send_stop_signal();
@@ -1573,7 +1805,7 @@ int main(int argc, char** argv) {
try
{
LOG_PRINT_L0(tools::wallet_rpc_server::tr("Storing wallet..."));
- wal->store();
+ wrpc.stop();
LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stored ok"));
}
catch (const std::exception& e)
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index eafe3fc87..230dcee5b 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -52,11 +52,14 @@ namespace tools
static const char* tr(const char* str);
- wallet_rpc_server(wallet2& cr);
+ wallet_rpc_server();
~wallet_rpc_server();
- bool init(const boost::program_options::variables_map& vm);
+ bool init(const boost::program_options::variables_map *vm);
bool run();
+ void stop();
+ void set_wallet(wallet2 *cr);
+
private:
CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map
@@ -95,6 +98,9 @@ namespace tools
MAP_JON_RPC_WE("rescan_spent", on_rescan_spent, wallet_rpc::COMMAND_RPC_RESCAN_SPENT)
MAP_JON_RPC_WE("start_mining", on_start_mining, wallet_rpc::COMMAND_RPC_START_MINING)
MAP_JON_RPC_WE("stop_mining", on_stop_mining, wallet_rpc::COMMAND_RPC_STOP_MINING)
+ MAP_JON_RPC_WE("get_languages", on_get_languages, wallet_rpc::COMMAND_RPC_GET_LANGUAGES)
+ MAP_JON_RPC_WE("create_wallet", on_create_wallet, wallet_rpc::COMMAND_RPC_CREATE_WALLET)
+ MAP_JON_RPC_WE("open_wallet", on_open_wallet, wallet_rpc::COMMAND_RPC_OPEN_WALLET)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -131,6 +137,9 @@ namespace tools
bool on_rescan_spent(const wallet_rpc::COMMAND_RPC_RESCAN_SPENT::request& req, wallet_rpc::COMMAND_RPC_RESCAN_SPENT::response& res, epee::json_rpc::error& er);
bool on_start_mining(const wallet_rpc::COMMAND_RPC_START_MINING::request& req, wallet_rpc::COMMAND_RPC_START_MINING::response& res, epee::json_rpc::error& er);
bool on_stop_mining(const wallet_rpc::COMMAND_RPC_STOP_MINING::request& req, wallet_rpc::COMMAND_RPC_STOP_MINING::response& res, epee::json_rpc::error& er);
+ bool on_get_languages(const wallet_rpc::COMMAND_RPC_GET_LANGUAGES::request& req, wallet_rpc::COMMAND_RPC_GET_LANGUAGES::response& res, epee::json_rpc::error& er);
+ bool on_create_wallet(const wallet_rpc::COMMAND_RPC_CREATE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CREATE_WALLET::response& res, epee::json_rpc::error& er);
+ bool on_open_wallet(const wallet_rpc::COMMAND_RPC_OPEN_WALLET::request& req, wallet_rpc::COMMAND_RPC_OPEN_WALLET::response& res, epee::json_rpc::error& er);
//json rpc v2
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er);
@@ -140,11 +149,14 @@ namespace tools
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd);
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd);
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd);
+ bool not_open(epee::json_rpc::error& er);
- wallet2& m_wallet;
+ wallet2 *m_wallet;
+ std::string m_wallet_dir;
std::string rpc_login_filename;
std::atomic<bool> m_stop;
bool m_trusted_daemon;
epee::net_utils::http::http_simple_client m_http_client;
+ const boost::program_options::variables_map *m_vm;
};
}
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 49d1c59fb..51fcf02b5 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -909,5 +909,61 @@ namespace wallet_rpc
};
};
+ struct COMMAND_RPC_GET_LANGUAGES
+ {
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ struct response
+ {
+ std::vector<std::string> languages;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(languages)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_CREATE_WALLET
+ {
+ struct request
+ {
+ std::string filename;
+ std::string password;
+ std::string language;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(filename)
+ KV_SERIALIZE(password)
+ KV_SERIALIZE(language)
+ END_KV_SERIALIZE_MAP()
+ };
+ struct response
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_OPEN_WALLET
+ {
+ struct request
+ {
+ std::string filename;
+ std::string password;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(filename)
+ KV_SERIALIZE(password)
+ END_KV_SERIALIZE_MAP()
+ };
+ struct response
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ };
}
}
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 6f1c3bbbd..3c79c0ac3 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -43,3 +43,4 @@
#define WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE -10
#define WALLET_RPC_ERROR_CODE_WRONG_URI -11
#define WALLET_RPC_ERROR_CODE_WRONG_INDEX -12
+#define WALLET_RPC_ERROR_CODE_NOT_OPEN -13