aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blockchain_db/blockchain_db.cpp4
-rw-r--r--src/blockchain_db/blockchain_db.h55
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp76
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h11
-rw-r--r--src/blockchain_db/testdb.h10
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp6
-rw-r--r--src/cryptonote_basic/hardfork.cpp30
-rw-r--r--src/cryptonote_basic/miner.cpp1
-rw-r--r--src/cryptonote_core/CMakeLists.txt2
-rw-r--r--src/cryptonote_core/blockchain.cpp71
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp5
-rw-r--r--src/cryptonote_core/tx_sanity_check.cpp100
-rw-r--r--src/cryptonote_core/tx_sanity_check.h36
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl2
-rw-r--r--src/daemon/main.cpp7
-rw-r--r--src/daemon/rpc_command_executor.cpp4
-rw-r--r--src/p2p/net_node.inl9
-rw-r--r--src/ringct/bulletproofs.cc62
-rw-r--r--src/ringct/rctSigs.cpp1
-rw-r--r--src/ringct/rctTypes.h2
-rw-r--r--src/rpc/core_rpc_server.cpp41
-rw-r--r--src/rpc/core_rpc_server.h3
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h18
-rw-r--r--src/rpc/daemon_handler.cpp2
-rw-r--r--src/simplewallet/simplewallet.cpp2
-rw-r--r--src/wallet/node_rpc_proxy.cpp13
-rw-r--r--src/wallet/node_rpc_proxy.h6
-rw-r--r--src/wallet/wallet2.cpp157
-rw-r--r--src/wallet/wallet2.h17
-rw-r--r--src/wallet/wallet_rpc_server.cpp97
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h14
32 files changed, 575 insertions, 292 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/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
index 89bca2f09..d5710f727 100644
--- a/src/cryptonote_basic/hardfork.cpp
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -185,26 +185,8 @@ void HardFork::init()
else
height = 1;
- bool populate = false;
- try
- {
- db.get_hard_fork_version(0);
- }
- catch (...) { populate = true; }
- if (populate) {
- MINFO("The DB has no hard fork info, reparsing from start");
- height = 1;
- }
- MDEBUG("reorganizing from " << height);
- if (populate) {
- reorganize_from_chain_height(height);
- // reorg will not touch the genesis block, use this as a flag for populating done
- db.set_hard_fork_version(0, original_version);
- }
- else {
- rescan_from_chain_height(height);
- }
- MDEBUG("reorganization done");
+ rescan_from_chain_height(height);
+ MDEBUG("init done");
}
uint8_t HardFork::get_block_version(uint64_t height) const
@@ -266,11 +248,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 +273,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_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index e6c6bddb6..173679e21 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -528,6 +528,7 @@ namespace cryptonote
uint32_t local_template_ver = 0;
block b;
slow_hash_allocate_state();
+ ++m_threads_active;
while(!m_stop)
{
if(m_pausers_count)//anti split workaround
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..f733efb2f 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...
@@ -2284,7 +2285,7 @@ bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container
// Find the split point between us and foreign blockchain and return
// (by reference) the most recent common block hash along with up to
// BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.
-bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height) const
+bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height, bool clip_pruned) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2295,11 +2296,15 @@ 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);
- uint64_t stop_height = tools::get_next_pruned_block_height(start_height, current_height, pruning_seed);
+ uint64_t stop_height = current_height;
+ if (clip_pruned)
+ {
+ const uint32_t pruning_seed = get_blockchain_pruning_seed();
+ start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed);
+ stop_height = tools::get_next_pruned_block_height(start_height, current_height, pruning_seed);
+ }
size_t count = 0;
hashes.reserve(std::min((size_t)(stop_height - start_height), (size_t)BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT));
for(size_t i = start_height; i < stop_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
@@ -2307,7 +2312,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;
}
@@ -2316,7 +2320,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height);
+ bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height, true);
if (result)
{
cryptonote::difficulty_type wide_cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1);
@@ -2354,7 +2358,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 +2384,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 +3538,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 +3547,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 +3829,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)
@@ -3896,6 +3898,10 @@ leave:
//------------------------------------------------------------------
bool Blockchain::prune_blockchain(uint32_t pruning_seed)
{
+ m_tx_pool.lock();
+ epee::misc_utils::auto_scope_leave_caller unlocker = epee::misc_utils::create_scope_leave_handler([&](){m_tx_pool.unlock();});
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
+
return m_db->prune_blockchain(pruning_seed);
}
//------------------------------------------------------------------
@@ -3945,8 +3951,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 +3994,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 +4012,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 +4024,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 +4038,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/blockchain.h b/src/cryptonote_core/blockchain.h
index 3588bbd1b..244e2a89a 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -394,10 +394,11 @@ namespace cryptonote
* @param hashes the hashes to be returned, return-by-reference
* @param start_height the start height, return-by-reference
* @param current_height the current blockchain height, return-by-reference
+ * @param clip_pruned whether to constrain results to unpruned data
*
* @return true if a block found in common, else false
*/
- bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height) const;
+ bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height, bool clip_pruned) const;
/**
* @brief get recent block hashes for a foreign chain
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/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index b7a50783a..7adca3158 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -2366,6 +2366,8 @@ skip:
{
MINFO("Target height decreasing from " << previous_target << " to " << target);
m_core.set_target_blockchain_height(target);
+ if (target == 0 && context.m_state > cryptonote_connection_context::state_before_handshake && !m_stopping)
+ MCWARNING("global", "monerod is now disconnected from the network");
}
m_block_queue.flush_spans(context.m_connection_id, false);
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index c3ac24b70..9e1c86b91 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -257,7 +257,12 @@ int main(int argc, char const * argv[])
bf::path log_file_path {data_dir / std::string(CRYPTONOTE_NAME ".log")};
if (!command_line::is_arg_defaulted(vm, daemon_args::arg_log_file))
log_file_path = command_line::get_arg(vm, daemon_args::arg_log_file);
- log_file_path = bf::absolute(log_file_path, relative_path_base);
+#ifdef __WIN32
+ if (!strchr(log_file_path.c_str(), '/') && !strchr(log_file_path.c_str(), '\\'))
+#else
+ if (!strchr(log_file_path.c_str(), '/'))
+#endif
+ log_file_path = bf::absolute(log_file_path, relative_path_base);
mlog_configure(log_file_path.string(), true, command_line::get_arg(vm, daemon_args::arg_max_log_file_size), command_line::get_arg(vm, daemon_args::arg_max_log_files));
// Set log level
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 5901be662..186296dc9 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -553,7 +553,7 @@ bool t_rpc_command_executor::mining_status() {
if (!mining_busy && mres.active && mres.speed > 0 && mres.block_target > 0 && mres.difficulty > 0)
{
- double ratio = mres.speed * mres.block_target / mres.difficulty;
+ double ratio = mres.speed * mres.block_target / (double)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;
@@ -2205,7 +2205,7 @@ bool t_rpc_command_executor::prune_blockchain()
}
}
- tools::success_msg_writer() << "Blockchain pruned: seed " << epee::string_tools::to_string_hex(res.pruning_seed);
+ tools::success_msg_writer() << "Blockchain pruned";
return true;
}
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 7d13b3216..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
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index e394ef088..6270d4d14 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -48,12 +48,12 @@ extern "C"
//#define DEBUG_BP
-#if 1
+#if 0
#define PERF_TIMER_START_BP(x) PERF_TIMER_START_UNIT(x, 1000000)
#define PERF_TIMER_STOP_BP(x) PERF_TIMER_STOP(x)
#else
-#define PERF_TIMER_START_BP(x) ((void*)0)
-#define PERF_TIMER_STOP_BP(x) ((void*)0)
+#define PERF_TIMER_START_BP(x) ((void)0)
+#define PERF_TIMER_STOP_BP(x) ((void)0)
#endif
#define STRAUS_SIZE_LIMIT 232
@@ -439,35 +439,35 @@ static epee::span<const rct::key> slice(const rct::keyV &a, size_t start, size_t
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1)
{
- rct::keyV data;
- data.reserve(3);
- data.push_back(hash_cache);
- data.push_back(mash0);
- data.push_back(mash1);
- return hash_cache = rct::hash_to_scalar(data);
+ rct::key data[3];
+ data[0] = hash_cache;
+ data[1] = mash0;
+ data[2] = mash1;
+ rct::hash_to_scalar(hash_cache, data, sizeof(data));
+ return hash_cache;
}
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2)
{
- rct::keyV data;
- data.reserve(4);
- data.push_back(hash_cache);
- data.push_back(mash0);
- data.push_back(mash1);
- data.push_back(mash2);
- return hash_cache = rct::hash_to_scalar(data);
+ rct::key data[4];
+ data[0] = hash_cache;
+ data[1] = mash0;
+ data[2] = mash1;
+ data[3] = mash2;
+ rct::hash_to_scalar(hash_cache, data, sizeof(data));
+ return hash_cache;
}
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2, const rct::key &mash3)
{
- rct::keyV data;
- data.reserve(5);
- data.push_back(hash_cache);
- data.push_back(mash0);
- data.push_back(mash1);
- data.push_back(mash2);
- data.push_back(mash3);
- return hash_cache = rct::hash_to_scalar(data);
+ rct::key data[5];
+ data[0] = hash_cache;
+ data[1] = mash0;
+ data[2] = mash1;
+ data[3] = mash2;
+ data[4] = mash3;
+ rct::hash_to_scalar(hash_cache, data, sizeof(data));
+ return hash_cache;
}
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
@@ -825,6 +825,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
size_t inv_offset = 0;
std::vector<rct::key> to_invert;
to_invert.reserve(11 * sizeof(proofs));
+ size_t max_logM = 0;
for (const Bulletproof *p: proofs)
{
const Bulletproof &proof = *p;
@@ -861,6 +862,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
size_t M;
for (pd.logM = 0; (M = 1<<pd.logM) <= maxM && M < proof.V.size(); ++pd.logM);
CHECK_AND_ASSERT_MES(proof.L.size() == 6+pd.logM, false, "Proof is not the expected size");
+ max_logM = std::max(pd.logM, max_logM);
const size_t rounds = pd.logM+logN;
CHECK_AND_ASSERT_MES(rounds > 0, false, "Zero rounds");
@@ -888,7 +890,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
rct::key tmp;
std::vector<MultiexpData> multiexp_data;
- multiexp_data.reserve(nV + (2 * (10/*logM*/ + logN) + 4) * proofs.size() + 2 * maxMN);
+ multiexp_data.reserve(nV + (2 * (max_logM + logN) + 4) * proofs.size() + 2 * maxMN);
multiexp_data.resize(2 * maxMN);
PERF_TIMER_START_BP(VERIFY_line_24_25_invert);
@@ -901,6 +903,8 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
rct::keyV m_z4(maxMN, rct::zero()), m_z5(maxMN, rct::zero());
rct::key m_y0 = rct::zero(), y1 = rct::zero();
int proof_data_index = 0;
+ rct::keyV w_cache;
+ rct::keyV proof8_V, proof8_L, proof8_R;
for (const Bulletproof *p: proofs)
{
const Bulletproof &proof = *p;
@@ -913,9 +917,9 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
const rct::key weight_z = rct::skGen();
// pre-multiply some points by 8
- rct::keyV proof8_V = proof.V; for (rct::key &k: proof8_V) k = rct::scalarmult8(k);
- rct::keyV proof8_L = proof.L; for (rct::key &k: proof8_L) k = rct::scalarmult8(k);
- rct::keyV proof8_R = proof.R; for (rct::key &k: proof8_R) k = rct::scalarmult8(k);
+ proof8_V.resize(proof.V.size()); for (size_t i = 0; i < proof.V.size(); ++i) proof8_V[i] = rct::scalarmult8(proof.V[i]);
+ proof8_L.resize(proof.L.size()); for (size_t i = 0; i < proof.L.size(); ++i) proof8_L[i] = rct::scalarmult8(proof.L[i]);
+ proof8_R.resize(proof.R.size()); for (size_t i = 0; i < proof.R.size(); ++i) proof8_R[i] = rct::scalarmult8(proof.R[i]);
rct::key proof8_T1 = rct::scalarmult8(proof.T1);
rct::key proof8_T2 = rct::scalarmult8(proof.T2);
rct::key proof8_S = rct::scalarmult8(proof.S);
@@ -976,7 +980,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
// precalc
PERF_TIMER_START_BP(VERIFY_line_24_25_precalc);
- rct::keyV w_cache(1<<rounds);
+ w_cache.resize(1<<rounds);
w_cache[0] = winv[0];
w_cache[1] = pd.w[0];
for (size_t j = 1; j < rounds; ++j)
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 39a8b4745..ec3833a1c 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"
@@ -432,17 +433,12 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HASHES_FAST>(invoke_http_mode::BIN, "/gethashes.bin", req, res, r))
return r;
- NOTIFY_RESPONSE_CHAIN_ENTRY::request resp;
-
- resp.start_height = req.start_height;
- if(!m_core.find_blockchain_supplement(req.block_ids, resp))
+ res.start_height = req.start_height;
+ if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, res.m_block_ids, res.start_height, res.current_height, false))
{
res.status = "Failed";
return false;
}
- res.current_height = resp.total_height;
- res.start_height = resp.start_height;
- res.m_block_ids = std::move(resp.m_block_ids);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -574,7 +570,7 @@ namespace cryptonote
// try the pool for any missing txes
size_t found_in_pool = 0;
std::unordered_set<crypto::hash> pool_tx_hashes;
- std::unordered_map<crypto::hash, bool> double_spend_seen;
+ std::unordered_map<crypto::hash, tx_info> per_tx_pool_tx_info;
if (!missed_txs.empty())
{
std::vector<tx_info> pool_tx_info;
@@ -629,7 +625,7 @@ namespace cryptonote
{
if (ti.id_hash == hash_string)
{
- double_spend_seen.insert(std::make_pair(h, ti.double_spend_seen));
+ per_tx_pool_tx_info.insert(std::make_pair(h, ti));
break;
}
}
@@ -715,14 +711,17 @@ namespace cryptonote
if (e.in_pool)
{
e.block_height = e.block_timestamp = std::numeric_limits<uint64_t>::max();
- if (double_spend_seen.find(tx_hash) != double_spend_seen.end())
+ auto it = per_tx_pool_tx_info.find(tx_hash);
+ if (it != per_tx_pool_tx_info.end())
{
- e.double_spend_seen = double_spend_seen[tx_hash];
+ e.double_spend_seen = it->second.double_spend_seen;
+ e.relayed = it->second.relayed;
}
else
{
- MERROR("Failed to determine double spend status for " << tx_hash);
+ MERROR("Failed to determine pool info for " << tx_hash);
e.double_spend_seen = false;
+ e.relayed = false;
}
}
else
@@ -730,6 +729,7 @@ namespace cryptonote
e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash);
e.block_timestamp = m_core.get_blockchain_storage().get_db().get_block_timestamp(e.block_height);
e.double_spend_seen = false;
+ e.relayed = false;
}
// fill up old style responses too, in case an old wallet asks
@@ -845,6 +845,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)
@@ -1296,7 +1304,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;
@@ -1394,11 +1405,9 @@ namespace cryptonote
submit_req.push_back(boost::value_initialized<std::string>());
res.height = m_core.get_blockchain_storage().get_current_blockchain_height();
- bool r = CORE_RPC_STATUS_OK;
-
for(size_t i = 0; i < req.amount_of_blocks; i++)
{
- r = on_getblocktemplate(template_req, template_res, error_resp, ctx);
+ bool r = on_getblocktemplate(template_req, template_res, error_resp, ctx);
res.status = template_res.status;
template_req.prev_block.clear();
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index a42ca2494..e4683bbe2 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -40,6 +40,9 @@
#include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc"
+
// yes, epee doesn't properly use its full namespace when calling its
// functions from macros. *sigh*
using namespace epee;
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index d2aba8d67..8342e88b1 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -364,6 +364,7 @@ namespace cryptonote
uint64_t block_height;
uint64_t block_timestamp;
std::vector<uint64_t> output_indices;
+ bool relayed;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
@@ -374,9 +375,16 @@ namespace cryptonote
KV_SERIALIZE(as_json)
KV_SERIALIZE(in_pool)
KV_SERIALIZE(double_spend_seen)
- KV_SERIALIZE(block_height)
- KV_SERIALIZE(block_timestamp)
- KV_SERIALIZE(output_indices)
+ if (!this_ref.in_pool)
+ {
+ KV_SERIALIZE(block_height)
+ KV_SERIALIZE(block_timestamp)
+ KV_SERIALIZE(output_indices)
+ }
+ else
+ {
+ KV_SERIALIZE(relayed)
+ }
END_KV_SERIALIZE_MAP()
};
@@ -577,10 +585,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 +609,7 @@ namespace cryptonote
bool overspend;
bool fee_too_low;
bool not_rct;
+ bool sanity_check_failed;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
@@ -613,6 +624,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/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index 540afe6b9..7c8953930 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -141,7 +141,7 @@ namespace rpc
auto& chain = m_core.get_blockchain_storage();
- if (!chain.find_blockchain_supplement(req.known_hashes, res.hashes, res.start_height, res.current_height))
+ if (!chain.find_blockchain_supplement(req.known_hashes, res.hashes, res.start_height, res.current_height, false))
{
res.status = Message::STATUS_FAILED;
res.error_details = "Blockchain::find_blockchain_supplement() returned false";
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 472f037d0..560c5be24 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)
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index f5f3c0e1b..1d5078a11 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -37,9 +37,10 @@ namespace tools
static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
-NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex)
+NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::recursive_mutex &mutex)
: m_http_client(http_client)
, m_daemon_rpc_mutex(mutex)
+ , m_offline(false)
{
invalidate();
}
@@ -61,6 +62,8 @@ void NodeRPCProxy::invalidate()
boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const
{
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_rpc_version == 0)
{
cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
@@ -84,6 +87,8 @@ void NodeRPCProxy::set_height(uint64_t h)
boost::optional<std::string> NodeRPCProxy::get_info() const
{
+ if (m_offline)
+ return boost::optional<std::string>("offline");
const time_t now = time(NULL);
if (now >= m_get_info_time + 30) // re-cache every 30 seconds
{
@@ -134,6 +139,8 @@ boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &bloc
boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const
{
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_earliest_height[version] == 0)
{
cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req_t = AUTO_VAL_INIT(req_t);
@@ -161,6 +168,8 @@ boost::optional<std::string> NodeRPCProxy::get_dynamic_base_fee_estimate(uint64_
if (result)
return result;
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_dynamic_base_fee_estimate_cached_height != height || m_dynamic_base_fee_estimate_grace_blocks != grace_blocks)
{
cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t);
@@ -191,6 +200,8 @@ boost::optional<std::string> NodeRPCProxy::get_fee_quantization_mask(uint64_t &f
if (result)
return result;
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_dynamic_base_fee_estimate_cached_height != height)
{
cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t);
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 3630aec08..3b75c8b94 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -39,9 +39,10 @@ namespace tools
class NodeRPCProxy
{
public:
- NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex);
+ NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::recursive_mutex &mutex);
void invalidate();
+ void set_offline(bool offline) { m_offline = offline; }
boost::optional<std::string> get_rpc_version(uint32_t &version) const;
boost::optional<std::string> get_height(uint64_t &height) const;
@@ -56,7 +57,8 @@ private:
boost::optional<std::string> get_info() const;
epee::net_utils::http::http_simple_client &m_http_client;
- boost::mutex &m_daemon_rpc_mutex;
+ boost::recursive_mutex &m_daemon_rpc_mutex;
+ bool m_offline;
mutable uint64_t m_height;
mutable uint64_t m_earliest_height[256];
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index b288994a5..a7da9395c 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -266,6 +266,7 @@ struct options {
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};
+ const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor 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)
@@ -456,6 +457,9 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
if (command_line::get_arg(vm, opts.no_dns))
wallet->enable_dns(false);
+ if (command_line::get_arg(vm, opts.offline))
+ wallet->set_offline();
+
try
{
if (!command_line::is_arg_defaulted(vm, opts.tx_notify))
@@ -792,7 +796,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
@@ -1083,7 +1087,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_unattended(unattended),
m_devices_registered(false),
m_device_last_key_image_sync(0),
- m_use_dns(true)
+ m_use_dns(true),
+ m_offline(false)
{
}
@@ -1139,6 +1144,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
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);
+ command_line::add_arg(desc_params, opts.offline);
}
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)
@@ -1184,6 +1190,8 @@ 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_options_t ssl_options)
{
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
+
if(m_http_client.is_connected())
m_http_client.disconnect();
m_daemon_address = std::move(daemon_address);
@@ -2392,7 +2400,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
req.start_height = start_height;
req.no_miner_tx = m_refresh_type == RefreshNoCoinbase;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/getblocks.bin", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblocks.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblocks.bin");
@@ -2414,7 +2422,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
req.start_height = start_height;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_bin("/gethashes.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/gethashes.bin", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gethashes.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gethashes.bin");
@@ -2691,7 +2699,7 @@ void wallet2::update_pool_state(bool refreshed)
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response res;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/get_transaction_pool_hashes.bin", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_transaction_pool_hashes.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_transaction_pool_hashes.bin");
@@ -2838,7 +2846,7 @@ void wallet2::update_pool_state(bool refreshed)
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
MDEBUG("Got " << r << " and " << res.status);
if (r && res.status == CORE_RPC_STATUS_OK)
@@ -2999,6 +3007,13 @@ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create
//----------------------------------------------------------------------------------------------------
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool)
{
+ if (m_offline)
+ {
+ blocks_fetched = 0;
+ received_money = 0;
+ return;
+ }
+
if(m_light_wallet) {
// MyMonero get_address_info needs to be called occasionally to trigger wallet sync.
@@ -3258,7 +3273,7 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
req.binary = true;
req.compress = true;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/get_output_distribution.bin", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
if (!r)
{
@@ -5088,7 +5103,14 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
{
THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline)
+ {
+ if (version)
+ *version = 0;
+ if (ssl)
+ *ssl = false;
+ return false;
+ }
// TODO: Add light wallet version check.
if(m_light_wallet) {
@@ -5099,20 +5121,23 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
return m_light_wallet_connected;
}
- if(!m_http_client.is_connected(ssl))
{
- m_node_rpc_proxy.invalidate();
- if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
- return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
if(!m_http_client.is_connected(ssl))
- return false;
+ {
+ m_node_rpc_proxy.invalidate();
+ if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
+ return false;
+ if(!m_http_client.is_connected(ssl))
+ return false;
+ }
}
if (version)
{
cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t);
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t, m_http_client);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t);
if(!r) {
*version = 0;
return false;
@@ -5126,6 +5151,18 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
return true;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::set_offline(bool offline)
+{
+ m_offline = offline;
+ m_http_client.set_auto_connect(!offline);
+ if (offline)
+ {
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
+ if(m_http_client.is_connected())
+ m_http_client.disconnect();
+ }
+}
+//----------------------------------------------------------------------------------------------------
bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const
{
hw::device &hwdev = m_account.get_device();
@@ -5304,7 +5341,7 @@ void wallet2::trim_hashchain()
cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response res = AUTO_VAL_INIT(res);
m_daemon_rpc_mutex.lock();
req.height = m_blockchain.size() - 1;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
if (r && res.status == CORE_RPC_STATUS_OK)
{
@@ -5660,7 +5697,7 @@ void wallet2::rescan_spent()
for (size_t n = start_offset; n < start_offset + n_outputs; ++n)
req.key_images.push_back(string_tools::pod_to_hex(m_transfers[n].m_key_image));
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
@@ -5988,7 +6025,7 @@ void wallet2::commit_tx(pending_tx& ptx)
oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
oreq.tx = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/submit_raw_tx", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/submit_raw_tx", oreq, ores, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "submit_raw_tx");
// MyMonero and OpenMonero use different status strings
@@ -6000,9 +6037,10 @@ 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);
+ bool r = invoke_http_json("/sendrawtransaction", req, daemon_send_resp, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
@@ -6955,7 +6993,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
m_daemon_rpc_mutex.lock();
getbh_req.start_height = m_blockchain.size() - N;
getbh_req.end_height = m_blockchain.size() - 1;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange");
THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange");
@@ -7126,7 +7164,7 @@ bool wallet2::unset_ring(const crypto::hash &txid)
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to get transaction from daemon");
if (res.txs.empty())
@@ -7180,8 +7218,8 @@ bool wallet2::find_and_save_rings(bool force)
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txs_hashes[s]));
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -7322,7 +7360,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
oreq.count = light_wallet_requested_outputs_count;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_random_outs", oreq, ores, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
@@ -7462,7 +7500,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
req_t.unlocked = true;
req_t.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -7485,7 +7523,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
req_t.cumulative = true;
req_t.binary = true;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout * 1000);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, rpc_timeout * 1000);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_distribution");
@@ -7884,7 +7922,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// get the keys for those
req.get_txid = false;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/get_outs.bin", req, daemon_resp, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
@@ -8596,7 +8634,7 @@ bool wallet2::light_wallet_login(bool &new_address)
// Always create account if it doesn't exist.
request.create_account = true;
m_daemon_rpc_mutex.lock();
- bool connected = epee::net_utils::invoke_http_json("/login", request, response, m_http_client, rpc_timeout, "POST");
+ bool connected = invoke_http_json("/login", request, response, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
// MyMonero doesn't send any status message. OpenMonero does.
m_light_wallet_connected = connected && (response.status.empty() || response.status == "success");
@@ -8621,7 +8659,7 @@ bool wallet2::light_wallet_import_wallet_request(tools::COMMAND_RPC_IMPORT_WALLE
oreq.address = get_account().get_public_address_str(m_nettype);
oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/import_wallet_request", oreq, response, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/import_wallet_request", oreq, response, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "import_wallet_request");
@@ -8647,7 +8685,7 @@ void wallet2::light_wallet_get_unspent_outs()
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_unspent_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_unspent_outs", oreq, ores, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_unspent_outs");
THROW_WALLET_EXCEPTION_IF(ores.status == "error", error::wallet_internal_error, ores.reason);
@@ -8792,7 +8830,7 @@ bool wallet2::light_wallet_get_address_info(tools::COMMAND_RPC_GET_ADDRESS_INFO:
request.address = get_account().get_public_address_str(m_nettype);
request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_address_info", request, response, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_address_info", request, response, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_info");
// TODO: Validate result
@@ -8809,7 +8847,7 @@ void wallet2::light_wallet_get_address_txs()
ireq.address = get_account().get_public_address_str(m_nettype);
ireq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_address_txs", ireq, ires, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_address_txs", ireq, ires, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_txs");
//OpenMonero sends status=success, Mymonero doesn't.
@@ -10113,7 +10151,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
req_t.max_count = 0;
req_t.unlocked = unlocked;
req_t.recent_cutoff = 0;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_outputs_from_histogram");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -10151,7 +10189,7 @@ uint64_t wallet2::get_num_rct_outputs()
req_t.max_count = 0;
req_t.unlocked = true;
req_t.recent_cutoff = 0;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_num_rct_outputs");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -10276,7 +10314,7 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -10319,8 +10357,8 @@ void wallet2::set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_
COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -10369,8 +10407,8 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -10431,8 +10469,8 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
COMMAND_RPC_GET_OUTPUTS_BIN::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
@@ -10487,8 +10525,8 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -10560,8 +10598,8 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
COMMAND_RPC_GET_OUTPUTS_BIN::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
@@ -10659,7 +10697,7 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -10708,7 +10746,7 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -10863,7 +10901,7 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -11155,7 +11193,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
gettx_req.decode_as_json = false;
gettx_req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", gettx_req, gettx_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || gettx_res.txs.size() != proofs.size(),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -11166,7 +11204,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
for (size_t i = 0; i < proofs.size(); ++i)
kispent_req.key_images.push_back(epee::string_tools::pod_to_hex(proofs[i].key_image));
m_daemon_rpc_mutex.lock();
- ok = epee::net_utils::invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, m_http_client, rpc_timeout);
+ ok = invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || kispent_res.spent_status.size() != proofs.size(),
error::wallet_internal_error, "Failed to get key image spent status from daemon");
@@ -11718,7 +11756,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
{
PERF_TIMER(import_key_images_RPC);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
@@ -11804,7 +11842,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
PERF_TIMER_START(import_key_images_E);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/gettransactions", gettxs_req, gettxs_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(gettxs_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -12032,14 +12070,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)
@@ -12052,13 +12091,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));
@@ -12739,7 +12778,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
height_mid,
height_max
};
- bool r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/getblocks_by_height.bin", req, res, rpc_timeout);
if (!r || res.status != CORE_RPC_STATUS_OK)
{
std::ostringstream oss;
@@ -12809,7 +12848,7 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response res = AUTO_VAL_INIT(res);
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "Failed to connect to daemon");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog");
@@ -12879,7 +12918,7 @@ uint64_t wallet2::get_segregation_fork_height() const
if (m_segregation_height > 0)
return m_segregation_height;
- if (m_use_dns)
+ if (m_use_dns && !m_offline)
{
// All four MoneroPulse domains have DNSSEC on and valid
static const std::vector<std::string> dns_urls = {
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 39380c9df..8561c42ba 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1139,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;
@@ -1232,19 +1232,22 @@ namespace tools
template<class t_request, class t_response>
inline bool invoke_http_json(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
{
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline) return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
return epee::net_utils::invoke_http_json(uri, req, res, m_http_client, timeout, http_method);
}
template<class t_request, class t_response>
inline bool invoke_http_bin(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
{
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline) return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
return epee::net_utils::invoke_http_bin(uri, req, res, m_http_client, timeout, http_method);
}
template<class t_request, class t_response>
inline bool invoke_http_json_rpc(const boost::string_ref uri, const std::string& method_name, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
{
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline) return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, m_http_client, timeout, http_method, req_id);
}
@@ -1291,6 +1294,7 @@ namespace tools
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; }
+ void set_offline(bool offline = true);
private:
/*!
@@ -1422,7 +1426,7 @@ namespace tools
std::atomic<bool> m_run;
- boost::mutex m_daemon_rpc_mutex;
+ boost::recursive_mutex m_daemon_rpc_mutex;
bool m_trusted_daemon;
i_wallet2_callback* m_callback;
@@ -1474,6 +1478,7 @@ namespace tools
std::string m_device_derivation_path;
uint64_t m_device_last_key_image_sync;
bool m_use_dns;
+ bool m_offline;
// 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..2039c6742 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1842,11 +1842,7 @@ namespace tools
{
if (req.account_index != td.m_subaddr_index.major || (!req.subaddr_indices.empty() && req.subaddr_indices.count(td.m_subaddr_index.minor) == 0))
continue;
- if (!transfers_found)
- {
- transfers_found = true;
- }
- auto txBlob = t_serializable_object_to_blob(td.m_tx);
+ transfers_found = true;
wallet_rpc::transfer_details rpc_transfers;
rpc_transfers.amount = td.amount();
rpc_transfers.spent = td.m_spent;
@@ -2581,7 +2577,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 +3107,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 +3149,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 +3158,17 @@ namespace tools
{
if (!m_wallet) return not_open(er);
- try
+ if (req.autosave_current)
{
- m_wallet->store();
- }
- catch (const std::exception& e)
- {
- 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 +3385,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 +3447,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 +3513,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 +3635,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;