diff options
Diffstat (limited to 'src')
37 files changed, 582 insertions, 208 deletions
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index d772bf4bb..2b039f557 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -211,8 +211,6 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck if (blk.tx_hashes.size() != txs.size()) throw std::runtime_error("Inconsistent tx/hashes sizes"); - block_txn_start(false); - TIME_MEASURE_START(time1); crypto::hash blk_hash = get_block_hash(blk); TIME_MEASURE_FINISH(time1); @@ -252,8 +250,6 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck m_hardfork->add(blk, prev_height); - block_txn_stop(); - ++num_calls; return prev_height; diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 2c40b5a78..567be6a65 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -770,9 +770,12 @@ public: */ virtual void set_batch_transactions(bool) = 0; - virtual void block_txn_start(bool readonly=false) = 0; - virtual void block_txn_stop() = 0; - virtual void block_txn_abort() = 0; + virtual void block_wtxn_start() = 0; + virtual void block_wtxn_stop() = 0; + virtual void block_wtxn_abort() = 0; + virtual bool block_rtxn_start() const = 0; + virtual void block_rtxn_stop() const = 0; + virtual void block_rtxn_abort() const = 0; virtual void set_hard_fork(HardFork* hf); @@ -1699,6 +1702,52 @@ public: }; // class BlockchainDB +class db_txn_guard +{ +public: + db_txn_guard(BlockchainDB *db, bool readonly): db(db), readonly(readonly), active(false) + { + if (readonly) + { + active = db->block_rtxn_start(); + } + else + { + db->block_wtxn_start(); + active = true; + } + } + virtual ~db_txn_guard() + { + if (active) + stop(); + } + void stop() + { + if (readonly) + db->block_rtxn_stop(); + else + db->block_wtxn_stop(); + active = false; + } + void abort() + { + if (readonly) + db->block_rtxn_abort(); + else + db->block_wtxn_abort(); + active = false; + } + +private: + BlockchainDB *db; + bool readonly; + bool active; +}; + +class db_rtxn_guard: public db_txn_guard { public: db_rtxn_guard(BlockchainDB *db): db_txn_guard(db, true) {} }; +class db_wtxn_guard: public db_txn_guard { public: db_wtxn_guard(BlockchainDB *db): db_txn_guard(db, false) {} }; + BlockchainDB *new_db(const std::string& db_type); } // namespace cryptonote diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index a07e9ac55..340434888 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -3611,16 +3611,15 @@ void BlockchainLMDB::block_rtxn_stop() const memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags)); } -void BlockchainLMDB::block_txn_start(bool readonly) +bool BlockchainLMDB::block_rtxn_start() const { - if (readonly) - { - MDB_txn *mtxn; - mdb_txn_cursors *mcur; - block_rtxn_start(&mtxn, &mcur); - return; - } + MDB_txn *mtxn; + mdb_txn_cursors *mcur; + return block_rtxn_start(&mtxn, &mcur); +} +void BlockchainLMDB::block_wtxn_start() +{ LOG_PRINT_L3("BlockchainLMDB::" << __func__); // Distinguish the exceptions here from exceptions that would be thrown while // using the txn and committing it. @@ -3652,10 +3651,13 @@ void BlockchainLMDB::block_txn_start(bool readonly) throw0(DB_ERROR_TXN_START((std::string("Attempted to start new write txn when batch txn already exists in ")+__FUNCTION__).c_str())); } -void BlockchainLMDB::block_txn_stop() +void BlockchainLMDB::block_wtxn_stop() { LOG_PRINT_L3("BlockchainLMDB::" << __func__); - if (m_write_txn && m_writer == boost::this_thread::get_id()) + if (!m_write_txn) + throw0(DB_ERROR_TXN_START((std::string("Attempted to stop write txn when no such txn exists in ")+__FUNCTION__).c_str())); + if (m_writer != boost::this_thread::get_id()) + throw0(DB_ERROR_TXN_START((std::string("Attempted to stop write txn from the wrong thread in ")+__FUNCTION__).c_str())); { if (! m_batch_active) { @@ -3669,40 +3671,31 @@ void BlockchainLMDB::block_txn_stop() memset(&m_wcursors, 0, sizeof(m_wcursors)); } } - else if (m_tinfo->m_ti_rtxn) - { - mdb_txn_reset(m_tinfo->m_ti_rtxn); - memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags)); - } } -void BlockchainLMDB::block_txn_abort() +void BlockchainLMDB::block_wtxn_abort() { LOG_PRINT_L3("BlockchainLMDB::" << __func__); - if (m_write_txn && m_writer == boost::this_thread::get_id()) - { - if (! m_batch_active) - { - delete m_write_txn; - m_write_txn = nullptr; - memset(&m_wcursors, 0, sizeof(m_wcursors)); - } - } - else if (m_tinfo->m_ti_rtxn) - { - mdb_txn_reset(m_tinfo->m_ti_rtxn); - memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags)); - } - else + if (!m_write_txn) + throw0(DB_ERROR_TXN_START((std::string("Attempted to abort write txn when no such txn exists in ")+__FUNCTION__).c_str())); + if (m_writer != boost::this_thread::get_id()) + throw0(DB_ERROR_TXN_START((std::string("Attempted to abort write txn from the wrong thread in ")+__FUNCTION__).c_str())); + + if (! m_batch_active) { - // This would probably mean an earlier exception was caught, but then we - // proceeded further than we should have. - throw0(DB_ERROR((std::string("BlockchainLMDB::") + __func__ + - std::string(": block-level DB transaction abort called when write txn doesn't exist") - ).c_str())); + delete m_write_txn; + m_write_txn = nullptr; + memset(&m_wcursors, 0, sizeof(m_wcursors)); } } +void BlockchainLMDB::block_rtxn_abort() const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + mdb_txn_reset(m_tinfo->m_ti_rtxn); + memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags)); +} + uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const std::vector<std::pair<transaction, blobdata>>& txs) { @@ -3728,11 +3721,6 @@ uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t { throw; } - catch (...) - { - block_txn_abort(); - throw; - } return ++m_height; } @@ -3742,16 +3730,16 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs) LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); - block_txn_start(false); + block_wtxn_start(); try { BlockchainDB::pop_block(blk, txs); - block_txn_stop(); + block_wtxn_stop(); } catch (...) { - block_txn_abort(); + block_wtxn_abort(); throw; } } diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index f6b00817d..4b46f081e 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -310,11 +310,14 @@ public: virtual void batch_stop(); virtual void batch_abort(); - virtual void block_txn_start(bool readonly); - virtual void block_txn_stop(); - virtual void block_txn_abort(); - virtual bool block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) const; + virtual void block_wtxn_start(); + virtual void block_wtxn_stop(); + virtual void block_wtxn_abort(); + virtual bool block_rtxn_start() const; virtual void block_rtxn_stop() const; + virtual void block_rtxn_abort() const; + + bool block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) const; virtual void pop_block(block& blk, std::vector<transaction>& txs); diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h index 04fad26a4..1492fb2ae 100644 --- a/src/blockchain_db/testdb.h +++ b/src/blockchain_db/testdb.h @@ -55,9 +55,13 @@ public: virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) { return true; } virtual void batch_stop() {} virtual void set_batch_transactions(bool) {} - virtual void block_txn_start(bool readonly=false) {} - virtual void block_txn_stop() {} - virtual void block_txn_abort() {} + virtual void block_wtxn_start() {} + virtual void block_wtxn_stop() {} + virtual void block_wtxn_abort() {} + virtual bool block_rtxn_start() const { return true; } + virtual void block_rtxn_stop() const {} + virtual void block_rtxn_abort() const {} + virtual void drop_hard_fork_info() {} virtual bool block_exists(const crypto::hash& h, uint64_t *height) const { return false; } virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); } diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 8454595ac..cb9154f29 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -194,7 +194,11 @@ int check_flush(cryptonote::core &core, std::vector<block_complete_entry> &block core.prevalidate_block_hashes(core.get_blockchain_storage().get_db().height(), hashes); std::vector<block> pblocks; - core.prepare_handle_incoming_blocks(blocks, pblocks); + if (!core.prepare_handle_incoming_blocks(blocks, pblocks)) + { + MERROR("Failed to prepare to add blocks"); + return 1; + } if (!pblocks.empty() && pblocks.size() != blocks.size()) { MERROR("Unexpected parsed blocks size"); diff --git a/src/common/combinator.h b/src/common/combinator.h index 72c6800d5..ba851bd81 100644 --- a/src/common/combinator.h +++ b/src/common/combinator.h @@ -32,6 +32,7 @@ #include <iostream> #include <vector> +#include <stdexcept> namespace tools { diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index 1a1155c7c..5e03bf897 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -33,7 +33,7 @@ #include <stdlib.h> #include "include_base_utils.h" #include "common/threadpool.h" -#include <random> +#include "crypto/crypto.h" #include <boost/thread/mutex.hpp> #include <boost/algorithm/string/join.hpp> #include <boost/optional.hpp> @@ -517,10 +517,7 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std std::vector<std::vector<std::string> > records; records.resize(dns_urls.size()); - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1); - size_t first_index = dis(gen); + size_t first_index = crypto::rand_idx(dns_urls.size()); // send all requests in parallel std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false); diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 22b182ab0..bac456f60 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -35,6 +35,7 @@ #include <boost/optional.hpp> #include <type_traits> #include <vector> +#include <random> #include "common/pod-class.h" #include "memwipe.h" @@ -162,6 +163,32 @@ namespace crypto { return res; } + /* UniformRandomBitGenerator using crypto::rand<uint64_t>() + */ + struct random_device + { + typedef uint64_t result_type; + static constexpr result_type min() { return 0; } + static constexpr result_type max() { return result_type(-1); } + result_type operator()() const { return crypto::rand<result_type>(); } + }; + + /* Generate a random value between range_min and range_max + */ + template<typename T> + typename std::enable_if<std::is_integral<T>::value, T>::type rand_range(T range_min, T range_max) { + crypto::random_device rd; + std::uniform_int_distribution<T> dis(range_min, range_max); + return dis(rd); + } + + /* Generate a random index between 0 and sz-1 + */ + template<typename T> + typename std::enable_if<std::is_unsigned<T>::value, T>::type rand_idx(T sz) { + return crypto::rand_range<T>(0, sz-1); + } + /* Generate a new key pair */ inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) { diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp index 5162e53e6..859173aa5 100644 --- a/src/cryptonote_basic/difficulty.cpp +++ b/src/cryptonote_basic/difficulty.cpp @@ -239,4 +239,19 @@ namespace cryptonote { return res.convert_to<difficulty_type>(); } + std::string hex(difficulty_type v) + { + static const char chars[] = "0123456789abcdef"; + std::string s; + while (v > 0) + { + s.push_back(chars[(v & 0xf).convert_to<unsigned>()]); + v >>= 4; + } + if (s.empty()) + s += "0"; + std::reverse(s.begin(), s.end()); + return "0x" + s; + } + } diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h index f7a9376fb..02ed89e5a 100644 --- a/src/cryptonote_basic/difficulty.h +++ b/src/cryptonote_basic/difficulty.h @@ -32,6 +32,7 @@ #include <cstdint> #include <vector> +#include <string> #include <boost/multiprecision/cpp_int.hpp> #include "crypto/hash.h" @@ -58,4 +59,6 @@ namespace cryptonote bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty); bool check_hash(const crypto::hash &hash, difficulty_type difficulty); difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds); + + std::string hex(difficulty_type v); } diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp index 89bca2f09..61240ea37 100644 --- a/src/cryptonote_basic/hardfork.cpp +++ b/src/cryptonote_basic/hardfork.cpp @@ -266,11 +266,9 @@ bool HardFork::reorganize_from_chain_height(uint64_t height) bool HardFork::rescan_from_block_height(uint64_t height) { CRITICAL_REGION_LOCAL(lock); - db.block_txn_start(true); - if (height >= db.height()) { - db.block_txn_stop(); + db_rtxn_guard rtxn_guard(&db); + if (height >= db.height()) return false; - } versions.clear(); @@ -293,8 +291,6 @@ bool HardFork::rescan_from_block_height(uint64_t height) current_fork_index = voted; } - db.block_txn_stop(); - return true; } diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index fb96de226..2cbe89b01 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -30,6 +30,7 @@ set(cryptonote_core_sources blockchain.cpp cryptonote_core.cpp tx_pool.cpp + tx_sanity_check.cpp cryptonote_tx_utils.cpp) set(cryptonote_core_headers) @@ -39,6 +40,7 @@ set(cryptonote_core_private_headers blockchain.h cryptonote_core.h tx_pool.h + tx_sanity_check.h cryptonote_tx_utils.h) monero_private_headers(cryptonote_core diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 7ef8f8c45..51fd9fe16 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -428,6 +428,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline block bl; block_verification_context bvc = boost::value_initialized<block_verification_context>(); generate_genesis_block(bl, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE); + db_wtxn_guard wtxn_guard(m_db); add_new_block(bl, bvc); CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "Failed to add genesis block to blockchain"); } @@ -443,7 +444,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline m_db->fixup(); } - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard(m_db); + // check how far behind we are uint64_t top_block_timestamp = m_db->get_top_block_timestamp(); uint64_t timestamp_diff = time(NULL) - top_block_timestamp; @@ -464,7 +466,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline #endif MINFO("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block()); - m_db->block_txn_stop(); + + rtxn_guard.stop(); uint64_t num_popped_blocks = 0; while (!m_db->is_read_only()) @@ -518,8 +521,11 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline if (test_options && test_options->long_term_block_weight_window) m_long_term_block_weights_window = test_options->long_term_block_weight_window; - if (!update_next_cumulative_weight_limit()) - return false; + { + db_txn_guard txn_guard(m_db, m_db->is_read_only()); + if (!update_next_cumulative_weight_limit()) + return false; + } return true; } //------------------------------------------------------------------ @@ -725,6 +731,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b) m_db->reset(); m_hardfork->init(); + db_wtxn_guard wtxn_guard(m_db); block_verification_context bvc = boost::value_initialized<block_verification_context>(); add_new_block(b, bvc); if (!update_next_cumulative_weight_limit()) @@ -772,7 +779,7 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const if(!sz) return true; - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard(m_db); bool genesis_included = false; uint64_t current_back_offset = 1; while(current_back_offset < sz) @@ -799,7 +806,6 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const { ids.push_back(m_db->get_block_hash_from_height(0)); } - m_db->block_txn_stop(); return true; } @@ -1866,7 +1872,7 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO { LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_blockchain_lock); - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard (m_db); rsp.current_blockchain_height = get_current_blockchain_height(); std::vector<std::pair<cryptonote::blobdata,block>> blocks; get_blocks(arg.blocks, blocks, rsp.missed_ids); @@ -1893,7 +1899,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO // as done below if any standalone transactions were requested // and missed. rsp.missed_ids.insert(rsp.missed_ids.end(), missed_tx_ids.begin(), missed_tx_ids.end()); - m_db->block_txn_stop(); return false; } @@ -1903,7 +1908,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO //get and pack other transactions, if needed get_transactions_blobs(arg.txs, rsp.txs, rsp.missed_ids); - m_db->block_txn_stop(); return true; } //------------------------------------------------------------------ @@ -2075,14 +2079,13 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc return false; } - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard(m_db); // make sure that the last block in the request's block list matches // the genesis block auto gen_hash = m_db->get_block_hash_from_height(0); if(qblock_ids.back() != gen_hash) { MCERROR("net.p2p", "Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block mismatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection"); - m_db->block_txn_abort(); return false; } @@ -2100,11 +2103,9 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc catch (const std::exception& e) { MWARNING("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it); - m_db->block_txn_abort(); return false; } } - m_db->block_txn_stop(); // this should be impossible, as we checked that we share the genesis block, // but just in case... @@ -2295,7 +2296,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc return false; } - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard(m_db); current_height = get_current_blockchain_height(); const uint32_t pruning_seed = get_blockchain_pruning_seed(); start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed); @@ -2307,7 +2308,6 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc hashes.push_back(m_db->get_block_hash_from_height(i)); } - m_db->block_txn_stop(); return true; } @@ -2354,7 +2354,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons } } - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard(m_db); total_height = get_current_blockchain_height(); size_t count = 0, size = 0; blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height))); @@ -2380,7 +2380,6 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons blocks.back().second.push_back(std::make_pair(b.tx_hashes[i], std::move(txs[i]))); } } - m_db->block_txn_stop(); return true; } //------------------------------------------------------------------ @@ -3535,7 +3534,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& static bool seen_future_version = false; - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard(m_db); uint64_t blockchain_height; const crypto::hash top_hash = get_tail_id(blockchain_height); ++blockchain_height; // block height to chain height @@ -3544,7 +3543,6 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& MERROR_VER("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << top_hash); bvc.m_verifivation_failed = true; leave: - m_db->block_txn_stop(); return false; } @@ -3827,7 +3825,7 @@ leave: if(precomputed) block_processing_time += m_fake_pow_calc_time; - m_db->block_txn_stop(); + rtxn_guard.stop(); TIME_MEASURE_START(addblock); uint64_t new_height = 0; if (!bvc.m_verifivation_failed) @@ -3945,8 +3943,6 @@ 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(); @@ -3990,7 +3986,6 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti new_weights[0] = long_term_block_weight; long_term_median = epee::misc_utils::median(new_weights); m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median); - short_term_constraint = m_long_term_effective_median_block_weight + m_long_term_effective_median_block_weight * 2 / 5; weights.clear(); get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW); @@ -4009,9 +4004,8 @@ 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(); + if (!m_db->is_read_only()) + m_db->add_max_block_size(m_current_block_cumul_weight_limit); return true; } @@ -4022,12 +4016,11 @@ bool Blockchain::add_new_block(const block& bl, block_verification_context& bvc) crypto::hash id = get_block_hash(bl); CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process CRITICAL_REGION_LOCAL1(m_blockchain_lock); - m_db->block_txn_start(true); + db_rtxn_guard rtxn_guard(m_db); if(have_block(id)) { LOG_PRINT_L3("block with id = " << id << " already exists"); bvc.m_already_exists = true; - m_db->block_txn_stop(); m_blocks_txs_check.clear(); return false; } @@ -4037,14 +4030,14 @@ bool Blockchain::add_new_block(const block& bl, block_verification_context& bvc) { //chain switching or wrong block bvc.m_added_to_main_chain = false; - m_db->block_txn_stop(); + rtxn_guard.stop(); bool r = handle_alternative_block(bl, id, bvc); m_blocks_txs_check.clear(); return r; //never relay alternative blocks } - m_db->block_txn_stop(); + rtxn_guard.stop(); return handle_block_to_main_chain(bl, id, bvc); } //------------------------------------------------------------------ diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 91dea4982..be1ea5a17 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1609,6 +1609,9 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool core::check_fork_time() { + if (m_nettype == FAKECHAIN) + return true; + HardFork::State state = m_blockchain_storage.get_hard_fork_state(); const el::Level level = el::Level::Warning; switch (state) { @@ -1824,7 +1827,7 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool core::check_block_rate() { - if (m_offline || m_target_blockchain_height > get_current_blockchain_height()) + if (m_offline || m_nettype == FAKECHAIN || m_target_blockchain_height > get_current_blockchain_height()) { MDEBUG("Not checking block rate, offline or syncing"); return true; diff --git a/src/cryptonote_core/tx_sanity_check.cpp b/src/cryptonote_core/tx_sanity_check.cpp new file mode 100644 index 000000000..d3b225f1c --- /dev/null +++ b/src/cryptonote_core/tx_sanity_check.cpp @@ -0,0 +1,100 @@ +// Copyright (c) 2019, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <stdint.h> +#include <vector> +#include "cryptonote_basic/cryptonote_basic_impl.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "blockchain.h" +#include "tx_sanity_check.h" + +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "txsanity" + +namespace cryptonote +{ + +bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob) +{ + cryptonote::transaction tx; + + if (!cryptonote::parse_and_validate_tx_from_blob(tx_blob, tx)) + { + MERROR("Failed to parse transaction"); + return false; + } + + if (cryptonote::is_coinbase(tx)) + { + MERROR("Transaction is coinbase"); + return false; + } + std::set<uint64_t> rct_indices; + size_t n_indices = 0; + + for (const auto &txin : tx.vin) + { + if (txin.type() != typeid(cryptonote::txin_to_key)) + continue; + const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(txin); + if (in_to_key.amount != 0) + continue; + const std::vector<uint64_t> absolute = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets); + for (uint64_t offset: absolute) + rct_indices.insert(offset); + n_indices += in_to_key.key_offsets.size(); + } + + if (n_indices <= 10) + { + MERROR("n_indices is only " << n_indices); + return true; + } + + uint64_t n_available = blockchain.get_num_mature_outputs(0); + if (n_available < 10000) + return true; + + if (rct_indices.size() < n_indices * 9 / 10) + { + MERROR("unique indices is only " << rct_indices.size() << "/" << n_indices); + return false; + } + + std::vector<uint64_t> offsets(rct_indices.begin(), rct_indices.end()); + uint64_t median = epee::misc_utils::median(offsets); + if (median < n_available * 9 / 10) + { + MERROR("median is " << median << "/" << n_available); + return false; + } + + return true; +} + +} diff --git a/src/cryptonote_core/tx_sanity_check.h b/src/cryptonote_core/tx_sanity_check.h new file mode 100644 index 000000000..c12d1b0b1 --- /dev/null +++ b/src/cryptonote_core/tx_sanity_check.h @@ -0,0 +1,36 @@ +// Copyright (c) 2019, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "cryptonote_basic/blobdatatype.h" + +namespace cryptonote +{ + class Blockchain; + + bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob); +} diff --git a/src/device/device.hpp b/src/device/device.hpp index 2e485b1d6..866e2c676 100644 --- a/src/device/device.hpp +++ b/src/device/device.hpp @@ -76,6 +76,7 @@ namespace hw { class i_device_callback { public: virtual void on_button_request(uint64_t code=0) {} + virtual void on_button_pressed() {} virtual boost::optional<epee::wipeable_string> on_pin_request() { return boost::none; } virtual boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) { return boost::none; } virtual void on_progress(const device_progress& event) {} diff --git a/src/device_trezor/device_trezor_base.cpp b/src/device_trezor/device_trezor_base.cpp index f3d15c5e2..58abde1d1 100644 --- a/src/device_trezor/device_trezor_base.cpp +++ b/src/device_trezor/device_trezor_base.cpp @@ -43,7 +43,7 @@ namespace trezor { const uint32_t device_trezor_base::DEFAULT_BIP44_PATH[] = {0x8000002c, 0x80000080}; - device_trezor_base::device_trezor_base(): m_callback(nullptr) { + device_trezor_base::device_trezor_base(): m_callback(nullptr), m_last_msg_type(messages::MessageType_Success) { #ifdef WITH_TREZOR_DEBUGGING m_debug = false; #endif @@ -275,6 +275,12 @@ namespace trezor { // Later if needed this generic message handler can be replaced by a pointer to // a protocol message handler which by default points to the device class which implements // the default handler. + + if (m_last_msg_type == messages::MessageType_ButtonRequest){ + on_button_pressed(); + } + m_last_msg_type = input.m_type; + switch(input.m_type){ case messages::MessageType_ButtonRequest: on_button_request(input, dynamic_cast<const messages::common::ButtonRequest*>(input.m_msg.get())); @@ -413,6 +419,11 @@ namespace trezor { resp = read_raw(); } + void device_trezor_base::on_button_pressed() + { + TREZOR_CALLBACK(on_button_pressed); + } + void device_trezor_base::on_pin_request(GenericMessage & resp, const messages::common::PinMatrixRequest * msg) { MDEBUG("on_pin_request"); diff --git a/src/device_trezor/device_trezor_base.hpp b/src/device_trezor/device_trezor_base.hpp index 8c3c14b29..c106d2099 100644 --- a/src/device_trezor/device_trezor_base.hpp +++ b/src/device_trezor/device_trezor_base.hpp @@ -98,6 +98,7 @@ namespace trezor { std::shared_ptr<messages::management::Features> m_features; // features from the last device reset boost::optional<epee::wipeable_string> m_pin; boost::optional<epee::wipeable_string> m_passphrase; + messages::MessageType m_last_msg_type; cryptonote::network_type network_type; @@ -311,6 +312,7 @@ namespace trezor { // Protocol callbacks void on_button_request(GenericMessage & resp, const messages::common::ButtonRequest * msg); + void on_button_pressed(); void on_pin_request(GenericMessage & resp, const messages::common::PinMatrixRequest * msg); void on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg); void on_passphrase_state_request(GenericMessage & resp, const messages::common::PassphraseStateRequest * msg); diff --git a/src/device_trezor/trezor/transport.cpp b/src/device_trezor/trezor/transport.cpp index 991ba3395..dd9b0b52f 100644 --- a/src/device_trezor/trezor/transport.cpp +++ b/src/device_trezor/trezor/transport.cpp @@ -223,6 +223,11 @@ namespace trezor{ msg = msg_wrap; } + static void assert_port_number(uint32_t port) + { + CHECK_AND_ASSERT_THROW_MES(port >= 1024 && port < 65535, "Invalid port number: " << port); + } + Transport::Transport(): m_open_counter(0) { } @@ -263,6 +268,29 @@ namespace trezor{ const char * BridgeTransport::PATH_PREFIX = "bridge:"; + BridgeTransport::BridgeTransport( + boost::optional<std::string> device_path, + boost::optional<std::string> bridge_host): + m_device_path(device_path), + m_bridge_host(bridge_host ? bridge_host.get() : DEFAULT_BRIDGE), + m_response(boost::none), + m_session(boost::none), + m_device_info(boost::none) + { + const char *env_bridge_port = nullptr; + if (!bridge_host && (env_bridge_port = getenv("TREZOR_BRIDGE_PORT")) != nullptr) + { + uint16_t bridge_port; + CHECK_AND_ASSERT_THROW_MES(epee::string_tools::get_xtype_from_string(bridge_port, env_bridge_port), "Invalid bridge port: " << env_bridge_port); + assert_port_number(bridge_port); + + m_bridge_host = std::string("127.0.0.1:") + boost::lexical_cast<std::string>(env_bridge_port); + MDEBUG("Bridge host: " << m_bridge_host); + } + + m_http_client.set_server(m_bridge_host, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_disabled); + } + std::string BridgeTransport::get_path() const { if (!m_device_path){ return ""; @@ -401,28 +429,40 @@ namespace trezor{ const char * UdpTransport::DEFAULT_HOST = "127.0.0.1"; const int UdpTransport::DEFAULT_PORT = 21324; + static void parse_udp_path(std::string &host, int &port, std::string path) + { + if (boost::starts_with(path, UdpTransport::PATH_PREFIX)) + { + path = path.substr(strlen(UdpTransport::PATH_PREFIX)); + } + + auto delim = path.find(':'); + if (delim == std::string::npos) { + host = path; + } else { + host = path.substr(0, delim); + port = std::stoi(path.substr(delim + 1)); + } + } + UdpTransport::UdpTransport(boost::optional<std::string> device_path, boost::optional<std::shared_ptr<Protocol>> proto) : m_io_service(), m_deadline(m_io_service) { + m_device_host = DEFAULT_HOST; m_device_port = DEFAULT_PORT; + const char *env_trezor_path = nullptr; + if (device_path) { - const std::string device_str = device_path.get(); - auto delim = device_str.find(':'); - if (delim == std::string::npos) { - m_device_host = device_str; - } else { - m_device_host = device_str.substr(0, delim); - m_device_port = std::stoi(device_str.substr(delim + 1)); - } + parse_udp_path(m_device_host, m_device_port, device_path.get()); + } else if ((env_trezor_path = getenv("TREZOR_PATH")) != nullptr && boost::starts_with(env_trezor_path, UdpTransport::PATH_PREFIX)){ + parse_udp_path(m_device_host, m_device_port, std::string(env_trezor_path)); + MDEBUG("Applied TREZOR_PATH: " << m_device_host << ":" << m_device_port); } else { m_device_host = DEFAULT_HOST; } - if (m_device_port <= 1024 || m_device_port > 65535){ - throw std::invalid_argument("Port number invalid"); - } - + assert_port_number((uint32_t)m_device_port); if (m_device_host != "localhost" && m_device_host != DEFAULT_HOST){ throw std::invalid_argument("Local endpoint allowed only"); } diff --git a/src/device_trezor/trezor/transport.hpp b/src/device_trezor/trezor/transport.hpp index 2945b3184..cde862547 100644 --- a/src/device_trezor/trezor/transport.hpp +++ b/src/device_trezor/trezor/transport.hpp @@ -163,15 +163,7 @@ namespace trezor { public: BridgeTransport( boost::optional<std::string> device_path = boost::none, - boost::optional<std::string> bridge_host = boost::none): - m_device_path(device_path), - m_bridge_host(bridge_host ? bridge_host.get() : DEFAULT_BRIDGE), - m_response(boost::none), - m_session(boost::none), - m_device_info(boost::none) - { - m_http_client.set_server(m_bridge_host, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_disabled); - } + boost::optional<std::string> bridge_host = boost::none); virtual ~BridgeTransport() = default; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index f0aef384f..be97edbe5 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -176,8 +176,15 @@ namespace nodetool if(!addr.is_blockable()) return false; + const time_t now = time(nullptr); + CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); - m_blocked_hosts[addr.host_str()] = time(nullptr) + seconds; + time_t limit; + if (now > std::numeric_limits<time_t>::max() - seconds) + limit = std::numeric_limits<time_t>::max(); + else + limit = now + seconds; + m_blocked_hosts[addr.host_str()] = limit; // drop any connection to that address. This should only have to look into // the zone related to the connection, but really make sure everything is @@ -1259,7 +1266,7 @@ namespace nodetool } } else - random_index = crypto::rand<size_t>() % filtered.size(); + random_index = crypto::rand_idx(filtered.size()); CHECK_AND_ASSERT_MES(random_index < filtered.size(), false, "random_index < filtered.size() failed!!"); random_index = filtered[random_index]; @@ -1313,7 +1320,7 @@ namespace nodetool return true; size_t try_count = 0; - size_t current_index = crypto::rand<size_t>()%m_seed_nodes.size(); + size_t current_index = crypto::rand_idx(m_seed_nodes.size()); const net_server& server = m_network_zones.at(epee::net_utils::zone::public_).m_net_server; while(true) { diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index ebe0268d8..52814af94 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -398,7 +398,7 @@ namespace nodetool return false; } - size_t random_index = crypto::rand<size_t>() % m_peers_gray.size(); + size_t random_index = crypto::rand_idx(m_peers_gray.size()); peers_indexed::index<by_time>::type& by_time_index = m_peers_gray.get<by_time>(); pe = *epee::misc_utils::move_it_backward(--by_time_index.end(), random_index); diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index e877c13ce..ff2a81d43 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -695,6 +695,7 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(mixRing[n].size() == inSk.size(), "Bad mixRing size"); } CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present"); + CHECK_AND_ASSERT_THROW_MES(inSk.size() < 2, "genRct is not suitable for 2+ rings"); rctSig rv; rv.type = RCTTypeFull; diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 50d0f4d91..e5413f1dc 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -191,6 +191,8 @@ namespace rct { Bulletproof(const rct::keyV &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t): V(V), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {} + bool operator==(const Bulletproof &other) const { return V == other.V && A == other.A && S == other.S && T1 == other.T1 && T2 == other.T2 && taux == other.taux && mu == other.mu && L == other.L && R == other.R && a == other.a && b == other.b && t == other.t; } + BEGIN_SERIALIZE_OBJECT() // Commitments aren't saved, they're restored via outPk // FIELD(V) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 71bfcc950..c45cb27f3 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -41,6 +41,7 @@ using namespace epee; #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/account.h" #include "cryptonote_basic/cryptonote_basic_impl.h" +#include "cryptonote_core/tx_sanity_check.h" #include "misc_language.h" #include "net/parse.h" #include "storages/http_abstract_invoke.h" @@ -74,7 +75,7 @@ namespace void store_difficulty(cryptonote::difficulty_type difficulty, uint64_t &sdiff, std::string &swdiff, uint64_t &stop64) { sdiff = (difficulty << 64 >> 64).convert_to<uint64_t>(); - swdiff = difficulty.convert_to<std::string>(); + swdiff = cryptonote::hex(difficulty); stop64 = (difficulty >> 64).convert_to<uint64_t>(); } } @@ -204,6 +205,7 @@ namespace cryptonote crypto::hash hash; m_core.get_blockchain_top(res.height, hash); + ++res.height; // block height to chain height res.hash = string_tools::pod_to_hex(hash); res.status = CORE_RPC_STATUS_OK; return true; @@ -844,6 +846,14 @@ namespace cryptonote return true; } + if (req.do_sanity_checks && !cryptonote::tx_sanity_check(m_core.get_blockchain_storage(), tx_blob)) + { + res.status = "Failed"; + res.reason = "Sanity check failed"; + res.sanity_check_failed = true; + return true; + } + cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context); tx_verification_context tvc = AUTO_VAL_INIT(tvc); if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed) @@ -1295,7 +1305,10 @@ namespace cryptonote LOG_ERROR("Failed to find tx pub key in blockblob"); return false; } - res.reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte) + if (req.reserve_size) + res.reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte) + else + res.reserved_offset = 0; if(res.reserved_offset + req.reserve_size > block_blob.size()) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index d2aba8d67..a1e2fdf8d 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -577,10 +577,12 @@ namespace cryptonote { std::string tx_as_hex; bool do_not_relay; + bool do_sanity_checks; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_as_hex) KV_SERIALIZE_OPT(do_not_relay, false) + KV_SERIALIZE_OPT(do_sanity_checks, true) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -599,6 +601,7 @@ namespace cryptonote bool overspend; bool fee_too_low; bool not_rct; + bool sanity_check_failed; bool untrusted; BEGIN_KV_SERIALIZE_MAP() @@ -613,6 +616,7 @@ namespace cryptonote KV_SERIALIZE(overspend) KV_SERIALIZE(fee_too_low) KV_SERIALIZE(not_rct) + KV_SERIALIZE(sanity_check_failed) KV_SERIALIZE(untrusted) END_KV_SERIALIZE_MAP() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 66317adcb..8c8afba56 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -118,7 +118,7 @@ typedef cryptonote::simple_wallet sw; if (!m_long_payment_id_support) { \ fail_msg_writer() << tr("Warning: Long payment IDs are obsolete."); \ fail_msg_writer() << tr("Long payment IDs are not encrypted on the blockchain, and will harm your privacy."); \ - fail_msg_writer() << tr("Use --long-payment-id-support if you really must use one, and warn the recipient they are using an obsolete feature that will disappear in the future."); \ + fail_msg_writer() << tr("Use --long-payment-id-support-bad-for-privacy if you really must use one, and warn the recipient they are using an obsolete feature that will disappear in the future."); \ return true; \ } \ } while(0) @@ -3189,10 +3189,11 @@ simple_wallet::simple_wallet() 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("welcome", boost::bind(&simple_wallet::welcome, this, _1), tr(USAGE_WELCOME), - tr("Prints simple network stats")); + tr("Prints basic info about Monero for first time users")); m_cmd_binder.set_handler("version", boost::bind(&simple_wallet::version, this, _1), tr(USAGE_VERSION), @@ -5064,8 +5065,7 @@ bool simple_wallet::refresh_main(uint64_t start_height, enum ResetType reset, bo LOCK_IDLE_SCOPE(); crypto::hash transfer_hash_pre{}; - uint64_t height_pre, height_post; - + uint64_t height_pre = 0, height_post; if (reset != ResetNone) { if (reset == ResetSoftKeepKI) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index c1303c225..032b873d6 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -249,6 +249,13 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback } } + virtual void on_device_button_pressed() + { + if (m_listener) { + m_listener->onDeviceButtonPressed(); + } + } + virtual boost::optional<epee::wipeable_string> on_device_pin_request() { if (m_listener) { @@ -449,6 +456,11 @@ WalletImpl::~WalletImpl() close(false); // do not store wallet as part of the closing activities // Stop refresh thread stopRefresh(); + + if (m_wallet2Callback->getListener()) { + m_wallet2Callback->getListener()->onSetWallet(nullptr); + } + LOG_PRINT_L1(__FUNCTION__ << " finished"); } diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index ee1d6ae79..0af3b1867 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -37,6 +37,7 @@ #include <set> #include <ctime> #include <iostream> +#include <stdexcept> // Public interface for libwallet library namespace Monero { @@ -337,6 +338,7 @@ protected: bool m_indeterminate; }; +struct Wallet; struct WalletListener { virtual ~WalletListener() = 0; @@ -381,7 +383,12 @@ struct WalletListener /** * @brief called by device if the action is required */ - virtual void onDeviceButtonRequest(uint64_t code) {} + virtual void onDeviceButtonRequest(uint64_t code) { (void)code; } + + /** + * @brief called by device if the button was pressed + */ + virtual void onDeviceButtonPressed() { } /** * @brief called by device when PIN is needed @@ -401,7 +408,12 @@ struct WalletListener /** * @brief Signalizes device operation progress */ - virtual void onDeviceProgress(const DeviceProgress & event) {}; + virtual void onDeviceProgress(const DeviceProgress & event) { (void)event; }; + + /** + * @brief If the listener is created before the wallet this enables to set created wallet object + */ + virtual void onSetWallet(Wallet * wallet) { (void)wallet; }; }; @@ -440,8 +452,8 @@ struct Wallet //! returns both error and error string atomically. suggested to use in instead of status() and errorString() virtual void statusWithErrorString(int& status, std::string& errorString) const = 0; virtual bool setPassword(const std::string &password) = 0; - virtual bool setDevicePin(const std::string &password) { return false; }; - virtual bool setDevicePassphrase(const std::string &password) { return false; }; + virtual bool setDevicePin(const std::string &pin) { (void)pin; return false; }; + virtual bool setDevicePassphrase(const std::string &passphrase) { (void)passphrase; return false; }; virtual std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const = 0; std::string mainAddress() const { return address(0, 0); } virtual std::string path() const = 0; @@ -1020,9 +1032,10 @@ struct WalletManager * \param password Password of wallet file * \param nettype Network type * \param kdf_rounds Number of rounds for key derivation function + * \param listener Wallet listener to set to the wallet after creation * \return Wallet instance (Wallet::status() needs to be called to check if opened successfully) */ - virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) = 0; + virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1, WalletListener * listener = nullptr) = 0; Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) // deprecated { return openWallet(path, password, testnet ? TESTNET : MAINNET); @@ -1134,6 +1147,7 @@ struct WalletManager * \param restoreHeight restore from start height (0 sets to current height) * \param subaddressLookahead Size of subaddress lookahead (empty sets to some default low value) * \param kdf_rounds Number of rounds for key derivation function + * \param listener Wallet listener to set to the wallet after creation * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ virtual Wallet * createWalletFromDevice(const std::string &path, @@ -1142,7 +1156,8 @@ struct WalletManager const std::string &deviceName, uint64_t restoreHeight = 0, const std::string &subaddressLookahead = "", - uint64_t kdf_rounds = 1) = 0; + uint64_t kdf_rounds = 1, + WalletListener * listener = nullptr) = 0; /*! * \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index f584e88ac..ef2ed2015 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -57,9 +57,14 @@ Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::stri return wallet; } -Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds) +Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds, WalletListener * listener) { WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); + wallet->setListener(listener); + if (listener){ + listener->onSetWallet(wallet); + } + wallet->open(path, password); //Refresh addressBook wallet->addressBook()->refresh(); @@ -122,9 +127,15 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path, const std::string &deviceName, uint64_t restoreHeight, const std::string &subaddressLookahead, - uint64_t kdf_rounds) + uint64_t kdf_rounds, + WalletListener * listener) { WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); + wallet->setListener(listener); + if (listener){ + listener->onSetWallet(wallet); + } + if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } else { diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index 0c83d794f..235f96e17 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -40,7 +40,7 @@ class WalletManagerImpl : public WalletManager public: Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) override; - Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) override; + Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1, WalletListener * listener = nullptr) override; virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, @@ -72,7 +72,8 @@ public: const std::string &deviceName, uint64_t restoreHeight = 0, const std::string &subaddressLookahead = "", - uint64_t kdf_rounds = 1) override; + uint64_t kdf_rounds = 1, + WalletListener * listener = nullptr) override; virtual bool closeWallet(Wallet *wallet, bool store = true) override; bool walletExists(const std::string &path) override; bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const override; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index dfcc61426..ea0e6629a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -265,6 +265,7 @@ struct options { const command_line::arg_descriptor<std::string> hw_device = {"hw-device", tools::wallet2::tr("HW device to use"), ""}; const command_line::arg_descriptor<std::string> hw_device_derivation_path = {"hw-device-deriv-path", tools::wallet2::tr("HW device wallet derivation path (e.g., SLIP-10)"), ""}; const command_line::arg_descriptor<std::string> tx_notify = { "tx-notify" , "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" , "" }; + const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false}; }; void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file) @@ -452,6 +453,9 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl wallet->device_name(device_name); wallet->device_derivation_path(device_derivation_path); + if (command_line::get_arg(vm, opts.no_dns)) + wallet->enable_dns(false); + try { if (!command_line::is_arg_defaulted(vm, opts.tx_notify)) @@ -788,7 +792,7 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra // pseudoOuts size += 32 * n_inputs; // ecdhInfo - size += 2 * 32 * n_outputs; + size += 8 * n_outputs; // outPk - only commitment is saved size += 32 * n_outputs; // txnFee @@ -992,6 +996,12 @@ void wallet_device_callback::on_button_request(uint64_t code) wallet->on_device_button_request(code); } +void wallet_device_callback::on_button_pressed() +{ + if (wallet) + wallet->on_device_button_pressed(); +} + boost::optional<epee::wipeable_string> wallet_device_callback::on_pin_request() { if (wallet) @@ -1072,7 +1082,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended): m_encrypt_keys_after_refresh(boost::none), m_unattended(unattended), m_devices_registered(false), - m_device_last_key_image_sync(0) + m_device_last_key_image_sync(0), + m_use_dns(true) { } @@ -1127,6 +1138,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par command_line::add_arg(desc_params, opts.hw_device); command_line::add_arg(desc_params, opts.hw_device_derivation_path); command_line::add_arg(desc_params, opts.tx_notify); + command_line::add_arg(desc_params, opts.no_dns); } std::pair<std::unique_ptr<wallet2>, tools::password_container> wallet2::make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) @@ -5773,7 +5785,7 @@ namespace { CHECK_AND_ASSERT_MES(!vec.empty(), T(), "Vector must be non-empty"); - size_t idx = crypto::rand<size_t>() % vec.size(); + size_t idx = crypto::rand_idx(vec.size()); return pop_index (vec, idx); } @@ -5876,7 +5888,7 @@ size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::ve } else { - idx = crypto::rand<size_t>() % candidates.size(); + idx = crypto::rand_idx(candidates.size()); } return pop_index (unused_indices, candidates[idx]); } @@ -5988,6 +6000,7 @@ void wallet2::commit_tx(pending_tx& ptx) COMMAND_RPC_SEND_RAW_TX::request req; req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); req.do_not_relay = false; + req.do_sanity_checks = true; COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json("/sendrawtransaction", req, daemon_send_resp, m_http_client, rpc_timeout); @@ -7565,7 +7578,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> if (n_rct == 0) return rct_offsets[block_offset] ? rct_offsets[block_offset] - 1 : 0; MDEBUG("Picking 1/" << n_rct << " in " << (last_block_offset - first_block_offset + 1) << " blocks centered around " << block_offset + rct_start_height); - return first_rct + crypto::rand<uint64_t>() % n_rct; + return first_rct + crypto::rand_idx(n_rct); }; size_t num_selected_transfers = 0; @@ -9621,14 +9634,16 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, s change -= r.second.first; MDEBUG("Adding " << cryptonote::print_money(change) << " expected change"); + // for all txes that have actual change, check change is coming back to the sending wallet for (const pending_tx &ptx: ptx_vector) - THROW_WALLET_EXCEPTION_IF(ptx.change_dts.addr != ptx_vector[0].change_dts.addr, error::wallet_internal_error, - "Change goes to several different addresses"); - const auto it = m_subaddresses.find(ptx_vector[0].change_dts.addr.m_spend_public_key); - THROW_WALLET_EXCEPTION_IF(change > 0 && it == m_subaddresses.end(), error::wallet_internal_error, "Change address is not ours"); - - required[ptx_vector[0].change_dts.addr].first += change; - required[ptx_vector[0].change_dts.addr].second = ptx_vector[0].change_dts.is_subaddress; + { + if (ptx.change_dts.amount == 0) + continue; + THROW_WALLET_EXCEPTION_IF(m_subaddresses.find(ptx.change_dts.addr.m_spend_public_key) == m_subaddresses.end(), + error::wallet_internal_error, "Change address is not ours"); + required[ptx.change_dts.addr].first += ptx.change_dts.amount; + required[ptx.change_dts.addr].second = ptx.change_dts.is_subaddress; + } for (const auto &r: required) { @@ -9694,7 +9709,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below if (unused_transfer_dust_indices_per_subaddr.count(0) == 1 && unused_transfer_dust_indices_per_subaddr.size() > 1) unused_transfer_dust_indices_per_subaddr.erase(0); auto i = unused_transfer_dust_indices_per_subaddr.begin(); - std::advance(i, crypto::rand<size_t>() % unused_transfer_dust_indices_per_subaddr.size()); + std::advance(i, crypto::rand_idx(unused_transfer_dust_indices_per_subaddr.size())); unused_transfers_indices = i->second.first; unused_dust_indices = i->second.second; LOG_PRINT_L2("Spending from subaddress index " << i->first); @@ -12018,14 +12033,15 @@ void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vect m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx); } //---------------------------------------------------------------------------------------------------- -std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs() const +std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const { PERF_TIMER(export_outputs); std::vector<tools::wallet2::transfer_details> outs; size_t offset = 0; - while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request)) - ++offset; + if (!all) + while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request)) + ++offset; outs.reserve(m_transfers.size() - offset); for (size_t n = offset; n < m_transfers.size(); ++n) @@ -12038,13 +12054,13 @@ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export return std::make_pair(offset, outs); } //---------------------------------------------------------------------------------------------------- -std::string wallet2::export_outputs_to_str() const +std::string wallet2::export_outputs_to_str(bool all) const { PERF_TIMER(export_outputs_to_str); std::stringstream oss; boost::archive::portable_binary_oarchive ar(oss); - const auto& outputs = export_outputs(); + const auto& outputs = export_outputs(all); ar << outputs; std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC)); @@ -12865,8 +12881,7 @@ uint64_t wallet2::get_segregation_fork_height() const if (m_segregation_height > 0) return m_segregation_height; - static const bool use_dns = true; - if (use_dns) + if (m_use_dns) { // All four MoneroPulse domains have DNSSEC on and valid static const std::vector<std::string> dns_urls = { @@ -12946,6 +12961,12 @@ void wallet2::on_device_button_request(uint64_t code) m_callback->on_device_button_request(code); } //---------------------------------------------------------------------------------------------------- +void wallet2::on_device_button_pressed() +{ + if (nullptr != m_callback) + m_callback->on_device_button_pressed(); +} +//---------------------------------------------------------------------------------------------------- boost::optional<epee::wipeable_string> wallet2::on_device_pin_request() { if (nullptr != m_callback) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c8ac7d429..032d2a663 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -105,6 +105,7 @@ namespace tools virtual void on_lw_money_spent(uint64_t height, const crypto::hash &txid, uint64_t amount) {} // Device callbacks virtual void on_device_button_request(uint64_t code) {} + virtual void on_device_button_pressed() {} virtual boost::optional<epee::wipeable_string> on_device_pin_request() { return boost::none; } virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device) { return boost::none; } virtual void on_device_progress(const hw::device_progress& event) {}; @@ -118,6 +119,7 @@ namespace tools public: wallet_device_callback(wallet2 * wallet): wallet(wallet) {}; void on_button_request(uint64_t code=0) override; + void on_button_pressed() override; boost::optional<epee::wipeable_string> on_pin_request() override; boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) override; void on_progress(const hw::device_progress& event) override; @@ -1137,8 +1139,8 @@ namespace tools bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const; // Import/Export wallet data - std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs() const; - std::string export_outputs_to_str() const; + std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const; + std::string export_outputs_to_str(bool all = false) const; size_t import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs); size_t import_outputs_from_str(const std::string &outputs_st); payment_container export_payments() const; @@ -1288,6 +1290,7 @@ namespace tools void hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const; uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const; void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash); + void enable_dns(bool enable) { m_use_dns = enable; } private: /*! @@ -1378,6 +1381,7 @@ namespace tools wallet_device_callback * get_device_callback(); void on_device_button_request(uint64_t code); + void on_device_button_pressed(); boost::optional<epee::wipeable_string> on_device_pin_request(); boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device); void on_device_progress(const hw::device_progress& event); @@ -1469,6 +1473,7 @@ namespace tools std::string m_device_name; std::string m_device_derivation_path; uint64_t m_device_last_key_image_sync; + bool m_use_dns; // Aux transaction data from device std::unordered_map<crypto::hash, std::string> m_tx_device; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 71c64d3c1..24981980c 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -2581,7 +2581,7 @@ namespace tools try { - res.outputs_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->export_outputs_to_str()); + res.outputs_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->export_outputs_to_str(req.all)); } catch (const std::exception &e) { @@ -3111,6 +3111,18 @@ namespace tools er.message = "Invalid filename"; return false; } + if (m_wallet && req.autosave_current) + { + try + { + m_wallet->store(); + } + catch (const std::exception& e) + { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); + return false; + } + } std::string wallet_file = m_wallet_dir + "/" + req.filename; { po::options_description desc("dummy"); @@ -3141,18 +3153,7 @@ namespace tools } if (m_wallet) - { - try - { - m_wallet->store(); - } - catch (const std::exception& e) - { - handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); - return false; - } delete m_wallet; - } m_wallet = wal.release(); return true; } @@ -3161,14 +3162,17 @@ namespace tools { if (!m_wallet) return not_open(er); - try - { - m_wallet->store(); - } - catch (const std::exception& e) + if (req.autosave_current) { - handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); - return false; + try + { + m_wallet->store(); + } + catch (const std::exception& e) + { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); + return false; + } } delete m_wallet; m_wallet = NULL; @@ -3385,6 +3389,20 @@ namespace tools return false; } + if (m_wallet && req.autosave_current) + { + try + { + if (!wallet_file.empty()) + m_wallet->store(); + } + catch (const std::exception &e) + { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); + return false; + } + } + try { if (!req.spendkey.empty()) @@ -3433,19 +3451,7 @@ namespace tools } if (m_wallet) - { - try - { - if (!wallet_file.empty()) - m_wallet->store(); - } - catch (const std::exception &e) - { - handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); - return false; - } delete m_wallet; - } m_wallet = wal.release(); res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); return true; @@ -3511,6 +3517,18 @@ namespace tools return false; } } + if (m_wallet && req.autosave_current) + { + try + { + m_wallet->store(); + } + catch (const std::exception &e) + { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); + return false; + } + } // process seed_offset if given { @@ -3621,18 +3639,7 @@ namespace tools } if (m_wallet) - { - try - { - m_wallet->store(); - } - catch (const std::exception &e) - { - handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR); - return false; - } delete m_wallet; - } m_wallet = wal.release(); res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); res.info = "Wallet has been restored successfully."; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index bb360ae01..8757acef2 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 9 +#define WALLET_RPC_VERSION_MINOR 10 #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 @@ -1626,7 +1626,10 @@ namespace wallet_rpc { struct request_t { + bool all; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(all) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -2043,10 +2046,12 @@ namespace wallet_rpc { std::string filename; std::string password; + bool autosave_current; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(filename) KV_SERIALIZE(password) + KV_SERIALIZE_OPT(autosave_current, true) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -2063,7 +2068,10 @@ namespace wallet_rpc { struct request_t { + bool autosave_current; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_OPT(autosave_current, true) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -2108,6 +2116,7 @@ namespace wallet_rpc std::string spendkey; std::string viewkey; std::string password; + bool autosave_current; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_OPT(restore_height, (uint64_t)0) @@ -2116,6 +2125,7 @@ namespace wallet_rpc KV_SERIALIZE(spendkey) KV_SERIALIZE(viewkey) KV_SERIALIZE(password) + KV_SERIALIZE_OPT(autosave_current, true) END_KV_SERIALIZE_MAP() }; @@ -2141,6 +2151,7 @@ namespace wallet_rpc std::string seed_offset; std::string password; std::string language; + bool autosave_current; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_OPT(restore_height, (uint64_t)0) @@ -2149,6 +2160,7 @@ namespace wallet_rpc KV_SERIALIZE(seed_offset) KV_SERIALIZE(password) KV_SERIALIZE(language) + KV_SERIALIZE_OPT(autosave_current, true) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; |