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.cpp53
-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.cpp32
-rw-r--r--src/rpc/core_rpc_server.h3
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h18
-rw-r--r--src/simplewallet/simplewallet.cpp2
-rw-r--r--src/wallet/wallet2.cpp14
-rw-r--r--src/wallet/wallet2.h4
-rw-r--r--src/wallet/wallet_rpc_server.cpp97
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h14
28 files changed, 442 insertions, 218 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..51fd9fe16 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -428,6 +428,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
block bl;
block_verification_context bvc = boost::value_initialized<block_verification_context>();
generate_genesis_block(bl, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE);
+ db_wtxn_guard wtxn_guard(m_db);
add_new_block(bl, bvc);
CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "Failed to add genesis block to blockchain");
}
@@ -443,7 +444,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
m_db->fixup();
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
+
// check how far behind we are
uint64_t top_block_timestamp = m_db->get_top_block_timestamp();
uint64_t timestamp_diff = time(NULL) - top_block_timestamp;
@@ -464,7 +466,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
#endif
MINFO("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block());
- m_db->block_txn_stop();
+
+ rtxn_guard.stop();
uint64_t num_popped_blocks = 0;
while (!m_db->is_read_only())
@@ -518,8 +521,11 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
if (test_options && test_options->long_term_block_weight_window)
m_long_term_block_weights_window = test_options->long_term_block_weight_window;
- if (!update_next_cumulative_weight_limit())
- return false;
+ {
+ db_txn_guard txn_guard(m_db, m_db->is_read_only());
+ if (!update_next_cumulative_weight_limit())
+ return false;
+ }
return true;
}
//------------------------------------------------------------------
@@ -725,6 +731,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
m_db->reset();
m_hardfork->init();
+ db_wtxn_guard wtxn_guard(m_db);
block_verification_context bvc = boost::value_initialized<block_verification_context>();
add_new_block(b, bvc);
if (!update_next_cumulative_weight_limit())
@@ -772,7 +779,7 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
if(!sz)
return true;
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
bool genesis_included = false;
uint64_t current_back_offset = 1;
while(current_back_offset < sz)
@@ -799,7 +806,6 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
{
ids.push_back(m_db->get_block_hash_from_height(0));
}
- m_db->block_txn_stop();
return true;
}
@@ -1866,7 +1872,7 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard (m_db);
rsp.current_blockchain_height = get_current_blockchain_height();
std::vector<std::pair<cryptonote::blobdata,block>> blocks;
get_blocks(arg.blocks, blocks, rsp.missed_ids);
@@ -1893,7 +1899,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
// as done below if any standalone transactions were requested
// and missed.
rsp.missed_ids.insert(rsp.missed_ids.end(), missed_tx_ids.begin(), missed_tx_ids.end());
- m_db->block_txn_stop();
return false;
}
@@ -1903,7 +1908,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
//get and pack other transactions, if needed
get_transactions_blobs(arg.txs, rsp.txs, rsp.missed_ids);
- m_db->block_txn_stop();
return true;
}
//------------------------------------------------------------------
@@ -2075,14 +2079,13 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
return false;
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
// make sure that the last block in the request's block list matches
// the genesis block
auto gen_hash = m_db->get_block_hash_from_height(0);
if(qblock_ids.back() != gen_hash)
{
MCERROR("net.p2p", "Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block mismatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection");
- m_db->block_txn_abort();
return false;
}
@@ -2100,11 +2103,9 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
catch (const std::exception& e)
{
MWARNING("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it);
- m_db->block_txn_abort();
return false;
}
}
- m_db->block_txn_stop();
// this should be impossible, as we checked that we share the genesis block,
// but just in case...
@@ -2295,7 +2296,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
return false;
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
current_height = get_current_blockchain_height();
const uint32_t pruning_seed = get_blockchain_pruning_seed();
start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed);
@@ -2307,7 +2308,6 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
hashes.push_back(m_db->get_block_hash_from_height(i));
}
- m_db->block_txn_stop();
return true;
}
@@ -2354,7 +2354,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
}
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
total_height = get_current_blockchain_height();
size_t count = 0, size = 0;
blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height)));
@@ -2380,7 +2380,6 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
blocks.back().second.push_back(std::make_pair(b.tx_hashes[i], std::move(txs[i])));
}
}
- m_db->block_txn_stop();
return true;
}
//------------------------------------------------------------------
@@ -3535,7 +3534,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
static bool seen_future_version = false;
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
uint64_t blockchain_height;
const crypto::hash top_hash = get_tail_id(blockchain_height);
++blockchain_height; // block height to chain height
@@ -3544,7 +3543,6 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
MERROR_VER("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << top_hash);
bvc.m_verifivation_failed = true;
leave:
- m_db->block_txn_stop();
return false;
}
@@ -3827,7 +3825,7 @@ leave:
if(precomputed)
block_processing_time += m_fake_pow_calc_time;
- m_db->block_txn_stop();
+ rtxn_guard.stop();
TIME_MEASURE_START(addblock);
uint64_t new_height = 0;
if (!bvc.m_verifivation_failed)
@@ -3945,8 +3943,6 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
LOG_PRINT_L3("Blockchain::" << __func__);
- m_db->block_txn_start(false);
-
// when we reach this, the last hf version is not yet written to the db
const uint64_t db_height = m_db->height();
const uint8_t hf_version = get_current_hard_fork_version();
@@ -3990,7 +3986,6 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
new_weights[0] = long_term_block_weight;
long_term_median = epee::misc_utils::median(new_weights);
m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
- short_term_constraint = m_long_term_effective_median_block_weight + m_long_term_effective_median_block_weight * 2 / 5;
weights.clear();
get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
@@ -4009,9 +4004,8 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
if (long_term_effective_median_block_weight)
*long_term_effective_median_block_weight = m_long_term_effective_median_block_weight;
- m_db->add_max_block_size(m_current_block_cumul_weight_limit);
-
- m_db->block_txn_stop();
+ if (!m_db->is_read_only())
+ m_db->add_max_block_size(m_current_block_cumul_weight_limit);
return true;
}
@@ -4022,12 +4016,11 @@ bool Blockchain::add_new_block(const block& bl, block_verification_context& bvc)
crypto::hash id = get_block_hash(bl);
CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process
CRITICAL_REGION_LOCAL1(m_blockchain_lock);
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
if(have_block(id))
{
LOG_PRINT_L3("block with id = " << id << " already exists");
bvc.m_already_exists = true;
- m_db->block_txn_stop();
m_blocks_txs_check.clear();
return false;
}
@@ -4037,14 +4030,14 @@ bool Blockchain::add_new_block(const block& bl, block_verification_context& bvc)
{
//chain switching or wrong block
bvc.m_added_to_main_chain = false;
- m_db->block_txn_stop();
+ rtxn_guard.stop();
bool r = handle_alternative_block(bl, id, bvc);
m_blocks_txs_check.clear();
return r;
//never relay alternative blocks
}
- m_db->block_txn_stop();
+ rtxn_guard.stop();
return handle_block_to_main_chain(bl, id, bvc);
}
//------------------------------------------------------------------
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 91dea4982..be1ea5a17 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1609,6 +1609,9 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::check_fork_time()
{
+ if (m_nettype == FAKECHAIN)
+ return true;
+
HardFork::State state = m_blockchain_storage.get_hard_fork_state();
const el::Level level = el::Level::Warning;
switch (state) {
@@ -1824,7 +1827,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::check_block_rate()
{
- if (m_offline || m_target_blockchain_height > get_current_blockchain_height())
+ if (m_offline || m_nettype == FAKECHAIN || m_target_blockchain_height > get_current_blockchain_height())
{
MDEBUG("Not checking block rate, offline or syncing");
return true;
diff --git a/src/cryptonote_core/tx_sanity_check.cpp b/src/cryptonote_core/tx_sanity_check.cpp
new file mode 100644
index 000000000..d3b225f1c
--- /dev/null
+++ b/src/cryptonote_core/tx_sanity_check.cpp
@@ -0,0 +1,100 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdint.h>
+#include <vector>
+#include "cryptonote_basic/cryptonote_basic_impl.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "blockchain.h"
+#include "tx_sanity_check.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "txsanity"
+
+namespace cryptonote
+{
+
+bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob)
+{
+ cryptonote::transaction tx;
+
+ if (!cryptonote::parse_and_validate_tx_from_blob(tx_blob, tx))
+ {
+ MERROR("Failed to parse transaction");
+ return false;
+ }
+
+ if (cryptonote::is_coinbase(tx))
+ {
+ MERROR("Transaction is coinbase");
+ return false;
+ }
+ std::set<uint64_t> rct_indices;
+ size_t n_indices = 0;
+
+ for (const auto &txin : tx.vin)
+ {
+ if (txin.type() != typeid(cryptonote::txin_to_key))
+ continue;
+ const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(txin);
+ if (in_to_key.amount != 0)
+ continue;
+ const std::vector<uint64_t> absolute = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
+ for (uint64_t offset: absolute)
+ rct_indices.insert(offset);
+ n_indices += in_to_key.key_offsets.size();
+ }
+
+ if (n_indices <= 10)
+ {
+ MERROR("n_indices is only " << n_indices);
+ return true;
+ }
+
+ uint64_t n_available = blockchain.get_num_mature_outputs(0);
+ if (n_available < 10000)
+ return true;
+
+ if (rct_indices.size() < n_indices * 9 / 10)
+ {
+ MERROR("unique indices is only " << rct_indices.size() << "/" << n_indices);
+ return false;
+ }
+
+ std::vector<uint64_t> offsets(rct_indices.begin(), rct_indices.end());
+ uint64_t median = epee::misc_utils::median(offsets);
+ if (median < n_available * 9 / 10)
+ {
+ MERROR("median is " << median << "/" << n_available);
+ return false;
+ }
+
+ return true;
+}
+
+}
diff --git a/src/cryptonote_core/tx_sanity_check.h b/src/cryptonote_core/tx_sanity_check.h
new file mode 100644
index 000000000..c12d1b0b1
--- /dev/null
+++ b/src/cryptonote_core/tx_sanity_check.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "cryptonote_basic/blobdatatype.h"
+
+namespace cryptonote
+{
+ class Blockchain;
+
+ bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob);
+}
diff --git a/src/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..ffd2a0113 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"
@@ -574,7 +575,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 +630,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 +716,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 +734,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 +850,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 +1309,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 +1410,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/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 2e134931f..8c8afba56 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -118,7 +118,7 @@ typedef cryptonote::simple_wallet sw;
if (!m_long_payment_id_support) { \
fail_msg_writer() << tr("Warning: Long payment IDs are obsolete."); \
fail_msg_writer() << tr("Long payment IDs are not encrypted on the blockchain, and will harm your privacy."); \
- fail_msg_writer() << tr("Use --long-payment-id-support if you really must use one, and warn the recipient they are using an obsolete feature that will disappear in the future."); \
+ fail_msg_writer() << tr("Use --long-payment-id-support-bad-for-privacy if you really must use one, and warn the recipient they are using an obsolete feature that will disappear in the future."); \
return true; \
} \
} while(0)
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index f662555b5..a7da9395c 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -796,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
@@ -6037,6 +6037,7 @@ void wallet2::commit_tx(pending_tx& ptx)
COMMAND_RPC_SEND_RAW_TX::request req;
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
req.do_not_relay = false;
+ req.do_sanity_checks = true;
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
m_daemon_rpc_mutex.lock();
bool r = invoke_http_json("/sendrawtransaction", req, daemon_send_resp, rpc_timeout);
@@ -12069,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)
@@ -12089,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));
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 094346293..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;
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;