aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blockchain_db/blockchain_db.h14
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp52
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h3
-rw-r--r--src/blockchain_db/testdb.h3
-rw-r--r--src/blockchain_utilities/blockchain_prune.cpp18
-rw-r--r--src/blockchain_utilities/blockchain_stats.cpp2
-rw-r--r--src/common/perf_timer.cpp6
-rw-r--r--src/common/util.cpp8
-rw-r--r--src/common/util.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp5
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h1
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp57
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h4
-rw-r--r--src/cryptonote_basic/miner.cpp31
-rw-r--r--src/cryptonote_basic/miner.h1
-rw-r--r--src/cryptonote_config.h4
-rw-r--r--src/cryptonote_core/blockchain.cpp31
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp29
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl26
-rw-r--r--src/daemon/rpc_command_executor.cpp11
-rw-r--r--src/device/device_io_hid.cpp21
-rw-r--r--src/device/device_io_hid.hpp3
-rw-r--r--src/device/device_ledger.cpp7
-rw-r--r--src/device_trezor/device_trezor.cpp2
-rw-r--r--src/lmdb/database.cpp4
-rw-r--r--src/lmdb/value_stream.cpp4
-rw-r--r--src/lmdb/value_stream.h2
-rw-r--r--src/rpc/core_rpc_server.cpp179
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h8
-rw-r--r--src/simplewallet/simplewallet.cpp193
-rw-r--r--src/simplewallet/simplewallet.h11
-rw-r--r--src/wallet/CMakeLists.txt1
-rw-r--r--src/wallet/wallet2.cpp252
-rw-r--r--src/wallet/wallet2.h32
-rw-r--r--src/wallet/wallet_rpc_server.cpp155
-rw-r--r--src/wallet/wallet_rpc_server.h2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h12
40 files changed, 844 insertions, 359 deletions
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index d2fe39fc2..2c40b5a78 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1514,6 +1514,20 @@ public:
virtual bool check_pruning() = 0;
/**
+ * @brief get the max block size
+ */
+ virtual uint64_t get_max_block_size() = 0;
+
+ /**
+ * @brief add a new max block size
+ *
+ * The max block size will be the maximum of sz and the current block size
+ *
+ * @param: sz the block size
+ */
+
+ virtual void add_max_block_size(uint64_t sz) = 0;
+ /**
* @brief runs a function over all txpool transactions
*
* The subclass should run the passed function for each txpool tx it has
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 9f71fd068..a07e9ac55 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -2513,6 +2513,58 @@ std::vector<uint64_t> BlockchainLMDB::get_block_info_64bit_fields(uint64_t start
return ret;
}
+uint64_t BlockchainLMDB::get_max_block_size()
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(properties)
+ MDB_val_str(k, "max_block_size");
+ MDB_val v;
+ int result = mdb_cursor_get(m_cur_properties, &k, &v, MDB_SET);
+ if (result == MDB_NOTFOUND)
+ return std::numeric_limits<uint64_t>::max();
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to retrieve max block size: ", result).c_str()));
+ if (v.mv_size != sizeof(uint64_t))
+ throw0(DB_ERROR("Failed to retrieve or create max block size: unexpected value size"));
+ uint64_t max_block_size;
+ memcpy(&max_block_size, v.mv_data, sizeof(max_block_size));
+ TXN_POSTFIX_RDONLY();
+ return max_block_size;
+}
+
+void BlockchainLMDB::add_max_block_size(uint64_t sz)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
+
+ CURSOR(properties)
+
+ MDB_val_str(k, "max_block_size");
+ MDB_val v;
+ int result = mdb_cursor_get(m_cur_properties, &k, &v, MDB_SET);
+ if (result && result != MDB_NOTFOUND)
+ throw0(DB_ERROR(lmdb_error("Failed to retrieve max block size: ", result).c_str()));
+ uint64_t max_block_size = 0;
+ if (result == 0)
+ {
+ if (v.mv_size != sizeof(uint64_t))
+ throw0(DB_ERROR("Failed to retrieve or create max block size: unexpected value size"));
+ memcpy(&max_block_size, v.mv_data, sizeof(max_block_size));
+ }
+ if (sz > max_block_size)
+ max_block_size = sz;
+ v.mv_data = (void*)&max_block_size;
+ v.mv_size = sizeof(max_block_size);
+ result = mdb_cursor_put(m_cur_properties, &k, &v, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to set max_block_size: ", result).c_str()));
+}
+
+
std::vector<uint64_t> BlockchainLMDB::get_block_weights(uint64_t start_height, size_t count) const
{
return get_block_info_64bit_fields(start_height, count, offsetof(mdb_block_info, bi_weight));
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 2f89b77ac..f6b00817d 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -400,6 +400,9 @@ private:
std::vector<uint64_t> get_block_info_64bit_fields(uint64_t start_height, size_t count, off_t offset) const;
+ uint64_t get_max_block_size();
+ void add_max_block_size(uint64_t sz);
+
// fix up anything that may be wrong due to past bugs
virtual void fixup();
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 7916364c5..04fad26a4 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -149,6 +149,9 @@ public:
virtual bool update_pruning() { return true; }
virtual bool check_pruning() { return true; }
virtual void prune_outputs(uint64_t amount) {}
+
+ virtual uint64_t get_max_block_size() { return 100000000; }
+ virtual void add_max_block_size(uint64_t sz) { }
};
}
diff --git a/src/blockchain_utilities/blockchain_prune.cpp b/src/blockchain_utilities/blockchain_prune.cpp
index 36080aade..8e13f2c04 100644
--- a/src/blockchain_utilities/blockchain_prune.cpp
+++ b/src/blockchain_utilities/blockchain_prune.cpp
@@ -611,24 +611,6 @@ int main(int argc, char* argv[])
}
already_pruned = true;
}
- if (n == 0)
- {
- const uint64_t blockchain_height = core_storage[0]->get_current_blockchain_height();
- const crypto::hash hash = core_storage[0]->get_block_id_by_height(blockchain_height - 1);
- cryptonote::block block;
- if (core_storage[0]->get_block_by_hash(hash, block))
- {
- if (block.major_version < 10)
- {
- time_t now = time(NULL);
- if (now < 1555286400) // 15 april 2019
- {
- MERROR("Pruning before v10 will confuse peers. Wait for v10 first");
- return 1;
- }
- }
- }
- }
}
core_storage[0]->deinit();
core_storage[0].reset(NULL);
diff --git a/src/blockchain_utilities/blockchain_stats.cpp b/src/blockchain_utilities/blockchain_stats.cpp
index 4cc84bf4a..33c26277e 100644
--- a/src/blockchain_utilities/blockchain_stats.cpp
+++ b/src/blockchain_utilities/blockchain_stats.cpp
@@ -205,7 +205,7 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
char buf[8];
unsigned int i;
for (i=0; i<24; i++) {
- sprintf(buf, "\t%02d:00", i);
+ sprintf(buf, "\t%02u:00", i);
std::cout << buf;
}
}
diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp
index dda498088..189eb85eb 100644
--- a/src/common/perf_timer.cpp
+++ b/src/common/perf_timer.cpp
@@ -88,7 +88,7 @@ namespace tools
namespace tools
{
-el::Level performance_timer_log_level = el::Level::Debug;
+el::Level performance_timer_log_level = el::Level::Info;
static __thread std::vector<LoggingPerformanceTimer*> *performance_timers = NULL;
@@ -97,8 +97,8 @@ void set_performance_timer_log_level(el::Level level)
if (level != el::Level::Debug && level != el::Level::Trace && level != el::Level::Info
&& level != el::Level::Warning && level != el::Level::Error && level != el::Level::Fatal)
{
- MERROR("Wrong log level: " << el::LevelHelper::convertToString(level) << ", using Debug");
- level = el::Level::Debug;
+ MERROR("Wrong log level: " << el::LevelHelper::convertToString(level) << ", using Info");
+ level = el::Level::Info;
}
performance_timer_log_level = level;
}
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 728efc294..3388974ce 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -641,16 +641,16 @@ std::string get_nix_version_display_string()
return res;
}
- std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name)
+ std::error_code replace_file(const std::string& old_name, const std::string& new_name)
{
int code;
#if defined(WIN32)
// Maximizing chances for success
std::wstring wide_replacement_name;
- try { wide_replacement_name = string_tools::utf8_to_utf16(replacement_name); }
+ try { wide_replacement_name = string_tools::utf8_to_utf16(old_name); }
catch (...) { return std::error_code(GetLastError(), std::system_category()); }
std::wstring wide_replaced_name;
- try { wide_replaced_name = string_tools::utf8_to_utf16(replaced_name); }
+ try { wide_replaced_name = string_tools::utf8_to_utf16(new_name); }
catch (...) { return std::error_code(GetLastError(), std::system_category()); }
DWORD attributes = ::GetFileAttributesW(wide_replaced_name.c_str());
@@ -662,7 +662,7 @@ std::string get_nix_version_display_string()
bool ok = 0 != ::MoveFileExW(wide_replacement_name.c_str(), wide_replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
code = ok ? 0 : static_cast<int>(::GetLastError());
#else
- bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
+ bool ok = 0 == std::rename(old_name.c_str(), new_name.c_str());
code = ok ? 0 : errno;
#endif
return std::error_code(code, std::system_category());
diff --git a/src/common/util.h b/src/common/util.h
index 77a5a9af6..f6d5c9b1f 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -145,7 +145,7 @@ namespace tools
bool create_directories_if_necessary(const std::string& path);
/*! \brief std::rename wrapper for nix and something strange for windows.
*/
- std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name);
+ std::error_code replace_file(const std::string& old_name, const std::string& new_name);
bool sanitize_locale();
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 03caafbb0..20d92bdf1 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -422,6 +422,8 @@ namespace cryptonote
FIELDS(*static_cast<block_header *>(this))
FIELD(miner_tx)
FIELD(tx_hashes)
+ if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
+ return false;
END_SERIALIZE()
};
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp
index e336cc1d1..d8de65b81 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.cpp
+++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp
@@ -76,11 +76,6 @@ namespace cryptonote {
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
}
//-----------------------------------------------------------------------------------------------
- size_t get_max_block_size()
- {
- return CRYPTONOTE_MAX_BLOCK_SIZE;
- }
- //-----------------------------------------------------------------------------------------------
size_t get_max_tx_size()
{
return CRYPTONOTE_MAX_TX_SIZE;
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index 036273f0e..c7198a16f 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -87,7 +87,6 @@ namespace cryptonote {
/* Cryptonote helper functions */
/************************************************************************/
size_t get_min_block_weight(uint8_t version);
- size_t get_max_block_size();
size_t get_max_tx_size();
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version);
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 094057b1f..566622c1a 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -1065,8 +1065,6 @@ namespace cryptonote
// prefix
get_transaction_prefix_hash(t, hashes[0]);
- transaction &tt = const_cast<transaction&>(t);
-
const blobdata blob = tx_to_blob(t);
const unsigned int unprunable_size = t.unprunable_size;
const unsigned int prefix_size = t.prefix_size;
@@ -1090,7 +1088,14 @@ namespace cryptonote
// we still need the size
if (blob_size)
- *blob_size = get_object_blobsize(t);
+ {
+ if (!t.is_blob_size_valid())
+ {
+ t.blob_size = blob.size();
+ t.set_blob_size_valid(true);
+ }
+ *blob_size = t.blob_size;
+ }
return true;
}
@@ -1143,21 +1148,37 @@ namespace cryptonote
return blob;
}
//---------------------------------------------------------------
- bool calculate_block_hash(const block& b, crypto::hash& res)
+ bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob)
{
+ blobdata bd;
+ if (!blob)
+ {
+ bd = block_to_blob(b);
+ blob = &bd;
+ }
+
+ bool hash_result = get_object_hash(get_block_hashing_blob(b), res);
+ if (!hash_result)
+ return false;
+
+ if (b.miner_tx.vin.size() == 1 && b.miner_tx.vin[0].type() == typeid(cryptonote::txin_gen))
+ {
+ const cryptonote::txin_gen &txin_gen = boost::get<cryptonote::txin_gen>(b.miner_tx.vin[0]);
+ if (txin_gen.height != 202612)
+ return true;
+ }
+
// EXCEPTION FOR BLOCK 202612
const std::string correct_blob_hash_202612 = "3a8a2b3a29b50fc86ff73dd087ea43c6f0d6b8f936c849194d5c84c737903966";
const std::string existing_block_id_202612 = "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698";
- crypto::hash block_blob_hash = get_blob_hash(block_to_blob(b));
+ crypto::hash block_blob_hash = get_blob_hash(*blob);
if (string_tools::pod_to_hex(block_blob_hash) == correct_blob_hash_202612)
{
string_tools::hex_to_pod(existing_block_id_202612, res);
return true;
}
- bool hash_result = get_object_hash(get_block_hashing_blob(b), res);
- if (hash_result)
{
// make sure that we aren't looking at a block with the 202612 block id but not the correct blobdata
if (string_tools::pod_to_hex(res) == existing_block_id_202612)
@@ -1200,9 +1221,9 @@ namespace cryptonote
bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height)
{
// block 202612 bug workaround
- const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000";
if (height == 202612)
{
+ static const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000";
string_tools::hex_to_pod(longhash_202612, res);
return true;
}
@@ -1239,7 +1260,7 @@ namespace cryptonote
return p;
}
//---------------------------------------------------------------
- bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
+ bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash)
{
std::stringstream ss;
ss << b_blob;
@@ -1248,9 +1269,26 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
b.invalidate_hashes();
b.miner_tx.invalidate_hashes();
+ if (block_hash)
+ {
+ calculate_block_hash(b, *block_hash, &b_blob);
+ ++block_hashes_calculated_count;
+ b.hash = *block_hash;
+ b.set_hash_valid(true);
+ }
return true;
}
//---------------------------------------------------------------
+ bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
+ {
+ return parse_and_validate_block_from_blob(b_blob, b, NULL);
+ }
+ //---------------------------------------------------------------
+ bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash)
+ {
+ return parse_and_validate_block_from_blob(b_blob, b, &block_hash);
+ }
+ //---------------------------------------------------------------
blobdata block_to_blob(const block& b)
{
return t_serializable_object_to_blob(b);
@@ -1286,6 +1324,7 @@ namespace cryptonote
crypto::hash get_tx_tree_hash(const block& b)
{
std::vector<crypto::hash> txs_ids;
+ txs_ids.reserve(1 + b.tx_hashes.size());
crypto::hash h = null_hash;
size_t bl_sz = 0;
get_transaction_hash(b.miner_tx, h, bl_sz);
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 40a9907be..3f8eef076 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -114,12 +114,14 @@ namespace cryptonote
crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash);
blobdata get_block_hashing_blob(const block& b);
- bool calculate_block_hash(const block& b, crypto::hash& res);
+ bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob = NULL);
bool get_block_hash(const block& b, crypto::hash& res);
crypto::hash get_block_hash(const block& b);
bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height);
crypto::hash get_block_longhash(const block& b, uint64_t height);
+ bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash);
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
+ bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash);
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
uint64_t get_outs_money_amount(const transaction& tx);
bool check_inputs_types_supported(const transaction& tx);
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 4e2edc20f..ded6e346f 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -106,6 +106,7 @@ namespace cryptonote
m_thread_index(0),
m_phandler(phandler),
m_height(0),
+ m_threads_active(0),
m_pausers_count(0),
m_threads_total(0),
m_starter_nonce(0),
@@ -264,8 +265,8 @@ namespace cryptonote
{
CRITICAL_REGION_LOCAL(m_threads_lock);
boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
- for(boost::thread& th: m_threads)
- th.join();
+ while (m_threads_active > 0)
+ misc_utils::sleep_no_w(100);
m_threads.clear();
}
boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
@@ -447,15 +448,17 @@ namespace cryptonote
// In case background mining was active and the miner threads are waiting
// on the background miner to signal start.
- m_is_background_mining_started_cond.notify_all();
-
- for(boost::thread& th: m_threads)
- th.join();
+ while (m_threads_active > 0)
+ {
+ m_is_background_mining_started_cond.notify_all();
+ misc_utils::sleep_no_w(100);
+ }
// The background mining thread could be sleeping for a long time, so we
// interrupt it just in case
m_background_mining_thread.interrupt();
m_background_mining_thread.join();
+ m_is_background_mining_enabled = false;
MINFO("Mining has been stopped, " << m_threads.size() << " finished" );
m_threads.clear();
@@ -589,6 +592,7 @@ namespace cryptonote
}
slow_hash_free_state();
MGINFO("Miner thread stopped ["<< th_local_index << "]");
+ --m_threads_active;
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -747,10 +751,10 @@ namespace cryptonote
uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff);
uint8_t process_percentage = get_percent_of_total(process_diff, total_diff);
- MGINFO("idle percentage is " << unsigned(idle_percentage) << "\%, miner percentage is " << unsigned(process_percentage) << "\%, ac power : " << on_ac_power);
+ MDEBUG("idle percentage is " << unsigned(idle_percentage) << "\%, miner percentage is " << unsigned(process_percentage) << "\%, ac power : " << on_ac_power);
if( idle_percentage + process_percentage < get_idle_threshold() || !on_ac_power )
{
- MGINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining stopping, thanks for your contribution!");
+ MINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining stopping, thanks for your contribution!");
m_is_background_mining_started = false;
// reset process times
@@ -788,10 +792,10 @@ namespace cryptonote
uint64_t idle_diff = (current_idle_time - prev_idle_time);
uint8_t idle_percentage = get_percent_of_total(idle_diff, total_diff);
- MGINFO("idle percentage is " << unsigned(idle_percentage));
+ MDEBUG("idle percentage is " << unsigned(idle_percentage));
if( idle_percentage >= get_idle_threshold() && on_ac_power )
{
- MGINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining started, good luck!");
+ MINFO("cpu is " << unsigned(idle_percentage) << "% idle, idle threshold is " << unsigned(get_idle_threshold()) << "\%, ac power : " << on_ac_power << ", background mining started, good luck!");
m_is_background_mining_started = true;
m_is_background_mining_started_cond.notify_all();
@@ -1049,7 +1053,12 @@ namespace cryptonote
if (boost::logic::indeterminate(on_battery))
{
- LOG_ERROR("couldn't query power status from " << power_supply_class_path);
+ static bool error_shown = false;
+ if (!error_shown)
+ {
+ LOG_ERROR("couldn't query power status from " << power_supply_class_path);
+ error_shown = true;
+ }
}
return on_battery;
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
index 08b1bd7f1..bbb576fff 100644
--- a/src/cryptonote_basic/miner.h
+++ b/src/cryptonote_basic/miner.h
@@ -125,6 +125,7 @@ namespace cryptonote
uint64_t m_height;
volatile uint32_t m_thread_index;
volatile uint32_t m_threads_total;
+ std::atomic<uint32_t> m_threads_active;
std::atomic<int32_t> m_pausers_count;
epee::critical_section m_miners_count_lock;
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index b6087de22..56b6a63b7 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -37,9 +37,9 @@
#define CRYPTONOTE_DNS_TIMEOUT_MS 20000
#define CRYPTONOTE_MAX_BLOCK_NUMBER 500000000
-#define CRYPTONOTE_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used!
#define CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE 196608 //size of block (bytes) that is the maximum that miners will produce
-#define CRYPTONOTE_MAX_TX_SIZE 1000000000
+#define CRYPTONOTE_MAX_TX_SIZE 1000000
+#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
#define CURRENT_TRANSACTION_VERSION 2
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 83d3044f8..8ab249ac1 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -1372,6 +1372,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
m_btc.timestamp = time(NULL); // update timestamp unconditionally
b = m_btc;
diffic = m_btc_difficulty;
+ height = m_btc_height;
expected_reward = m_btc_expected_reward;
return true;
}
@@ -1516,7 +1517,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
", cumulative weight " << cumulative_weight << " is now good");
#endif
- cache_block_template(b, miner_address, ex_nonce, diffic, expected_reward, pool_cookie);
+ cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, pool_cookie);
return true;
}
LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
@@ -3176,6 +3177,7 @@ bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const
if (version >= HF_VERSION_DYNAMIC_FEE)
{
median = m_current_block_cumul_weight_limit / 2;
+ const uint64_t blockchain_height = m_db->height();
already_generated_coins = blockchain_height ? m_db->get_block_already_generated_coins(blockchain_height - 1) : 0;
if (!get_block_reward(median, 1, already_generated_coins, base_reward, version))
return false;
@@ -3688,6 +3690,8 @@ leave:
//TODO: why is this done? make sure that keeping invalid blocks makes sense.
add_block_as_invalid(bl, id);
MERROR_VER("Block with id " << id << " added as invalid because of wrong inputs in transactions");
+ MERROR_VER("tx_index " << tx_index << ", m_blocks_txs_check " << m_blocks_txs_check.size() << ":");
+ for (const auto &h: m_blocks_txs_check) MERROR_VER(" " << h);
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
goto leave;
@@ -3817,12 +3821,6 @@ leave:
//------------------------------------------------------------------
bool Blockchain::prune_blockchain(uint32_t pruning_seed)
{
- uint8_t hf_version = m_hardfork->get_current_version();
- if (hf_version < 10)
- {
- MERROR("Most of the network will only be ready for pruned blockchains from v10, not pruning");
- return false;
- }
return m_db->prune_blockchain(pruning_seed);
}
//------------------------------------------------------------------
@@ -3872,6 +3870,8 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
LOG_PRINT_L3("Blockchain::" << __func__);
+ m_db->block_txn_start(false);
+
// when we reach this, the last hf version is not yet written to the db
const uint64_t db_height = m_db->height();
const uint8_t hf_version = get_current_hard_fork_version();
@@ -3934,6 +3934,10 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
if (long_term_effective_median_block_weight)
*long_term_effective_median_block_weight = m_long_term_effective_median_block_weight;
+ m_db->add_max_block_size(m_current_block_cumul_weight_limit);
+
+ m_db->block_txn_stop();
+
return true;
}
//------------------------------------------------------------------
@@ -4332,8 +4336,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
for (unsigned int j = 0; j < batches; j++, ++blockidx)
{
block &block = blocks[blockidx];
+ crypto::hash block_hash;
- if (!parse_and_validate_block_from_blob(it->block, block))
+ if (!parse_and_validate_block_from_blob(it->block, block, block_hash))
return false;
// check first block and skip all blocks if its not chained properly
@@ -4346,7 +4351,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
return true;
}
}
- if (have_block(get_block_hash(block)))
+ if (have_block(block_hash))
blocks_exist = true;
std::advance(it, 1);
@@ -4356,11 +4361,12 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
for (unsigned i = 0; i < extra && !blocks_exist; i++, blockidx++)
{
block &block = blocks[blockidx];
+ crypto::hash block_hash;
- if (!parse_and_validate_block_from_blob(it->block, block))
+ if (!parse_and_validate_block_from_blob(it->block, block, block_hash))
return false;
- if (have_block(get_block_hash(block)))
+ if (have_block(block_hash))
blocks_exist = true;
std::advance(it, 1);
@@ -4888,13 +4894,14 @@ void Blockchain::invalidate_block_template_cache()
m_btc_valid = false;
}
-void Blockchain::cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t expected_reward, uint64_t pool_cookie)
+void Blockchain::cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t pool_cookie)
{
MDEBUG("Setting block template cache");
m_btc = b;
m_btc_address = address;
m_btc_nonce = nonce;
m_btc_difficulty = diff;
+ m_btc_height = height;
m_btc_expected_reward = expected_reward;
m_btc_pool_cookie = pool_cookie;
m_btc_valid = true;
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 2cd4dc31b..c1677ed37 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -1094,6 +1094,7 @@ namespace cryptonote
account_public_address m_btc_address;
blobdata m_btc_nonce;
difficulty_type m_btc_difficulty;
+ uint64_t m_btc_height;
uint64_t m_btc_pool_cookie;
uint64_t m_btc_expected_reward;
bool m_btc_valid;
@@ -1464,6 +1465,6 @@ namespace cryptonote
*
* At some point, may be used to push an update to miners
*/
- void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t expected_reward, uint64_t pool_cookie);
+ void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t pool_cookie);
};
} // namespace cryptonote
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index da413bbe2..6b0052dc0 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -62,6 +62,9 @@ DISABLE_VS_WARNINGS(4355)
#define BAD_SEMANTICS_TXES_MAX_SIZE 100
+// basically at least how many bytes the block itself serializes to without the miner tx
+#define BLOCK_SIZE_SANITY_LEEWAY 100
+
namespace cryptonote
{
const command_line::arg_descriptor<bool, false> arg_testnet_on = {
@@ -1417,22 +1420,26 @@ namespace cryptonote
{
TRY_ENTRY();
- // load json & DNS checkpoints every 10min/hour respectively,
- // and verify them with respect to what blocks we already have
- CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
-
bvc = boost::value_initialized<block_verification_context>();
- if(block_blob.size() > get_max_block_size())
+
+ if (!check_incoming_block_size(block_blob))
{
- LOG_PRINT_L1("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected");
bvc.m_verifivation_failed = true;
return false;
}
+ if (((size_t)-1) <= 0xffffffff && block_blob.size() >= 0x3fffffff)
+ MWARNING("This block's size is " << block_blob.size() << ", closing on the 32 bit limit");
+
+ // load json & DNS checkpoints every 10min/hour respectively,
+ // and verify them with respect to what blocks we already have
+ CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
+
block lb;
if (!b)
{
- if(!parse_and_validate_block_from_blob(block_blob, lb))
+ crypto::hash block_hash;
+ if(!parse_and_validate_block_from_blob(block_blob, lb, block_hash))
{
LOG_PRINT_L1("Failed to parse and validate new block");
bvc.m_verifivation_failed = true;
@@ -1452,9 +1459,13 @@ namespace cryptonote
// block_blob
bool core::check_incoming_block_size(const blobdata& block_blob) const
{
- if(block_blob.size() > get_max_block_size())
+ // note: we assume block weight is always >= block blob size, so we check incoming
+ // blob size against the block weight limit, which acts as a sanity check without
+ // having to parse/weigh first; in fact, since the block blob is the block header
+ // plus the tx hashes, the weight will typically be much larger than the blob size
+ if(block_blob.size() > m_blockchain_storage.get_current_cumulative_block_weight_limit() + BLOCK_SIZE_SANITY_LEEWAY)
{
- LOG_PRINT_L1("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected");
+ LOG_PRINT_L1("WRONG BLOCK BLOB, sanity check failed on size " << block_blob.size() << ", rejected");
return false;
}
return true;
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 32f0afceb..b7a50783a 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -48,6 +48,17 @@
#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
#define MLOG_P2P_MESSAGE(x) MCINFO("net.p2p.msg", context << x)
+#define MLOGIF_P2P_MESSAGE(init, test, x) \
+ do { \
+ const auto level = el::Level::Info; \
+ const char *cat = "net.p2p.msg"; \
+ if (ELPP->vRegistry()->allowed(level, cat)) { \
+ init; \
+ if (test) \
+ el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << x; \
+ } \
+ } while(0)
+
#define MLOG_PEER_STATE(x) \
MCINFO(MONERO_DEFAULT_LOG_CATEGORY, context << "[" << epee::string_tools::to_string_hex(context.m_pruning_seed) << "] state: " << x << " in state " << cryptonote::get_protocol_state_string(context.m_state))
@@ -418,7 +429,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (" << arg.b.txs.size() << " txes)");
+ MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
@@ -488,7 +499,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
+ MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
@@ -858,6 +869,9 @@ namespace cryptonote
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
+ for (const auto &blob: arg.txs)
+ MLOGIF_P2P_MESSAGE(cryptonote::transaction tx; crypto::hash hash; bool ret = cryptonote::parse_and_validate_tx_from_blob(blob, tx, hash);, ret, "Including transaction " << hash);
+
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
@@ -995,7 +1009,8 @@ namespace cryptonote
return 1;
}
- if(!parse_and_validate_block_from_blob(block_entry.block, b))
+ crypto::hash block_hash;
+ if(!parse_and_validate_block_from_blob(block_entry.block, b, block_hash))
{
LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
@@ -1014,7 +1029,6 @@ namespace cryptonote
if (start_height == std::numeric_limits<uint64_t>::max())
start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
- const crypto::hash block_hash = get_block_hash(b);
auto req_it = context.m_requested_objects.find(block_hash);
if(req_it == context.m_requested_objects.end())
{
@@ -1121,13 +1135,13 @@ namespace cryptonote
<< ", we need " << previous_height);
block new_block;
- if (!parse_and_validate_block_from_blob(blocks.back().block, new_block))
+ crypto::hash last_block_hash;
+ if (!parse_and_validate_block_from_blob(blocks.back().block, new_block, last_block_hash))
{
MERROR(context << "Failed to parse block, but it should already have been parsed");
m_block_queue.remove_spans(span_connection_id, start_height);
continue;
}
- const crypto::hash last_block_hash = cryptonote::get_block_hash(new_block);
if (m_core.have_block(last_block_hash))
{
const uint64_t subchain_height = start_height + blocks.size();
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index c9ec5109e..5901be662 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -551,11 +551,12 @@ bool t_rpc_command_executor::mining_status() {
tools::msg_writer() << " Ignore battery: " << (mres.bg_ignore_battery ? "yes" : "no");
}
- if (!mining_busy && mres.active)
+ if (!mining_busy && mres.active && mres.speed > 0 && mres.block_target > 0 && mres.difficulty > 0)
{
- uint64_t daily = 86400ull / mres.block_target * mres.block_reward;
- uint64_t monthly = 86400ull / mres.block_target * 30.5 * mres.block_reward;
- uint64_t yearly = 86400ull / mres.block_target * 356 * mres.block_reward;
+ double ratio = mres.speed * mres.block_target / mres.difficulty;
+ uint64_t daily = 86400ull / mres.block_target * mres.block_reward * ratio;
+ uint64_t monthly = 86400ull / mres.block_target * 30.5 * mres.block_reward * ratio;
+ uint64_t yearly = 86400ull / mres.block_target * 356 * mres.block_reward * ratio;
tools::msg_writer() << "Expected: " << cryptonote::print_money(daily) << " monero daily, "
<< cryptonote::print_money(monthly) << " monero monthly, " << cryptonote::print_money(yearly) << " yearly";
}
@@ -2235,7 +2236,7 @@ bool t_rpc_command_executor::check_blockchain_pruning()
if (res.pruning_seed)
{
- tools::success_msg_writer() << "Blockchain pruning checked";
+ tools::success_msg_writer() << "Blockchain is pruned";
}
else
{
diff --git a/src/device/device_io_hid.cpp b/src/device/device_io_hid.cpp
index f07e0eaae..721bed9ca 100644
--- a/src/device/device_io_hid.cpp
+++ b/src/device/device_io_hid.cpp
@@ -85,7 +85,18 @@ namespace hw {
void device_io_hid::connect(void *params) {
hid_conn_params *p = (struct hid_conn_params*)params;
- this->connect(p->vid, p->pid, p->interface_number, p->usage_page);
+ if (!this->connect(p->vid, p->pid, p->interface_number, p->usage_page)) {
+ ASSERT_X(false, "No device found");
+ }
+ }
+
+ void device_io_hid::connect(const std::vector<hid_conn_params> &hcpV) {
+ for (auto p: hcpV) {
+ if (this->connect(p.vid, p.pid, p.interface_number, p.usage_page)) {
+ return;
+ }
+ }
+ ASSERT_X(false, "No device found");
}
hid_device_info *device_io_hid::find_device(hid_device_info *devices_list, boost::optional<int> interface_number, boost::optional<unsigned short> usage_page) {
@@ -124,14 +135,17 @@ namespace hw {
return result;
}
- void device_io_hid::connect(unsigned int vid, unsigned int pid, boost::optional<int> interface_number, boost::optional<unsigned short> usage_page) {
+ hid_device *device_io_hid::connect(unsigned int vid, unsigned int pid, boost::optional<int> interface_number, boost::optional<unsigned short> usage_page) {
hid_device_info *hwdev_info_list;
hid_device *hwdev;
this->disconnect();
hwdev_info_list = hid_enumerate(vid, pid);
- ASSERT_X(hwdev_info_list, "Unable to enumerate device "+std::to_string(vid)+":"+std::to_string(vid)+ ": "+ safe_hid_error(this->usb_device));
+ if (!hwdev_info_list) {
+ MDEBUG("Unable to enumerate device "+std::to_string(vid)+":"+std::to_string(vid)+ ": "+ safe_hid_error(this->usb_device));
+ return NULL;
+ }
hwdev = NULL;
if (hid_device_info *device = find_device(hwdev_info_list, interface_number, usage_page)) {
hwdev = hid_open_path(device->path);
@@ -141,6 +155,7 @@ namespace hw {
this->usb_vid = vid;
this->usb_pid = pid;
this->usb_device = hwdev;
+ return hwdev;
}
diff --git a/src/device/device_io_hid.hpp b/src/device/device_io_hid.hpp
index ed22058d6..96cb8d993 100644
--- a/src/device/device_io_hid.hpp
+++ b/src/device/device_io_hid.hpp
@@ -98,7 +98,8 @@ namespace hw {
void init();
void connect(void *params);
- void connect(unsigned int vid, unsigned int pid, boost::optional<int> interface_number, boost::optional<unsigned short> usage_page);
+ void connect(const std::vector<hid_conn_params> &conn);
+ hid_device *connect(unsigned int vid, unsigned int pid, boost::optional<int> interface_number, boost::optional<unsigned short> usage_page);
bool connected() const;
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len, bool user_input);
void disconnect();
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index d6033e189..200370564 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -389,10 +389,15 @@ namespace hw {
MDEBUG( "Device "<<this->id <<" HIDUSB inited");
return true;
}
+
+ static const std::vector<hw::io::hid_conn_params> known_devices {
+ {0x2c97, 0x0001, 0, 0xffa0},
+ {0x2c97, 0x0004, 0, 0xffa0},
+ };
bool device_ledger::connect(void) {
this->disconnect();
- hw_device.connect(0x2c97, 0x0001, 0, 0xffa0);
+ hw_device.connect(known_devices);
this->reset();
#ifdef DEBUG_HWDEVICE
cryptonote::account_public_address pubkey;
diff --git a/src/device_trezor/device_trezor.cpp b/src/device_trezor/device_trezor.cpp
index b4a80cf2c..b1022dd9c 100644
--- a/src/device_trezor/device_trezor.cpp
+++ b/src/device_trezor/device_trezor.cpp
@@ -137,7 +137,7 @@ namespace trezor {
}
auto current_time = std::chrono::steady_clock::now();
- if (current_time - m_last_live_refresh_time <= std::chrono::seconds(20))
+ if (current_time - m_last_live_refresh_time <= std::chrono::minutes(5))
{
continue;
}
diff --git a/src/lmdb/database.cpp b/src/lmdb/database.cpp
index c6b244671..ccab1902a 100644
--- a/src/lmdb/database.cpp
+++ b/src/lmdb/database.cpp
@@ -46,7 +46,7 @@ namespace lmdb
{
namespace
{
- constexpr const std::size_t max_resize = 1 * 1024 * 1024 * 1024; // 1 GB
+ constexpr const mdb_size_t max_resize = 1 * 1024 * 1024 * 1024; // 1 GB
void acquire_context(context& ctx) noexcept
{
while (ctx.lock.test_and_set());
@@ -136,7 +136,7 @@ namespace lmdb
MDB_envinfo info{};
MONERO_LMDB_CHECK(mdb_env_info(handle(), &info));
- const std::size_t resize = std::min(info.me_mapsize, max_resize);
+ const mdb_size_t resize = std::min(info.me_mapsize, max_resize);
const int err = mdb_env_set_mapsize(handle(), info.me_mapsize + resize);
ctx.lock.clear();
if (err)
diff --git a/src/lmdb/value_stream.cpp b/src/lmdb/value_stream.cpp
index 1024deb06..604140e47 100644
--- a/src/lmdb/value_stream.cpp
+++ b/src/lmdb/value_stream.cpp
@@ -36,9 +36,9 @@ namespace lmdb
{
namespace stream
{
- std::size_t count(MDB_cursor* cur)
+ mdb_size_t count(MDB_cursor* cur)
{
- std::size_t out = 0;
+ mdb_size_t out = 0;
if (cur)
{
const int rc = mdb_cursor_count(cur, &out);
diff --git a/src/lmdb/value_stream.h b/src/lmdb/value_stream.h
index c9977221f..01090aa67 100644
--- a/src/lmdb/value_stream.h
+++ b/src/lmdb/value_stream.h
@@ -43,7 +43,7 @@ namespace lmdb
\throw std::system_error if unexpected LMDB error.
\return 0 if `cur == nullptr`, otherwise count of values at current key.
*/
- std::size_t count(MDB_cursor* cur);
+ mdb_size_t count(MDB_cursor* cur);
/*!
Calls `mdb_cursor_get` and does some error checking.
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index f5f1a2f9a..b540520c7 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -91,7 +91,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_rpc_ssl);
command_line::add_arg(desc, arg_rpc_ssl_private_key);
command_line::add_arg(desc, arg_rpc_ssl_certificate);
- command_line::add_arg(desc, arg_rpc_ssl_allowed_certificates);
+ command_line::add_arg(desc, arg_rpc_ssl_ca_certificates);
command_line::add_arg(desc, arg_rpc_ssl_allowed_fingerprints);
command_line::add_arg(desc, arg_rpc_ssl_allow_any_cert);
command_line::add_arg(desc, arg_bootstrap_daemon_address);
@@ -149,36 +149,38 @@ namespace cryptonote
if (rpc_config->login)
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
- epee::net_utils::ssl_support_t ssl_support;
- const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl);
- if (!epee::net_utils::ssl_support_from_string(ssl_support, ssl))
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect;
+ if (command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert))
+ ssl_options.verification = epee::net_utils::ssl_verification_t::none;
+ else
{
- MFATAL("Invalid RPC SSL support: " << ssl);
- return false;
+ std::string ssl_ca_path = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
+ const std::vector<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
+ std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() };
+ std::transform(ssl_allowed_fingerprint_strings.begin(), ssl_allowed_fingerprint_strings.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
+
+ if (!ssl_ca_path.empty() || !ssl_allowed_fingerprints.empty())
+ ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(ssl_ca_path)};
}
- const std::string ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
- const std::string ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
- const std::vector<std::string> ssl_allowed_certificate_paths = command_line::get_arg(vm, arg_rpc_ssl_allowed_certificates);
- std::list<std::string> ssl_allowed_certificates;
- for (const std::string &path: ssl_allowed_certificate_paths)
+
+ ssl_options.auth = epee::net_utils::ssl_authentication_t{
+ command_line::get_arg(vm, arg_rpc_ssl_private_key), command_line::get_arg(vm, arg_rpc_ssl_certificate)
+ };
+
+ // user specified CA file or fingeprints implies enabled SSL by default
+ if (ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
{
- ssl_allowed_certificates.push_back({});
- if (!epee::file_io_utils::load_file_to_string(path, ssl_allowed_certificates.back()))
+ const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl);
+ if (!epee::net_utils::ssl_support_from_string(ssl_options.support, ssl))
{
- MERROR("Failed to load certificate: " << path);
- ssl_allowed_certificates.back() = std::string();
+ MFATAL("Invalid RPC SSL support: " << ssl);
+ return false;
}
}
- const std::vector<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
- std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() };
- std::transform(ssl_allowed_fingerprint_strings.begin(), ssl_allowed_fingerprint_strings.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
- const bool ssl_allow_any_cert = command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert);
-
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
- rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
- ssl_support, std::make_pair(ssl_private_key, ssl_certificate), std::move(ssl_allowed_certificates), std::move(ssl_allowed_fingerprints), ssl_allow_any_cert
+ rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(ssl_options)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -200,7 +202,9 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HEIGHT>(invoke_http_mode::JON, "/getheight", req, res, r))
return r;
- res.height = m_core.get_current_blockchain_height();
+ crypto::hash hash;
+ m_core.get_blockchain_top(res.height, hash);
+ res.hash = string_tools::pod_to_hex(hash);
res.status = CORE_RPC_STATUS_OK;
return true;
}
@@ -247,7 +251,6 @@ namespace cryptonote
res.cumulative_difficulty, res.wide_cumulative_difficulty, res.cumulative_difficulty_top64);
res.block_size_limit = res.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit();
res.block_size_median = res.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median();
- res.status = CORE_RPC_STATUS_OK;
res.start_time = restricted ? 0 : (uint64_t)m_core.get_start_time();
res.free_space = restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
@@ -265,6 +268,8 @@ namespace cryptonote
res.database_size = round_up(res.database_size, 5ull* 1024 * 1024 * 1024);
res.update_available = restricted ? false : m_core.is_update_available();
res.version = restricted ? "" : MONERO_VERSION;
+
+ res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -646,30 +651,61 @@ namespace cryptonote
e.prunable_hash = epee::string_tools::pod_to_hex(std::get<2>(tx));
if (req.split || req.prune || std::get<3>(tx).empty())
{
+ // use splitted form with pruned and prunable (filled only when prune=false and the daemon has it), leaving as_hex as empty
e.pruned_as_hex = string_tools::buff_to_hex_nodelimer(std::get<1>(tx));
if (!req.prune)
e.prunable_as_hex = string_tools::buff_to_hex_nodelimer(std::get<3>(tx));
- }
- else
- {
- cryptonote::blobdata tx_data;
- if (req.prune)
- tx_data = std::get<1>(tx);
- else
- tx_data = std::get<1>(tx) + std::get<3>(tx);
- e.as_hex = string_tools::buff_to_hex_nodelimer(tx_data);
- if (req.decode_as_json && !tx_data.empty())
+ if (req.decode_as_json)
{
+ cryptonote::blobdata tx_data;
cryptonote::transaction t;
- if (cryptonote::parse_and_validate_tx_from_blob(tx_data, t))
+ if (req.prune || std::get<3>(tx).empty())
{
- if (req.prune)
+ // decode pruned tx to JSON
+ tx_data = std::get<1>(tx);
+ if (cryptonote::parse_and_validate_tx_base_from_blob(tx_data, t))
{
pruned_transaction pruned_tx{t};
e.as_json = obj_to_json_str(pruned_tx);
}
else
+ {
+ res.status = "Failed to parse and validate pruned tx from blob";
+ return true;
+ }
+ }
+ else
+ {
+ // decode full tx to JSON
+ tx_data = std::get<1>(tx) + std::get<3>(tx);
+ if (cryptonote::parse_and_validate_tx_from_blob(tx_data, t))
+ {
e.as_json = obj_to_json_str(t);
+ }
+ else
+ {
+ res.status = "Failed to parse and validate tx from blob";
+ return true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // use non-splitted form, leaving pruned_as_hex and prunable_as_hex as empty
+ cryptonote::blobdata tx_data = std::get<1>(tx) + std::get<3>(tx);
+ e.as_hex = string_tools::buff_to_hex_nodelimer(tx_data);
+ if (req.decode_as_json)
+ {
+ cryptonote::transaction t;
+ if (cryptonote::parse_and_validate_tx_from_blob(tx_data, t))
+ {
+ e.as_json = obj_to_json_str(t);
+ }
+ else
+ {
+ res.status = "Failed to parse and validate tx from blob";
+ return true;
}
}
}
@@ -939,6 +975,7 @@ namespace cryptonote
const miner& lMiner = m_core.get_miner();
res.active = lMiner.is_mining();
res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled();
+ store_difficulty(m_core.get_blockchain_storage().get_difficulty_for_next_block(), res.difficulty, res.wide_difficulty, res.difficulty_top64);
res.block_target = m_core.get_blockchain_storage().get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
if ( lMiner.is_mining() ) {
@@ -1718,67 +1755,7 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
{
- PERF_TIMER(on_get_info_json);
- bool r;
- if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON_RPC, "get_info", req, res, r))
- {
- res.bootstrap_daemon_address = m_bootstrap_daemon_address;
- crypto::hash top_hash;
- m_core.get_blockchain_top(res.height_without_bootstrap, top_hash);
- ++res.height_without_bootstrap; // turn top block height into blockchain height
- res.was_bootstrap_ever_used = true;
- return r;
- }
-
- const bool restricted = m_restricted && ctx;
-
- crypto::hash top_hash;
- m_core.get_blockchain_top(res.height, top_hash);
- ++res.height; // turn top block height into blockchain height
- res.top_block_hash = string_tools::pod_to_hex(top_hash);
- res.target_height = m_core.get_target_blockchain_height();
- store_difficulty(m_core.get_blockchain_storage().get_difficulty_for_next_block(),
- res.difficulty, res.wide_difficulty, res.difficulty_top64);
- res.target = m_core.get_blockchain_storage().get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
- res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase
- res.tx_pool_size = m_core.get_pool_transactions_count();
- res.alt_blocks_count = restricted ? 0 : m_core.get_blockchain_storage().get_alternative_blocks_count();
- uint64_t total_conn = restricted ? 0 : m_p2p.get_public_connections_count();
- res.outgoing_connections_count = restricted ? 0 : m_p2p.get_public_outgoing_connections_count();
- res.incoming_connections_count = restricted ? 0 : (total_conn - res.outgoing_connections_count);
- res.rpc_connections_count = restricted ? 0 : get_connections_count();
- res.white_peerlist_size = restricted ? 0 : m_p2p.get_public_white_peers_count();
- res.grey_peerlist_size = restricted ? 0 : m_p2p.get_public_gray_peers_count();
-
- cryptonote::network_type net_type = nettype();
- res.mainnet = net_type == MAINNET;
- res.testnet = net_type == TESTNET;
- res.stagenet = net_type == STAGENET;
- res.nettype = net_type == MAINNET ? "mainnet" : net_type == TESTNET ? "testnet" : net_type == STAGENET ? "stagenet" : "fakechain";
-
- store_difficulty(m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1),
- res.cumulative_difficulty, res.wide_cumulative_difficulty, res.cumulative_difficulty_top64);
- res.block_size_limit = res.block_weight_limit = m_core.get_blockchain_storage().get_current_cumulative_block_weight_limit();
- res.block_size_median = res.block_weight_median = m_core.get_blockchain_storage().get_current_cumulative_block_weight_median();
- res.status = CORE_RPC_STATUS_OK;
- res.start_time = restricted ? 0 : (uint64_t)m_core.get_start_time();
- res.free_space = restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
- res.offline = m_core.offline();
- res.bootstrap_daemon_address = restricted ? "" : m_bootstrap_daemon_address;
- res.height_without_bootstrap = restricted ? 0 : res.height;
- if (restricted)
- res.was_bootstrap_ever_used = false;
- else
- {
- boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
- res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
- }
- res.database_size = m_core.get_blockchain_storage().get_db().get_database_size();
- if (restricted)
- res.database_size = round_up(res.database_size, 5ull * 1024 * 1024 * 1024);
- res.update_available = restricted ? false : m_core.is_update_available();
- res.version = restricted ? "" : MONERO_VERSION;
- return true;
+ return on_get_info(req, res, ctx);
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request& req, COMMAND_RPC_HARD_FORK_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
@@ -2436,9 +2413,9 @@ namespace cryptonote
, ""
};
- const command_line::arg_descriptor<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_certificates = {
- "rpc-ssl-allowed-certificates"
- , "List of paths to PEM format certificates of allowed peers (all allowed if empty)"
+ const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_ca_certificates = {
+ "rpc-ssl-ca-certificates"
+ , "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)."
};
const command_line::arg_descriptor<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_fingerprints = {
@@ -2448,7 +2425,7 @@ namespace cryptonote
const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_ssl_allow_any_cert = {
"rpc-ssl-allow-any-cert"
- , "Allow any peer certificate, rather than just those on the allowed list"
+ , "Allow any peer certificate"
, false
};
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 8f5d83f1b..a42ca2494 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -60,7 +60,7 @@ namespace cryptonote
static const command_line::arg_descriptor<std::string> arg_rpc_ssl;
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key;
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate;
- static const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_certificates;
+ static const command_line::arg_descriptor<std::string> arg_rpc_ssl_ca_certificates;
static const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints;
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 1f14267f6..7811db979 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -102,11 +102,13 @@ namespace cryptonote
uint64_t height;
std::string status;
bool untrusted;
+ std::string hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
+ KV_SERIALIZE(hash)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -821,6 +823,9 @@ namespace cryptonote
uint8_t bg_target;
uint32_t block_target;
uint64_t block_reward;
+ uint64_t difficulty;
+ std::string wide_difficulty;
+ uint64_t difficulty_top64;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@@ -836,6 +841,9 @@ namespace cryptonote
KV_SERIALIZE(bg_target)
KV_SERIALIZE(block_target)
KV_SERIALIZE(block_reward)
+ KV_SERIALIZE(difficulty)
+ KV_SERIALIZE(wide_difficulty)
+ KV_SERIALIZE(difficulty_top64)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 23122e1bb..4692f7d59 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -243,6 +243,7 @@ namespace
const char* USAGE_FREEZE("freeze <key_image>");
const char* USAGE_THAW("thaw <key_image>");
const char* USAGE_FROZEN("frozen <key_image>");
+ const char* USAGE_NET_STATS("net_stats");
const char* USAGE_VERSION("version");
const char* USAGE_HELP("help [<command>]");
@@ -2131,6 +2132,13 @@ bool simple_wallet::frozen(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::net_stats(const std::vector<std::string> &args)
+{
+ message_writer() << std::to_string(m_wallet->get_bytes_sent()) + tr(" bytes sent");
+ message_writer() << std::to_string(m_wallet->get_bytes_received()) + tr(" bytes received");
+ return true;
+}
+
bool simple_wallet::version(const std::vector<std::string> &args)
{
message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
@@ -2625,6 +2633,31 @@ bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std:
return true;
}
+bool simple_wallet::set_setup_background_mining(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ tools::wallet2::BackgroundMiningSetupType setup = tools::wallet2::BackgroundMiningMaybe;
+ if (args[1] == "yes" || args[1] == "1")
+ setup = tools::wallet2::BackgroundMiningYes;
+ else if (args[1] == "no" || args[1] == "0")
+ setup = tools::wallet2::BackgroundMiningNo;
+ else
+ {
+ fail_msg_writer() << tr("invalid argument: must be either 1/yes or 0/no");
+ return true;
+ }
+ m_wallet->setup_background_mining(setup);
+ m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ if (setup == tools::wallet2::BackgroundMiningYes)
+ start_background_mining();
+ else
+ stop_background_mining();
+ }
+ return true;
+}
+
bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -3134,6 +3167,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::frozen, this, _1),
tr(USAGE_FROZEN),
tr("Checks whether a given output is currently frozen by key image"));
+ m_cmd_binder.set_handler("net_stats",
+ boost::bind(&simple_wallet::net_stats, this, _1),
+ tr(USAGE_NET_STATS),
+ tr("Prints simple network stats"));
m_cmd_binder.set_handler("version",
boost::bind(&simple_wallet::version, this, _1),
tr(USAGE_VERSION),
@@ -3162,6 +3199,13 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
case tools::wallet2::AskPasswordOnAction: ask_password_string = "action"; break;
case tools::wallet2::AskPasswordToDecrypt: ask_password_string = "decrypt"; break;
}
+ std::string setup_background_mining_string = "invalid";
+ switch (m_wallet->setup_background_mining())
+ {
+ case tools::wallet2::BackgroundMiningMaybe: setup_background_mining_string = "maybe"; break;
+ case tools::wallet2::BackgroundMiningYes: setup_background_mining_string = "yes"; break;
+ case tools::wallet2::BackgroundMiningNo: setup_background_mining_string = "no"; break;
+ }
success_msg_writer() << "seed = " << seed_language;
success_msg_writer() << "always-confirm-transfers = " << m_wallet->always_confirm_transfers();
success_msg_writer() << "print-ring-members = " << m_wallet->print_ring_members();
@@ -3188,6 +3232,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "segregation-height = " << m_wallet->segregation_height();
success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs();
success_msg_writer() << "track-uses = " << m_wallet->track_uses();
+ success_msg_writer() << "setup-background-mining = " << setup_background_mining_string + tr(" (set this to support the network and to get a chance to receive new monero)");
success_msg_writer() << "device_name = " << m_wallet->device_name();
return true;
}
@@ -3245,6 +3290,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("setup-background-mining", set_setup_background_mining, tr("1/yes or 0/no"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
@@ -3440,6 +3486,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET;
epee::wipeable_string multisig_keys;
+ epee::wipeable_string password;
if (!handle_command_line(vm))
return false;
@@ -3547,7 +3594,6 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
}
}
- epee::wipeable_string password;
if (!m_generate_from_view_key.empty())
{
m_wallet_file = m_generate_from_view_key;
@@ -3992,8 +4038,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("can't specify --subaddress-lookahead and --wallet-file at the same time");
return false;
}
- bool r = open_wallet(vm);
+ auto r = open_wallet(vm);
CHECK_AND_ASSERT_MES(r, false, tr("failed to open account"));
+ password = *r;
}
if (!m_wallet)
{
@@ -4009,6 +4056,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_wallet->callback(this);
+ check_background_mining(password);
+
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -4378,12 +4427,12 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
return std::move(password);
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
+boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
{
if (!tools::wallet2::wallet_valid_path_format(m_wallet_file))
{
fail_msg_writer() << tr("wallet file path not valid: ") << m_wallet_file;
- return false;
+ return {};
}
bool keys_file_exists;
@@ -4393,7 +4442,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
if(!keys_file_exists)
{
fail_msg_writer() << tr("Key file not found. Failed to open wallet");
- return false;
+ return {};
}
epee::wipeable_string password;
@@ -4404,7 +4453,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
password = std::move(std::move(rc.second).password());
if (!m_wallet)
{
- return false;
+ return {};
}
m_wallet->callback(this);
@@ -4430,7 +4479,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
{
bool is_deterministic;
{
- SCOPED_WALLET_UNLOCK();
+ SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return {};);
is_deterministic = m_wallet->is_deterministic();
}
if (is_deterministic)
@@ -4439,7 +4488,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
"a deprecated version of the wallet. Please proceed to upgrade your wallet.\n");
std::string mnemonic_language = get_mnemonic_language();
if (mnemonic_language.empty())
- return false;
+ return {};
m_wallet->set_seed_language(mnemonic_language);
m_wallet->rewrite(m_wallet_file, password);
@@ -4471,14 +4520,14 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
if (password_is_correct)
fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % m_wallet_file;
}
- return false;
+ return {};
}
success_msg_writer() <<
"**********************************************************************\n" <<
tr("Use the \"help\" command to see the list of available commands.\n") <<
tr("Use \"help <command>\" to see a command's documentation.\n") <<
"**********************************************************************";
- return true;
+ return std::move(password);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::close_wallet()
@@ -4559,7 +4608,118 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std
}
return true;
}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::start_background_mining()
+{
+ COMMAND_RPC_MINING_STATUS::request reqq;
+ COMMAND_RPC_MINING_STATUS::response resq;
+ bool r = m_wallet->invoke_http_json("/mining_status", reqq, resq);
+ std::string err = interpret_rpc_response(r, resq.status);
+ if (!r)
+ return;
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to query mining status: ") << err;
+ return;
+ }
+ if (!resq.is_background_mining_enabled)
+ {
+ COMMAND_RPC_START_MINING::request req;
+ COMMAND_RPC_START_MINING::response res;
+ req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
+ req.threads_count = 1;
+ req.do_background_mining = true;
+ req.ignore_battery = false;
+ bool r = m_wallet->invoke_http_json("/start_mining", req, res);
+ std::string err = interpret_rpc_response(r, res.status);
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to setup background mining: ") << err;
+ return;
+ }
+ }
+ success_msg_writer() << tr("Background mining enabled. Thank you for supporting the Monero network.");
+}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::stop_background_mining()
+{
+ COMMAND_RPC_MINING_STATUS::request reqq;
+ COMMAND_RPC_MINING_STATUS::response resq;
+ bool r = m_wallet->invoke_http_json("/mining_status", reqq, resq);
+ if (!r)
+ return;
+ std::string err = interpret_rpc_response(r, resq.status);
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to query mining status: ") << err;
+ return;
+ }
+ if (resq.is_background_mining_enabled)
+ {
+ COMMAND_RPC_STOP_MINING::request req;
+ COMMAND_RPC_STOP_MINING::response res;
+ bool r = m_wallet->invoke_http_json("/stop_mining", req, res);
+ std::string err = interpret_rpc_response(r, res.status);
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to setup background mining: ") << err;
+ return;
+ }
+ }
+ message_writer(console_color_red, false) << tr("Background mining not enabled. Run \"set setup-background-mining 1\" to change.");
+}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::check_background_mining(const epee::wipeable_string &password)
+{
+ tools::wallet2::BackgroundMiningSetupType setup = m_wallet->setup_background_mining();
+ if (setup == tools::wallet2::BackgroundMiningNo)
+ {
+ message_writer(console_color_red, false) << tr("Background mining not enabled. Run \"set setup-background-mining 1\" to change.");
+ return;
+ }
+
+ if (!m_wallet->is_trusted_daemon())
+ {
+ message_writer() << tr("Using an untrusted daemon, skipping background mining check");
+ return;
+ }
+
+ COMMAND_RPC_MINING_STATUS::request req;
+ COMMAND_RPC_MINING_STATUS::response res;
+ bool r = m_wallet->invoke_http_json("/mining_status", req, res);
+ std::string err = interpret_rpc_response(r, res.status);
+ bool is_background_mining_enabled = false;
+ if (err.empty())
+ is_background_mining_enabled = res.is_background_mining_enabled;
+
+ if (is_background_mining_enabled)
+ {
+ // already active, nice
+ m_wallet->setup_background_mining(tools::wallet2::BackgroundMiningYes);
+ m_wallet->rewrite(m_wallet_file, password);
+ start_background_mining();
+ return;
+ }
+ if (res.active)
+ return;
+ if (setup == tools::wallet2::BackgroundMiningMaybe)
+ {
+ message_writer() << tr("The daemon is not set up to background mine.");
+ message_writer() << tr("With background mining enabled, the daemon will mine when idle and not on batttery.");
+ message_writer() << tr("Enabling this supports the network you are using, and makes you eligible for receiving new monero");
+ std::string accepted = input_line(tr("Do you want to do it now? (Y/Yes/N/No): "));
+ if (std::cin.eof() || !command_line::is_yes(accepted)) {
+ m_wallet->setup_background_mining(tools::wallet2::BackgroundMiningNo);
+ m_wallet->rewrite(m_wallet_file, password);
+ message_writer(console_color_red, false) << tr("Background mining not enabled. Set setup-background-mining to 1 to change.");
+ return;
+ }
+ m_wallet->setup_background_mining(tools::wallet2::BackgroundMiningYes);
+ m_wallet->rewrite(m_wallet_file, password);
+ start_background_mining();
+ }
+}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::start_mining(const std::vector<std::string>& args)
{
@@ -4985,10 +5145,15 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0});
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
+ uint64_t blocks_to_unlock;
+ uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, &blocks_to_unlock);
+ std::string unlock_time_message;
+ if (blocks_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account)) << ", "
- << tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance(m_current_subaddress_account)) << extra;
+ << tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account);
- std::map<uint32_t, uint64_t> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
if (!detailed || balance_per_subaddress.empty())
return true;
success_msg_writer() << tr("Balance per address:");
@@ -5000,7 +5165,7 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
cryptonote::subaddress_index subaddr_index = {m_current_subaddress_account, i.first};
std::string address_str = m_wallet->get_subaddress_as_str(subaddr_index).substr(0, 6);
uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == subaddr_index; });
- success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first]) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
+ success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first].first) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
}
return true;
}
@@ -6691,7 +6856,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
{
const tx_destination_entry &entry = cd.splitted_dsts[d];
std::string address, standard_address = get_account_address_as_str(m_wallet->nettype(), entry.is_subaddress, entry.addr);
- if (has_encrypted_payment_id && !entry.is_subaddress)
+ if (has_encrypted_payment_id && !entry.is_subaddress && standard_address != entry.original)
{
address = get_account_integrated_address_as_str(m_wallet->nettype(), entry.addr, payment_id8);
address += std::string(" (" + standard_address + " with encrypted payment id " + epee::string_tools::pod_to_hex(payment_id8) + ")");
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index c982a323b..0cbb33cf9 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -102,7 +102,7 @@ namespace cryptonote
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
const epee::wipeable_string &multisig_keys, const std::string &old_language);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm);
- bool open_wallet(const boost::program_options::variables_map& vm);
+ boost::optional<epee::wipeable_string> open_wallet(const boost::program_options::variables_map& vm);
bool close_wallet();
bool viewkey(const std::vector<std::string> &args = std::vector<std::string>());
@@ -143,6 +143,7 @@ namespace cryptonote
bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>());
bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>());
bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_setup_background_mining(const std::vector<std::string> &args = std::vector<std::string>());
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
@@ -242,6 +243,7 @@ namespace cryptonote
bool freeze(const std::vector<std::string>& args);
bool thaw(const std::vector<std::string>& args);
bool frozen(const std::vector<std::string>& args);
+ bool net_stats(const std::vector<std::string>& args);
bool version(const std::vector<std::string>& args);
bool cold_sign_tx(const std::vector<tools::wallet2::pending_tx>& ptx_vector, tools::wallet2::signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::function<bool(const tools::wallet2::signed_tx_set &)> accept_func);
@@ -298,6 +300,13 @@ namespace cryptonote
*/
void commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_vector, bool do_not_relay);
+ /*!
+ * \brief checks whether background mining is enabled, and asks to configure it if not
+ */
+ void check_background_mining(const epee::wipeable_string &password);
+ void start_background_mining();
+ void stop_background_mining();
+
//----------------- i_wallet2_callback ---------------------
virtual void on_new_block(uint64_t height, const cryptonote::block& block);
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index);
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index def23aff0..d0fc21f51 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -127,6 +127,7 @@ if (BUILD_GUI_DEPS)
ringct_basic
checkpoints
version
+ net
device_trezor)
foreach(lib ${libs_to_merge})
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index f066c9c14..dfcc61426 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -243,9 +243,10 @@ struct options {
const command_line::arg_descriptor<std::string> daemon_ssl = {"daemon-ssl", tools::wallet2::tr("Enable SSL on daemon RPC connections: enabled|disabled|autodetect"), "autodetect"};
const command_line::arg_descriptor<std::string> daemon_ssl_private_key = {"daemon-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
const command_line::arg_descriptor<std::string> daemon_ssl_certificate = {"daemon-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
- const command_line::arg_descriptor<std::vector<std::string>> daemon_ssl_allowed_certificates = {"daemon-ssl-allowed-certificates", tools::wallet2::tr("List of paths to PEM format certificates of allowed RPC servers")};
+ const command_line::arg_descriptor<std::string> daemon_ssl_ca_certificates = {"daemon-ssl-ca-certificates", tools::wallet2::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s).")};
const command_line::arg_descriptor<std::vector<std::string>> daemon_ssl_allowed_fingerprints = {"daemon-ssl-allowed-fingerprints", tools::wallet2::tr("List of valid fingerprints of allowed RPC servers")};
const command_line::arg_descriptor<bool> daemon_ssl_allow_any_cert = {"daemon-ssl-allow-any-cert", tools::wallet2::tr("Allow any SSL certificate from the daemon"), false};
+ const command_line::arg_descriptor<bool> daemon_ssl_allow_chained = {"daemon-ssl-allow-chained", tools::wallet2::tr("Allow user (via --daemon-ssl-ca-certificates) chain certificates"), false};
const command_line::arg_descriptor<bool> testnet = {"testnet", tools::wallet2::tr("For testnet. Daemon must also be launched with --testnet flag"), false};
const command_line::arg_descriptor<bool> stagenet = {"stagenet", tools::wallet2::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false};
const command_line::arg_descriptor<std::string, false, true, 2> shared_ringdb_dir = {
@@ -314,6 +315,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
const uint64_t kdf_rounds = command_line::get_arg(vm, opts.kdf_rounds);
THROW_WALLET_EXCEPTION_IF(kdf_rounds == 0, tools::error::wallet_internal_error, "KDF rounds must not be 0");
+ const bool use_proxy = command_line::has_arg(vm, opts.proxy);
auto daemon_address = command_line::get_arg(vm, opts.daemon_address);
auto daemon_host = command_line::get_arg(vm, opts.daemon_host);
auto daemon_port = command_line::get_arg(vm, opts.daemon_port);
@@ -321,13 +323,37 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
auto device_derivation_path = command_line::get_arg(vm, opts.hw_device_derivation_path);
auto daemon_ssl_private_key = command_line::get_arg(vm, opts.daemon_ssl_private_key);
auto daemon_ssl_certificate = command_line::get_arg(vm, opts.daemon_ssl_certificate);
- auto daemon_ssl_allowed_certificates = command_line::get_arg(vm, opts.daemon_ssl_allowed_certificates);
+ auto daemon_ssl_ca_file = command_line::get_arg(vm, opts.daemon_ssl_ca_certificates);
auto daemon_ssl_allowed_fingerprints = command_line::get_arg(vm, opts.daemon_ssl_allowed_fingerprints);
auto daemon_ssl_allow_any_cert = command_line::get_arg(vm, opts.daemon_ssl_allow_any_cert);
auto daemon_ssl = command_line::get_arg(vm, opts.daemon_ssl);
- epee::net_utils::ssl_support_t ssl_support;
- THROW_WALLET_EXCEPTION_IF(!epee::net_utils::ssl_support_from_string(ssl_support, daemon_ssl), tools::error::wallet_internal_error,
- tools::wallet2::tr("Invalid argument for ") + std::string(opts.daemon_ssl.name));
+
+ // user specified CA file or fingeprints implies enabled SSL by default
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ if (command_line::get_arg(vm, opts.daemon_ssl_allow_any_cert))
+ ssl_options.verification = epee::net_utils::ssl_verification_t::none;
+ else if (!daemon_ssl_ca_file.empty() || !daemon_ssl_allowed_fingerprints.empty())
+ {
+ std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ daemon_ssl_allowed_fingerprints.size() };
+ std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
+
+ ssl_options = epee::net_utils::ssl_options_t{
+ std::move(ssl_allowed_fingerprints), std::move(daemon_ssl_ca_file)
+ };
+
+ if (command_line::get_arg(vm, opts.daemon_ssl_allow_chained))
+ ssl_options.verification = epee::net_utils::ssl_verification_t::user_ca;
+ }
+
+ if (ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, opts.daemon_ssl))
+ {
+ THROW_WALLET_EXCEPTION_IF(!epee::net_utils::ssl_support_from_string(ssl_options.support, daemon_ssl), tools::error::wallet_internal_error,
+ tools::wallet2::tr("Invalid argument for ") + std::string(opts.daemon_ssl.name));
+ }
+
+ ssl_options.auth = epee::net_utils::ssl_authentication_t{
+ std::move(daemon_ssl_private_key), std::move(daemon_ssl_certificate)
+ };
THROW_WALLET_EXCEPTION_IF(!daemon_address.empty() && !daemon_host.empty() && 0 != daemon_port,
tools::error::wallet_internal_error, tools::wallet2::tr("can't specify daemon host or port more than once"));
@@ -357,22 +383,24 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
if (daemon_address.empty())
daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
- boost::asio::ip::tcp::endpoint proxy{};
- if (command_line::has_arg(vm, opts.proxy))
{
- namespace ip = boost::asio::ip;
const boost::string_ref real_daemon = boost::string_ref{daemon_address}.substr(0, daemon_address.rfind(':'));
- // onion and i2p addresses contain information about the server cert
- // which both authenticates and encrypts
- const bool unencrypted_proxy =
- !real_daemon.ends_with(".onion") && !real_daemon.ends_with(".i2p") &&
- daemon_ssl_allowed_certificates.empty() && daemon_ssl_allowed_fingerprints.empty();
+ const bool verification_required =
+ ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy;
+
THROW_WALLET_EXCEPTION_IF(
- unencrypted_proxy,
+ verification_required && !ssl_options.has_strong_verification(real_daemon),
tools::error::wallet_internal_error,
- std::string{"Use of --"} + opts.proxy.name + " requires --" + opts.daemon_ssl_allowed_certificates.name + " or --" + opts.daemon_ssl_allowed_fingerprints.name + " or use of a .onion/.i2p domain"
+ tools::wallet2::tr("Enabling --") + std::string{use_proxy ? opts.proxy.name : opts.daemon_ssl.name} + tools::wallet2::tr(" requires --") +
+ opts.daemon_ssl_ca_certificates.name + tools::wallet2::tr(" or --") + opts.daemon_ssl_allowed_fingerprints.name + tools::wallet2::tr(" or use of a .onion/.i2p domain")
);
+ }
+
+ boost::asio::ip::tcp::endpoint proxy{};
+ if (use_proxy)
+ {
+ namespace ip = boost::asio::ip;
const auto proxy_address = command_line::get_arg(vm, opts.proxy);
@@ -416,22 +444,8 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
catch (const std::exception &e) { }
}
- std::list<std::string> ssl_allowed_certificates;
- for (const std::string &path: daemon_ssl_allowed_certificates)
- {
- ssl_allowed_certificates.push_back({});
- if (!epee::file_io_utils::load_file_to_string(path, ssl_allowed_certificates.back()))
- {
- MERROR("Failed to load certificate: " << path);
- ssl_allowed_certificates.back() = std::string();
- }
- }
-
- std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ daemon_ssl_allowed_fingerprints.size() };
- std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
-
std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, kdf_rounds, unattended));
- wallet->init(std::move(daemon_address), std::move(login), std::move(proxy), 0, *trusted_daemon, ssl_support, std::make_pair(daemon_ssl_private_key, daemon_ssl_certificate), ssl_allowed_certificates, ssl_allowed_fingerprints, daemon_ssl_allow_any_cert);
+ wallet->init(std::move(daemon_address), std::move(login), std::move(proxy), 0, *trusted_daemon, std::move(ssl_options));
boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir);
wallet->set_ring_database(ringdb_path.string());
wallet->get_message_store().set_options(vm);
@@ -1032,6 +1046,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_segregation_height(0),
m_ignore_fractional_outputs(true),
m_track_uses(false),
+ m_setup_background_mining(BackgroundMiningMaybe),
m_is_initialized(false),
m_kdf_rounds(kdf_rounds),
is_old_file_format(false),
@@ -1100,9 +1115,10 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
command_line::add_arg(desc_params, opts.daemon_ssl);
command_line::add_arg(desc_params, opts.daemon_ssl_private_key);
command_line::add_arg(desc_params, opts.daemon_ssl_certificate);
- command_line::add_arg(desc_params, opts.daemon_ssl_allowed_certificates);
+ command_line::add_arg(desc_params, opts.daemon_ssl_ca_certificates);
command_line::add_arg(desc_params, opts.daemon_ssl_allowed_fingerprints);
command_line::add_arg(desc_params, opts.daemon_ssl_allow_any_cert);
+ command_line::add_arg(desc_params, opts.daemon_ssl_allow_chained);
command_line::add_arg(desc_params, opts.testnet);
command_line::add_arg(desc_params, opts.stagenet);
command_line::add_arg(desc_params, opts.shared_ringdb_dir);
@@ -1154,10 +1170,7 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, bool trusted_daemon,
- epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path,
- const std::list<std::string> &allowed_certificates, const std::vector<std::vector<uint8_t>> &allowed_fingerprints,
- bool allow_any_cert)
+bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options)
{
if(m_http_client.is_connected())
m_http_client.disconnect();
@@ -1166,17 +1179,17 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u
m_trusted_daemon = trusted_daemon;
MINFO("setting daemon to " << get_daemon_address());
- return m_http_client.set_server(get_daemon_address(), get_daemon_login(), ssl_support, private_key_and_certificate_path, allowed_certificates, allowed_fingerprints, allow_any_cert);
+ return m_http_client.set_server(get_daemon_address(), get_daemon_login(), std::move(ssl_options));
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, boost::asio::ip::tcp::endpoint proxy, uint64_t upper_transaction_weight_limit, bool trusted_daemon, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, const std::vector<std::vector<uint8_t>> &allowed_fingerprints, bool allow_any_cert)
+bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, boost::asio::ip::tcp::endpoint proxy, uint64_t upper_transaction_weight_limit, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options)
{
m_checkpoints.init_default_checkpoints(m_nettype);
m_is_initialized = true;
m_upper_transaction_weight_limit = upper_transaction_weight_limit;
if (proxy != boost::asio::ip::tcp::endpoint{})
m_http_client.set_connector(net::socks::connector{std::move(proxy)});
- return set_daemon(daemon_address, daemon_login, trusted_daemon, ssl_support, private_key_and_certificate_path, allowed_certificates, allowed_fingerprints, allow_any_cert);
+ return set_daemon(daemon_address, daemon_login, trusted_daemon, std::move(ssl_options));
}
//----------------------------------------------------------------------------------------------------
bool wallet2::is_deterministic() const
@@ -2275,6 +2288,12 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
add_rings(tx);
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::should_skip_block(const cryptonote::block &b, uint64_t height) const
+{
+ // seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup
+ return !(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height);
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
@@ -2284,7 +2303,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
//handle transactions from new block
//optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup
- if(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height)
+ if (!should_skip_block(b, height))
{
TIME_MEASURE_START(miner_tx_handle_time);
if (m_refresh_type != RefreshNoCoinbase)
@@ -2348,9 +2367,7 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids, uint64_t gra
//----------------------------------------------------------------------------------------------------
void wallet2::parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const
{
- error = !cryptonote::parse_and_validate_block_from_blob(blob, bl);
- if (!error)
- bl_id = get_block_hash(bl);
+ error = !cryptonote::parse_and_validate_block_from_blob(blob, bl, bl_id);
}
//----------------------------------------------------------------------------------------------------
void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices)
@@ -2416,6 +2433,11 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
{
THROW_WALLET_EXCEPTION_IF(parsed_blocks[i].txes.size() != parsed_blocks[i].block.tx_hashes.size(),
error::wallet_internal_error, "Mismatched parsed_blocks[i].txes.size() and parsed_blocks[i].block.tx_hashes.size()");
+ if (should_skip_block(parsed_blocks[i].block, start_height + i))
+ {
+ txidx += 1 + parsed_blocks[i].block.tx_hashes.size();
+ continue;
+ }
if (m_refresh_type != RefreshNoCoinbase)
tpool.submit(&waiter, [&, i, txidx](){ cache_tx_data(parsed_blocks[i].block.miner_tx, get_transaction_hash(parsed_blocks[i].block.miner_tx), tx_cache_data[txidx]); });
++txidx;
@@ -2444,6 +2466,8 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
for (size_t i = 0; i < tx_cache_data.size(); ++i)
{
+ if (tx_cache_data[i].empty())
+ continue;
tpool.submit(&waiter, [&hwdev, &gender, &tx_cache_data, i]() {
auto &slot = tx_cache_data[i];
boost::unique_lock<hw::device> hwdev_lock(hwdev);
@@ -2462,6 +2486,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
if (o.target.type() == typeid(cryptonote::txout_to_key))
{
std::vector<crypto::key_derivation> additional_derivations;
+ additional_derivations.reserve(tx_cache_data[txidx].additional.size());
for (const auto &iod: tx_cache_data[txidx].additional)
additional_derivations.push_back(iod.derivation);
const auto &key = boost::get<txout_to_key>(o.target).key;
@@ -2479,6 +2504,12 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
txidx = 0;
for (size_t i = 0; i < blocks.size(); ++i)
{
+ if (should_skip_block(parsed_blocks[i].block, start_height + i))
+ {
+ txidx += 1 + parsed_blocks[i].block.tx_hashes.size();
+ continue;
+ }
+
if (m_refresh_type != RefreshType::RefreshNoCoinbase)
{
THROW_WALLET_EXCEPTION_IF(txidx >= tx_cache_data.size(), error::wallet_internal_error, "txidx out of range");
@@ -3522,6 +3553,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_track_uses ? 1 : 0);
json.AddMember("track_uses", value2, json.GetAllocator());
+ value2.SetInt(m_setup_background_mining);
+ json.AddMember("setup_background_mining", value2, json.GetAllocator());
+
value2.SetUint(m_subaddress_lookahead_major);
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
@@ -3673,6 +3707,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = 0;
m_ignore_fractional_outputs = true;
m_track_uses = false;
+ m_setup_background_mining = BackgroundMiningMaybe;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false;
@@ -3827,6 +3862,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
m_track_uses = field_track_uses;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, setup_background_mining, BackgroundMiningSetupType, Int, false, BackgroundMiningMaybe);
+ m_setup_background_mining = field_setup_background_mining;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
@@ -4128,6 +4165,17 @@ bool wallet2::query_device(hw::device::device_type& device_type, const std::stri
return true;
}
+void wallet2::init_type(hw::device::device_type device_type)
+{
+ m_account_public_address = m_account.get_keys().m_account_address;
+ m_watch_only = false;
+ m_multisig = false;
+ m_multisig_threshold = 0;
+ m_multisig_signers.clear();
+ m_original_keys_available = false;
+ m_key_device_type = device_type;
+}
+
/*!
* \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file
@@ -4197,18 +4245,15 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys);
m_account.finalize_multisig(spend_public_key);
- m_account_public_address = m_account.get_keys().m_account_address;
- m_watch_only = false;
+ // Not possible to restore a multisig wallet that is able to activate the MMS
+ // (because the original keys are not (yet) part of the restore info), so
+ // keep m_original_keys_available to false
+ init_type(hw::device::device_type::SOFTWARE);
m_multisig = true;
m_multisig_threshold = threshold;
m_multisig_signers = multisig_signers;
- m_key_device_type = hw::device::device_type::SOFTWARE;
setup_keys(password);
- // Not possible to restore a multisig wallet that is able to activate the MMS
- // (because the original keys are not (yet) part of the restore info)
- m_original_keys_available = false;
-
create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
setup_new_blockchain();
@@ -4241,13 +4286,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
crypto::secret_key retval = m_account.generate(recovery_param, recover, two_random);
- m_account_public_address = m_account.get_keys().m_account_address;
- m_watch_only = false;
- m_multisig = false;
- m_multisig_threshold = 0;
- m_multisig_signers.clear();
- m_original_keys_available = false;
- m_key_device_type = hw::device::device_type::SOFTWARE;
+ init_type(hw::device::device_type::SOFTWARE);
setup_keys(password);
// calculate a starting refresh height
@@ -4330,13 +4369,9 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
}
m_account.create_from_viewkey(account_public_address, viewkey);
- m_account_public_address = account_public_address;
+ init_type(hw::device::device_type::SOFTWARE);
m_watch_only = true;
- m_multisig = false;
- m_multisig_threshold = 0;
- m_multisig_signers.clear();
- m_original_keys_available = false;
- m_key_device_type = hw::device::device_type::SOFTWARE;
+ m_account_public_address = account_public_address;
setup_keys(password);
create_keys_file(wallet_, true, password, m_nettype != MAINNET || create_address_file);
@@ -4371,13 +4406,8 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
}
m_account.create_from_keys(account_public_address, spendkey, viewkey);
+ init_type(hw::device::device_type::SOFTWARE);
m_account_public_address = account_public_address;
- m_watch_only = false;
- m_multisig = false;
- m_multisig_threshold = 0;
- m_multisig_signers.clear();
- m_original_keys_available = false;
- m_key_device_type = hw::device::device_type::SOFTWARE;
setup_keys(password);
create_keys_file(wallet_, false, password, create_address_file);
@@ -4412,13 +4442,7 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
hwdev.set_callback(get_device_callback());
m_account.create_from_device(hwdev);
- m_key_device_type = m_account.get_device().get_type();
- m_account_public_address = m_account.get_keys().m_account_address;
- m_watch_only = false;
- m_multisig = false;
- m_multisig_threshold = 0;
- m_multisig_signers.clear();
- m_original_keys_available = false;
+ init_type(m_account.get_device().get_type());
setup_keys(password);
m_device_name = device_name;
@@ -4550,10 +4574,9 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
"Failed to create multisig wallet due to bad keys");
memwipe(&spend_skey, sizeof(rct::key));
- m_account_public_address = m_account.get_keys().m_account_address;
- m_watch_only = false;
+ init_type(hw::device::device_type::SOFTWARE);
+ m_original_keys_available = true;
m_multisig = true;
- m_key_device_type = hw::device::device_type::SOFTWARE;
m_multisig_threshold = threshold;
m_multisig_signers = multisig_signers;
++m_multisig_rounds_passed;
@@ -5441,13 +5464,19 @@ uint64_t wallet2::balance(uint32_t index_major) const
return amount;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance(uint32_t index_major) const
+uint64_t wallet2::unlocked_balance(uint32_t index_major, uint64_t *blocks_to_unlock) const
{
uint64_t amount = 0;
+ if (blocks_to_unlock)
+ *blocks_to_unlock = 0;
if(m_light_wallet)
return m_light_wallet_balance;
for (const auto& i : unlocked_balance_per_subaddress(index_major))
- amount += i.second;
+ {
+ amount += i.second.first;
+ if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
+ *blocks_to_unlock = i.second.second;
+ }
return amount;
}
//----------------------------------------------------------------------------------------------------
@@ -5480,18 +5509,36 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
return amount_per_subaddr;
}
//----------------------------------------------------------------------------------------------------
-std::map<uint32_t, uint64_t> wallet2::unlocked_balance_per_subaddress(uint32_t index_major) const
+std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major) const
{
- std::map<uint32_t, uint64_t> amount_per_subaddr;
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr;
+ const uint64_t blockchain_height = get_blockchain_current_height();
for(const transfer_details& td: m_transfers)
{
- if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen && is_transfer_unlocked(td))
+ if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
{
+ uint64_t amount = 0, blocks_to_unlock = 0;
+ if (is_transfer_unlocked(td))
+ {
+ amount = td.amount();
+ blocks_to_unlock = 0;
+ }
+ else
+ {
+ uint64_t unlock_height = td.m_block_height + std::max<uint64_t>(CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);
+ if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > unlock_height)
+ unlock_height = td.m_tx.unlock_time;
+ blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 0;
+ amount = 0;
+ }
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
- amount_per_subaddr[td.m_subaddr_index.minor] = td.amount();
+ amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, blocks_to_unlock);
else
- found->second += td.amount();
+ {
+ found->second.first += amount;
+ found->second.second = std::max(found->second.second, blocks_to_unlock);
+ }
}
}
return amount_per_subaddr;
@@ -5505,11 +5552,18 @@ uint64_t wallet2::balance_all() const
return r;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance_all() const
+uint64_t wallet2::unlocked_balance_all(uint64_t *blocks_to_unlock) const
{
uint64_t r = 0;
+ if (blocks_to_unlock)
+ *blocks_to_unlock = 0;
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
- r += unlocked_balance(index_major);
+ {
+ uint64_t local_blocks_to_unlock;
+ r += unlocked_balance(index_major, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
+ if (blocks_to_unlock)
+ *blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
+ }
return r;
}
//----------------------------------------------------------------------------------------------------
@@ -9092,7 +9146,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// throw if attempting a transaction with no money
THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination);
- std::map<uint32_t, uint64_t> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account);
if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
@@ -9110,7 +9164,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
for (uint32_t index_minor : subaddr_indices)
{
balance_subtotal += balance_per_subaddr[index_minor];
- unlocked_balance_subtotal += unlocked_balance_per_subaddr[index_minor];
+ unlocked_balance_subtotal += unlocked_balance_per_subaddr[index_minor].first;
}
THROW_WALLET_EXCEPTION_IF(needed_money + min_fee > balance_subtotal, error::not_enough_money,
balance_subtotal, needed_money, 0);
@@ -9176,7 +9230,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
{
auto sort_predicate = [&unlocked_balance_per_subaddr] (const std::pair<uint32_t, std::vector<size_t>>& x, const std::pair<uint32_t, std::vector<size_t>>& y)
{
- return unlocked_balance_per_subaddr[x.first] > unlocked_balance_per_subaddr[y.first];
+ return unlocked_balance_per_subaddr[x.first].first > unlocked_balance_per_subaddr[y.first].first;
};
std::sort(unused_transfers_indices_per_subaddr.begin(), unused_transfers_indices_per_subaddr.end(), sort_predicate);
std::sort(unused_dust_indices_per_subaddr.begin(), unused_dust_indices_per_subaddr.end(), sort_predicate);
@@ -10621,13 +10675,13 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
check_tx_key_helper(tx, derivation, additional_derivations, address, received);
in_pool = res.txs.front().in_pool;
- confirmations = (uint64_t)-1;
+ confirmations = 0;
if (!in_pool)
{
std::string err;
uint64_t bc_height = get_daemon_blockchain_height(err);
if (err.empty())
- confirmations = bc_height - (res.txs.front().block_height + 1);
+ confirmations = bc_height - res.txs.front().block_height;
}
}
@@ -10823,13 +10877,13 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
return false;
in_pool = res.txs.front().in_pool;
- confirmations = (uint64_t)-1;
+ confirmations = 0;
if (!in_pool)
{
std::string err;
uint64_t bc_height = get_daemon_blockchain_height(err);
if (err.empty())
- confirmations = bc_height - (res.txs.front().block_height + 1);
+ confirmations = bc_height - res.txs.front().block_height;
}
return true;
@@ -12990,4 +13044,14 @@ void wallet2::finish_rescan_bc_keep_key_images(uint64_t transfer_height, const c
m_transfers[it->second].m_key_image_known = true;
}
}
+//----------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_bytes_sent() const
+{
+ return m_http_client.get_bytes_sent();
+}
+//----------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_bytes_received() const
+{
+ return m_http_client.get_bytes_received();
+}
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 921172988..c8ac7d429 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -194,6 +194,12 @@ namespace tools
AskPasswordToDecrypt = 2,
};
+ enum BackgroundMiningSetupType {
+ BackgroundMiningMaybe = 0,
+ BackgroundMiningYes = 1,
+ BackgroundMiningNo = 2,
+ };
+
static const char* tr(const char* str);
static bool has_testnet_option(const boost::program_options::variables_map& vm);
@@ -533,6 +539,8 @@ namespace tools
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
std::vector<is_out_data> primary;
std::vector<is_out_data> additional;
+
+ bool empty() const { return tx_extra_fields.empty() && primary.empty() && additional.empty(); }
};
/*!
@@ -687,16 +695,10 @@ namespace tools
boost::asio::ip::tcp::endpoint proxy = {},
uint64_t upper_transaction_weight_limit = 0,
bool trusted_daemon = true,
- epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
- const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
- const std::list<std::string> &allowed_certificates = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {},
- bool allow_any_cert = false);
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
bool set_daemon(std::string daemon_address = "http://localhost:8080",
boost::optional<epee::net_utils::http::login> daemon_login = boost::none, bool trusted_daemon = true,
- epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
- const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
- const std::list<std::string> &allowed_certificates = {}, const std::vector<std::vector<uint8_t>> &allowed_fingerprints = {},
- bool allow_any_cert = false);
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); }
@@ -771,13 +773,13 @@ namespace tools
// locked & unlocked balance of given or current subaddress account
uint64_t balance(uint32_t subaddr_index_major) const;
- uint64_t unlocked_balance(uint32_t subaddr_index_major) const;
+ uint64_t unlocked_balance(uint32_t subaddr_index_major, uint64_t *blocks_to_unlock = NULL) const;
// locked & unlocked balance per subaddress of given or current subaddress account
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major) const;
- std::map<uint32_t, uint64_t> unlocked_balance_per_subaddress(uint32_t subaddr_index_major) const;
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major) const;
// all locked & unlocked balances of all subaddress accounts
uint64_t balance_all() const;
- uint64_t unlocked_balance_all() const;
+ uint64_t unlocked_balance_all(uint64_t *blocks_to_unlock = NULL) const;
template<typename T>
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
@@ -1014,6 +1016,8 @@ namespace tools
void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; }
bool track_uses() const { return m_track_uses; }
void track_uses(bool value) { m_track_uses = value; }
+ BackgroundMiningSetupType setup_background_mining() const { return m_setup_background_mining; }
+ void setup_background_mining(BackgroundMiningSetupType value) { m_setup_background_mining = value; }
const std::string & device_name() const { return m_device_name; }
void device_name(const std::string & device_name) { m_device_name = device_name; }
const std::string & device_derivation_path() const { return m_device_derivation_path; }
@@ -1264,6 +1268,9 @@ namespace tools
bool frozen(const crypto::key_image &ki) const;
bool frozen(const transfer_details &td) const;
+ uint64_t get_bytes_sent() const;
+ uint64_t get_bytes_received() const;
+
// MMS -------------------------------------------------------------------------------------------------
mms::message_store& get_message_store() { return m_message_store; };
const mms::message_store& get_message_store() const { return m_message_store; };
@@ -1298,6 +1305,7 @@ namespace tools
*/
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
+ bool should_skip_block(const cryptonote::block &b, uint64_t height) const;
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const;
@@ -1364,6 +1372,7 @@ namespace tools
void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const;
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> create_output_tracker_cache() const;
+ void init_type(hw::device::device_type device_type);
void setup_new_blockchain();
void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
@@ -1452,6 +1461,7 @@ namespace tools
uint64_t m_segregation_height;
bool m_ignore_fractional_outputs;
bool m_track_uses;
+ BackgroundMiningSetupType m_setup_background_mining;
bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 95cda7f1e..71c64d3c1 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -68,7 +68,7 @@ namespace
const command_line::arg_descriptor<std::string> arg_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"};
const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
- const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_certificates = {"rpc-ssl-allowed-certificates", tools::wallet2::tr("List of paths to PEM format certificates of allowed RPC servers (all allowed if empty)")};
+ const command_line::arg_descriptor<std::string> arg_rpc_ssl_ca_certificates = {"rpc-ssl-ca-certificates", tools::wallet2::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s).")};
const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints = {"rpc-ssl-allowed-fingerprints", tools::wallet2::tr("List of certificate fingerprints to allow")};
constexpr const char default_rpc_username[] = "monero";
@@ -247,40 +247,102 @@ namespace tools
auto rpc_ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
auto rpc_ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
- auto rpc_ssl_allowed_certificates = command_line::get_arg(vm, arg_rpc_ssl_allowed_certificates);
+ auto rpc_ssl_ca_file = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
auto rpc_ssl_allowed_fingerprints = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
auto rpc_ssl = command_line::get_arg(vm, arg_rpc_ssl);
- epee::net_utils::ssl_support_t rpc_ssl_support;
- if (!epee::net_utils::ssl_support_from_string(rpc_ssl_support, rpc_ssl))
+ epee::net_utils::ssl_options_t rpc_ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+
+ if (!rpc_ssl_ca_file.empty() || !rpc_ssl_allowed_fingerprints.empty())
{
- MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
- return false;
+ std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
+ std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
+
+ rpc_ssl_options = epee::net_utils::ssl_options_t{
+ std::move(allowed_fingerprints), std::move(rpc_ssl_ca_file)
+ };
}
- std::list<std::string> allowed_certificates;
- for (const std::string &path: rpc_ssl_allowed_certificates)
+
+ // user specified CA file or fingeprints implies enabled SSL by default
+ if (rpc_ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
{
- allowed_certificates.push_back({});
- if (!epee::file_io_utils::load_file_to_string(path, allowed_certificates.back()))
- {
- MERROR("Failed to load certificate: " << path);
- allowed_certificates.back() = std::string();
- }
+ if (!epee::net_utils::ssl_support_from_string(rpc_ssl_options.support, rpc_ssl))
+ {
+ MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
+ return false;
+ }
}
- std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
- std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
+ rpc_ssl_options.auth = epee::net_utils::ssl_authentication_t{
+ std::move(rpc_ssl_private_key), std::move(rpc_ssl_certificate)
+ };
m_auto_refresh_period = DEFAULT_AUTO_REFRESH_PERIOD;
m_last_auto_refresh_time = boost::posix_time::min_date_time;
+ check_background_mining();
+
m_net_server.set_threads_prefix("RPC");
auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); };
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
- rpc_ssl_support, std::make_pair(rpc_ssl_private_key, rpc_ssl_certificate), std::move(allowed_certificates), std::move(allowed_fingerprints)
+ std::move(rpc_ssl_options)
);
}
//------------------------------------------------------------------------------------------------------------------------------
+ void wallet_rpc_server::check_background_mining()
+ {
+ if (!m_wallet)
+ return;
+
+ tools::wallet2::BackgroundMiningSetupType setup = m_wallet->setup_background_mining();
+ if (setup == tools::wallet2::BackgroundMiningNo)
+ {
+ MLOG_RED(el::Level::Warning, "Background mining not enabled. Run \"set setup-background-mining 1\" in monero-wallet-cli to change.");
+ return;
+ }
+
+ if (!m_wallet->is_trusted_daemon())
+ {
+ MDEBUG("Using an untrusted daemon, skipping background mining check");
+ return;
+ }
+
+ cryptonote::COMMAND_RPC_MINING_STATUS::request req;
+ cryptonote::COMMAND_RPC_MINING_STATUS::response res;
+ bool r = m_wallet->invoke_http_json("/mining_status", req, res);
+ if (!r || res.status != CORE_RPC_STATUS_OK)
+ {
+ MERROR("Failed to query mining status: " << (r ? res.status : "No connection to daemon"));
+ return;
+ }
+ if (res.active || res.is_background_mining_enabled)
+ return;
+
+ if (setup == tools::wallet2::BackgroundMiningMaybe)
+ {
+ MINFO("The daemon is not set up to background mine.");
+ MINFO("With background mining enabled, the daemon will mine when idle and not on batttery.");
+ MINFO("Enabling this supports the network you are using, and makes you eligible for receiving new monero");
+ MINFO("Set setup-background-mining to 1 in monero-wallet-cli to change.");
+ return;
+ }
+
+ cryptonote::COMMAND_RPC_START_MINING::request req2;
+ cryptonote::COMMAND_RPC_START_MINING::response res2;
+ req2.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
+ req2.threads_count = 1;
+ req2.do_background_mining = true;
+ req2.ignore_battery = false;
+ r = m_wallet->invoke_http_json("/start_mining", req2, res);
+ if (!r || res2.status != CORE_RPC_STATUS_OK)
+ {
+ MERROR("Failed to setup background mining: " << (r ? res.status : "No connection to daemon"));
+ return;
+ }
+
+ MINFO("Background mining enabled. The daemon will mine when idle and not on batttery.");
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::not_open(epee::json_rpc::error& er)
{
er.code = WALLET_RPC_ERROR_CODE_NOT_OPEN;
@@ -385,10 +447,10 @@ namespace tools
try
{
res.balance = req.all_accounts ? m_wallet->balance_all() : m_wallet->balance(req.account_index);
- res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all() : m_wallet->unlocked_balance(req.account_index);
+ res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(&res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, &res.blocks_to_unlock);
res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images();
std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account;
- std::map<uint32_t, std::map<uint32_t, uint64_t>> unlocked_balance_per_subaddress_per_account;
+ std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account;
if (req.all_accounts)
{
for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
@@ -408,7 +470,7 @@ namespace tools
{
uint32_t account_index = p.first;
std::map<uint32_t, uint64_t> balance_per_subaddress = p.second;
- std::map<uint32_t, uint64_t> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
std::set<uint32_t> address_indices;
if (!req.all_accounts && !req.address_indices.empty())
{
@@ -427,7 +489,8 @@ namespace tools
cryptonote::subaddress_index index = {info.account_index, info.address_index};
info.address = m_wallet->get_subaddress_as_str(index);
info.balance = balance_per_subaddress[i];
- info.unlocked_balance = unlocked_balance_per_subaddress[i];
+ info.unlocked_balance = unlocked_balance_per_subaddress[i].first;
+ info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second;
info.label = m_wallet->get_subaddress_label(index);
info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index; });
res.per_subaddress.emplace_back(std::move(info));
@@ -1173,7 +1236,7 @@ namespace tools
{
const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d];
std::string address = cryptonote::get_account_address_as_str(m_wallet->nettype(), entry.is_subaddress, entry.addr);
- if (has_encrypted_payment_id && !entry.is_subaddress)
+ if (has_encrypted_payment_id && !entry.is_subaddress && address != entry.original)
address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), entry.addr, payment_id8);
auto i = dests.find(entry.addr);
if (i == dests.end())
@@ -2916,7 +2979,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
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, const connection_context *ctx)
{
- crypto::ElectrumWords::get_language_list(res.languages);
+ crypto::ElectrumWords::get_language_list(res.languages, true);
+ crypto::ElectrumWords::get_language_list(res.languages_local, false);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -2947,14 +3011,19 @@ namespace tools
std::string wallet_file = req.filename.empty() ? "" : (m_wallet_dir + "/" + req.filename);
{
std::vector<std::string> languages;
- crypto::ElectrumWords::get_language_list(languages);
+ crypto::ElectrumWords::get_language_list(languages, false);
std::vector<std::string>::iterator it;
it = std::find(languages.begin(), languages.end(), req.language);
if (it == languages.end())
{
+ crypto::ElectrumWords::get_language_list(languages, true);
+ 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";
+ er.message = "Unknown language: " + req.language;
return false;
}
}
@@ -4048,13 +4117,7 @@ namespace tools
er.message = "Command unavailable in restricted mode.";
return false;
}
- epee::net_utils::ssl_support_t ssl_support;
- if (!epee::net_utils::ssl_support_from_string(ssl_support, req.ssl_support))
- {
- er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
- er.message = std::string("Invalid ssl support mode");
- return false;
- }
+
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints;
ssl_allowed_fingerprints.reserve(req.ssl_allowed_fingerprints.size());
for (const std::string &fp: req.ssl_allowed_fingerprints)
@@ -4064,7 +4127,31 @@ namespace tools
for (auto c: fp)
v.push_back(c);
}
- if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, ssl_support, std::make_pair(req.ssl_private_key_path, req.ssl_certificate_path), req.ssl_allowed_certificates, ssl_allowed_fingerprints, req.ssl_allow_any_cert))
+
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ if (req.ssl_allow_any_cert)
+ ssl_options.verification = epee::net_utils::ssl_verification_t::none;
+ else if (!ssl_allowed_fingerprints.empty() || !req.ssl_ca_file.empty())
+ ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(req.ssl_ca_file)};
+
+ if (!epee::net_utils::ssl_support_from_string(ssl_options.support, req.ssl_support))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
+ er.message = std::string("Invalid ssl support mode");
+ return false;
+ }
+
+ ssl_options.auth = epee::net_utils::ssl_authentication_t{
+ std::move(req.ssl_private_key_path), std::move(req.ssl_certificate_path)
+ };
+
+ if (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled && !ssl_options.has_strong_verification(boost::string_ref{}))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
+ er.message = "SSL is enabled but no user certificate or fingerprints were provided";
+ }
+
+ if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, std::move(ssl_options)))
{
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
er.message = std::string("Unable to set daemon");
@@ -4272,7 +4359,7 @@ int main(int argc, char** argv) {
command_line::add_arg(desc_params, arg_rpc_ssl);
command_line::add_arg(desc_params, arg_rpc_ssl_private_key);
command_line::add_arg(desc_params, arg_rpc_ssl_certificate);
- command_line::add_arg(desc_params, arg_rpc_ssl_allowed_certificates);
+ command_line::add_arg(desc_params, arg_rpc_ssl_ca_certificates);
command_line::add_arg(desc_params, arg_rpc_ssl_allowed_fingerprints);
daemonizer::init_options(hidden_options, desc_params);
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index fb0c48a80..7d2272dd0 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -254,6 +254,8 @@ namespace tools
bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er);
+ void check_background_mining();
+
wallet2 *m_wallet;
std::string m_wallet_dir;
tools::private_file rpc_login_file;
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 298f34f66..bb360ae01 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 8
+#define WALLET_RPC_VERSION_MINOR 9
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@@ -81,6 +81,7 @@ namespace wallet_rpc
uint64_t unlocked_balance;
std::string label;
uint64_t num_unspent_outputs;
+ uint64_t blocks_to_unlock;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
@@ -90,6 +91,7 @@ namespace wallet_rpc
KV_SERIALIZE(unlocked_balance)
KV_SERIALIZE(label)
KV_SERIALIZE(num_unspent_outputs)
+ KV_SERIALIZE(blocks_to_unlock)
END_KV_SERIALIZE_MAP()
};
@@ -99,12 +101,14 @@ namespace wallet_rpc
uint64_t unlocked_balance;
bool multisig_import_needed;
std::vector<per_subaddress_info> per_subaddress;
+ uint64_t blocks_to_unlock;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balance)
KV_SERIALIZE(unlocked_balance)
KV_SERIALIZE(multisig_import_needed)
KV_SERIALIZE(per_subaddress)
+ KV_SERIALIZE(blocks_to_unlock)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -1999,9 +2003,11 @@ namespace wallet_rpc
struct response_t
{
std::vector<std::string> languages;
+ std::vector<std::string> languages_local;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(languages)
+ KV_SERIALIZE(languages_local)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -2446,7 +2452,7 @@ namespace wallet_rpc
std::string ssl_support; // disabled, enabled, autodetect
std::string ssl_private_key_path;
std::string ssl_certificate_path;
- std::list<std::string> ssl_allowed_certificates;
+ std::string ssl_ca_file;
std::vector<std::string> ssl_allowed_fingerprints;
bool ssl_allow_any_cert;
@@ -2456,7 +2462,7 @@ namespace wallet_rpc
KV_SERIALIZE_OPT(ssl_support, (std::string)"autodetect")
KV_SERIALIZE(ssl_private_key_path)
KV_SERIALIZE(ssl_certificate_path)
- KV_SERIALIZE(ssl_allowed_certificates)
+ KV_SERIALIZE(ssl_ca_file)
KV_SERIALIZE(ssl_allowed_fingerprints)
KV_SERIALIZE_OPT(ssl_allow_any_cert, false)
END_KV_SERIALIZE_MAP()