aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp3
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.h2
-rw-r--r--src/blockchain_db/blockchain_db.h9
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp56
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h3
-rw-r--r--src/blockchain_utilities/fake_core.h4
-rw-r--r--src/cryptonote_core/blockchain.cpp41
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp67
-rw-r--r--src/cryptonote_core/cryptonote_core.h9
-rw-r--r--src/cryptonote_core/tx_pool.cpp48
-rw-r--r--src/cryptonote_core/tx_pool.h29
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl8
-rw-r--r--src/daemon/command_parser_executor.cpp18
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp5
-rw-r--r--src/daemon/rpc_command_executor.cpp105
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/ringct/rctSigs.cpp173
-rw-r--r--src/ringct/rctSigs.h6
-rw-r--r--src/rpc/core_rpc_server.cpp5
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h6
-rw-r--r--src/wallet/api/address_book.cpp54
-rw-r--r--src/wallet/api/wallet.cpp79
-rw-r--r--src/wallet/api/wallet.h5
-rw-r--r--src/wallet/wallet2.cpp65
-rw-r--r--src/wallet/wallet2.h6
-rw-r--r--src/wallet/wallet2_api.h20
-rw-r--r--tests/core_proxy/core_proxy.cpp2
-rw-r--r--tests/core_proxy/core_proxy.h2
-rw-r--r--tests/core_tests/chaingen.h4
-rw-r--r--tests/unit_tests/ban.cpp2
-rw-r--r--tests/unit_tests/hardfork.cpp2
-rw-r--r--tests/unit_tests/main.cpp1
-rw-r--r--tests/unit_tests/serialization.cpp8
34 files changed, 630 insertions, 221 deletions
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index 137ed9dc6..57d8371bd 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -1813,9 +1813,10 @@ bool BlockchainBDB::has_key_image(const crypto::key_image& img) const
// Ostensibly BerkeleyDB has batch transaction support built-in,
// so the following few functions will be NOP.
-void BlockchainBDB::batch_start(uint64_t batch_num_blocks)
+bool BlockchainBDB::batch_start(uint64_t batch_num_blocks)
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
+ return false;
}
void BlockchainBDB::batch_commit()
diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h
index f320ab0e3..266e780c6 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.h
+++ b/src/blockchain_db/berkeleydb/db_bdb.h
@@ -324,7 +324,7 @@ public:
);
virtual void set_batch_transactions(bool batch_transactions);
- virtual void batch_start(uint64_t batch_num_blocks=0);
+ virtual bool batch_start(uint64_t batch_num_blocks=0);
virtual void batch_commit();
virtual void batch_stop();
virtual void batch_abort();
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index b39cb1801..455e0c811 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -655,16 +655,17 @@ public:
* been called. In either case, it should end the batch and write to its
* backing store.
*
- * If a batch is already in-progress, this function should throw a DB_ERROR.
- * This exception may change in the future if it is deemed necessary to
- * have a more granular exception type for this scenario.
+ * If a batch is already in-progress, this function must return false.
+ * If a batch was started by this call, it must return true.
*
* If any of this cannot be done, the subclass should throw the corresponding
* subclass of DB_EXCEPTION
*
* @param batch_num_blocks number of blocks to batch together
+ *
+ * @return true if we started the batch, false if already started
*/
- virtual void batch_start(uint64_t batch_num_blocks=0) = 0;
+ virtual bool batch_start(uint64_t batch_num_blocks=0) = 0;
/**
* @brief ends a batch transaction
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index ba2cb60bd..ca79ab4f8 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -543,6 +543,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
uint64_t min_block_size = 4 * 1024;
uint64_t block_stop = 0;
+ uint64_t m_height = height();
if (m_height > 1)
block_stop = m_height - 1;
uint64_t block_start = 0;
@@ -593,6 +594,7 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
+ uint64_t m_height = height();
CURSOR(block_heights)
blk_height bh = {blk_hash, m_height};
@@ -654,6 +656,7 @@ void BlockchainLMDB::remove_block()
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height == 0)
throw0(BLOCK_DNE ("Attempting to remove block from an empty blockchain"));
@@ -691,6 +694,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
+ uint64_t m_height = height();
int result;
uint64_t tx_id = m_num_txs;
@@ -787,6 +791,7 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
+ uint64_t m_height = height();
int result = 0;
@@ -1018,7 +1023,6 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions)
m_write_txn = nullptr;
m_write_batch_txn = nullptr;
m_batch_active = false;
- m_height = 0;
m_cum_size = 0;
m_cum_count = 0;
@@ -1143,7 +1147,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
if ((result = mdb_stat(txn, m_blocks, &db_stats)))
throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
LOG_PRINT_L2("Setting m_height to: " << db_stats.ms_entries);
- m_height = db_stats.ms_entries;
+ uint64_t m_height = db_stats.ms_entries;
// get and keep current number of txs
if ((result = mdb_stat(txn, m_txs, &db_stats)))
@@ -1294,7 +1298,6 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to write version to database: ", result).c_str()));
txn.commit();
- m_height = 0;
m_num_outputs = 0;
m_cum_size = 0;
m_cum_count = 0;
@@ -1515,6 +1518,7 @@ uint64_t BlockchainLMDB::get_top_block_timestamp() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
// if no blocks, return 0
if (m_height == 0)
@@ -1666,6 +1670,7 @@ crypto::hash BlockchainLMDB::top_block_hash() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height != 0)
{
return get_block_hash_from_height(m_height - 1);
@@ -1678,6 +1683,7 @@ block BlockchainLMDB::get_top_block() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height != 0)
{
@@ -1692,8 +1698,14 @@ uint64_t BlockchainLMDB::height() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ TXN_PREFIX_RDONLY();
+ int result;
- return m_height;
+ // get current height
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_blocks, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
+ return db_stats.ms_entries;
}
bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
@@ -2242,15 +2254,15 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
}
// batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts.
-void BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
+bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
if (! m_batch_transactions)
throw0(DB_ERROR("batch transactions not enabled"));
if (m_batch_active)
- throw0(DB_ERROR("batch transaction already in progress"));
+ return false;
if (m_write_batch_txn != nullptr)
- throw0(DB_ERROR("batch transaction already in progress"));
+ return false;
if (m_write_txn)
throw0(DB_ERROR("batch transaction attempted, but m_write_txn already in use"));
check_open();
@@ -2276,6 +2288,7 @@ void BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
memset(&m_wcursors, 0, sizeof(m_wcursors));
LOG_PRINT_L3("batch transaction: begin");
+ return true;
}
void BlockchainLMDB::batch_commit()
@@ -2287,6 +2300,9 @@ void BlockchainLMDB::batch_commit()
throw0(DB_ERROR("batch transaction not in progress"));
if (m_write_batch_txn == nullptr)
throw0(DB_ERROR("batch transaction not in progress"));
+ if (m_writer != boost::this_thread::get_id())
+ return; // batch txn owned by other thread
+
check_open();
LOG_PRINT_L3("batch transaction: committing...");
@@ -2311,6 +2327,8 @@ void BlockchainLMDB::batch_stop()
throw0(DB_ERROR("batch transaction not in progress"));
if (m_write_batch_txn == nullptr)
throw0(DB_ERROR("batch transaction not in progress"));
+ if (m_writer != boost::this_thread::get_id())
+ return; // batch txn owned by other thread
check_open();
LOG_PRINT_L3("batch transaction: committing...");
TIME_MEASURE_START(time1);
@@ -2333,6 +2351,8 @@ void BlockchainLMDB::batch_abort()
throw0(DB_ERROR("batch transactions not enabled"));
if (! m_batch_active)
throw0(DB_ERROR("batch transaction not in progress"));
+ if (m_writer != boost::this_thread::get_id())
+ return; // batch txn owned by other thread
check_open();
// for destruction of batch transaction
m_write_txn = nullptr;
@@ -2505,6 +2525,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height % 1000 == 0)
{
@@ -2558,8 +2579,6 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
block_txn_abort();
throw;
}
-
- --m_height;
}
void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@@ -2850,7 +2869,7 @@ void BlockchainLMDB::fixup()
void BlockchainLMDB::migrate_0_1()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- uint64_t i, z;
+ uint64_t i, z, m_height;
int result;
mdb_txn_safe txn(false);
MDB_val k, v;
@@ -2859,17 +2878,22 @@ void BlockchainLMDB::migrate_0_1()
LOG_PRINT_YELLOW("Migrating blockchain from DB version 0 to 1 - this may take a while:", LOG_LEVEL_0);
LOG_PRINT_L0("updating blocks, hf_versions, outputs, txs, and spent_keys tables...");
- LOG_PRINT_L0("Total number of blocks: " << m_height);
- LOG_PRINT_L1("block migration will update block_heights, block_info, and hf_versions...");
-
do {
+ result = mdb_txn_begin(m_env, NULL, 0, txn);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
+
+ MDB_stat db_stats;
+ if ((result = mdb_stat(txn, m_blocks, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
+ m_height = db_stats.ms_entries;
+ LOG_PRINT_L0("Total number of blocks: " << m_height);
+ LOG_PRINT_L1("block migration will update block_heights, block_info, and hf_versions...");
+
LOG_PRINT_L1("migrating block_heights:");
MDB_dbi o_heights;
unsigned int flags;
- result = mdb_txn_begin(m_env, NULL, 0, txn);
- if (result)
- throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
result = mdb_dbi_flags(txn, m_block_heights, &flags);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to retrieve block_heights flags: ", result).c_str()));
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index b0d8d9d0a..e7faf8cdc 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -247,7 +247,7 @@ public:
);
virtual void set_batch_transactions(bool batch_transactions);
- virtual void batch_start(uint64_t batch_num_blocks=0);
+ virtual bool batch_start(uint64_t batch_num_blocks=0);
virtual void batch_commit();
virtual void batch_stop();
virtual void batch_abort();
@@ -369,7 +369,6 @@ private:
MDB_dbi m_properties;
- uint64_t m_height;
uint64_t m_num_txs;
uint64_t m_num_outputs;
mutable uint64_t m_cum_size; // used in batch size estimation
diff --git a/src/blockchain_utilities/fake_core.h b/src/blockchain_utilities/fake_core.h
index ba1c2ed72..814139602 100644
--- a/src/blockchain_utilities/fake_core.h
+++ b/src/blockchain_utilities/fake_core.h
@@ -119,9 +119,9 @@ struct fake_core_db
return m_storage.get_db().add_block(blk, block_size, cumulative_difficulty, coins_generated, txs);
}
- void batch_start(uint64_t batch_num_blocks = 0)
+ bool batch_start(uint64_t batch_num_blocks = 0)
{
- m_storage.get_db().batch_start(batch_num_blocks);
+ return m_storage.get_db().batch_start(batch_num_blocks);
}
void batch_stop()
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 5230864ec..47fc26d39 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -375,6 +375,7 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const cryptonote::te
LOG_PRINT_GREEN("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(), LOG_LEVEL_0);
m_db->block_txn_stop();
+ update_next_cumulative_size_limit();
return true;
}
//------------------------------------------------------------------
@@ -508,7 +509,7 @@ block Blockchain::pop_block_from_blockchain()
// that might not be always true. Unlikely though, and always relaying
// these again might cause a spike of traffic as many nodes re-relay
// all the transactions in a popped block when a reorg happens.
- bool r = m_tx_pool.add_tx(tx, tvc, true, true, version);
+ bool r = m_tx_pool.add_tx(tx, tvc, true, true, false, version);
if (!r)
{
LOG_ERROR("Error returning transaction to tx_pool");
@@ -532,6 +533,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
block_verification_context bvc = boost::value_initialized<block_verification_context>();
add_new_block(b, bvc);
+ update_next_cumulative_size_limit();
return bvc.m_added_to_main_chain && !bvc.m_verifivation_failed;
}
//------------------------------------------------------------------
@@ -2341,10 +2343,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type));
}
- // outPk
- CHECK_AND_ASSERT_MES(rv.outPk.size() == tx.vout.size(), false, "Bad outPk size");
- for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
- rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
+ // outPk was already done by handle_incoming_tx
return true;
}
@@ -2649,7 +2648,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
- if (!rct::verRctSimple(rv))
+ if (!rct::verRctSimple(rv, false))
{
LOG_PRINT_L1("Failed to check ringct signatures!");
return false;
@@ -2707,7 +2706,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
- if (!rct::verRct(rv))
+ if (!rct::verRct(rv, false))
{
LOG_PRINT_L1("Failed to check ringct signatures!");
return false;
@@ -2981,7 +2980,7 @@ void Blockchain::return_tx_to_pool(const std::vector<transaction> &txs)
// that might not be always true. Unlikely though, and always relaying
// these again might cause a spike of traffic as many nodes re-relay
// all the transactions in a popped block when a reorg happens.
- if (!m_tx_pool.add_tx(tx, tvc, true, true, version))
+ if (!m_tx_pool.add_tx(tx, tvc, true, true, false, version))
{
LOG_PRINT_L0("Failed to return taken transaction with hash: " << get_transaction_hash(tx) << " to tx_pool");
}
@@ -2998,9 +2997,9 @@ bool Blockchain::flush_txes_from_pool(const std::list<crypto::hash> &txids)
cryptonote::transaction tx;
size_t blob_size;
uint64_t fee;
- bool relayed;
+ bool relayed, do_not_relay;
LOG_PRINT_L1("Removing txid " << txid << " from the pool");
- if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, blob_size, fee, relayed))
+ if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, blob_size, fee, relayed, do_not_relay))
{
LOG_PRINT_L0("Failed to remove txid " << txid << " from the pool");
res = false;
@@ -3161,7 +3160,7 @@ leave:
transaction tx;
size_t blob_size = 0;
uint64_t fee = 0;
- bool relayed = false;
+ bool relayed = false, do_not_relay = false;
TIME_MEASURE_START(aa);
// XXX old code does not check whether tx exists
@@ -3178,7 +3177,7 @@ leave:
TIME_MEASURE_START(bb);
// get transaction with hash <tx_id> from tx_pool
- if(!m_tx_pool.take_tx(tx_id, tx, blob_size, fee, relayed))
+ if(!m_tx_pool.take_tx(tx_id, tx, blob_size, fee, relayed, do_not_relay))
{
LOG_PRINT_L1("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id);
bvc.m_verifivation_failed = true;
@@ -3389,9 +3388,10 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc
void Blockchain::check_against_checkpoints(const checkpoints& points, bool enforce)
{
const auto& pts = points.get_points();
+ bool stop_batch;
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- m_db->batch_start();
+ stop_batch = m_db->batch_start();
for (const auto& pt : pts)
{
// if the checkpoint is for a block we don't have yet, move on
@@ -3415,7 +3415,8 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor
}
}
}
- m_db->batch_stop();
+ if (stop_batch)
+ m_db->batch_stop();
}
//------------------------------------------------------------------
// returns false if any of the checkpoints loading returns false.
@@ -3489,6 +3490,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
CRITICAL_REGION_LOCAL(m_blockchain_lock);
TIME_MEASURE_START(t1);
+ m_db->batch_stop();
if (m_sync_counter > 0)
{
if (force_sync)
@@ -3553,11 +3555,18 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
{
LOG_PRINT_YELLOW("Blockchain::" << __func__, LOG_LEVEL_3);
TIME_MEASURE_START(prepare);
+ bool stop_batch;
CRITICAL_REGION_LOCAL(m_blockchain_lock);
if(blocks_entry.size() == 0)
return false;
+ while (!(stop_batch = m_db->batch_start(blocks_entry.size()))) {
+ m_blockchain_lock.unlock();
+ epee::misc_utils::sleep_no_w(1000);
+ m_blockchain_lock.lock();
+ }
+
if ((m_db->height() + blocks_entry.size()) < m_blocks_hash_check.size())
return true;
@@ -3962,12 +3971,12 @@ void Blockchain::load_compiled_in_block_hashes()
size_t blob_size;
uint64_t fee;
- bool relayed;
+ bool relayed, do_not_relay;
transaction pool_tx;
for(const transaction &tx : txs)
{
crypto::hash tx_hash = get_transaction_hash(tx);
- m_tx_pool.take_tx(tx_hash, pool_tx, blob_size, fee, relayed);
+ m_tx_pool.take_tx(tx_hash, pool_tx, blob_size, fee, relayed, do_not_relay);
}
}
}
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index c63a08ee4..ede7ed748 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -49,6 +49,7 @@ using namespace epee;
#if defined(BERKELEY_DB)
#include "blockchain_db/berkeleydb/db_bdb.h"
#endif
+#include "ringct/rctSigs.h"
DISABLE_VS_WARNINGS(4355)
@@ -312,9 +313,9 @@ namespace cryptonote
LOG_PRINT_L0("Loading blockchain from folder " << folder.string() << " ...");
const std::string filename = folder.string();
- // temporarily default to fastest:async:1000
+ // default to fast:async:1
blockchain_db_sync_mode sync_mode = db_async;
- uint64_t blocks_per_sync = 1000;
+ uint64_t blocks_per_sync = 1;
try
{
@@ -327,12 +328,12 @@ namespace cryptonote
for(const auto &option : options)
LOG_PRINT_L0("option: " << option);
- // default to fast:async:1000
+ // default to fast:async:1
uint64_t DEFAULT_FLAGS = DBS_FAST_MODE;
if(options.size() == 0)
{
- // temporarily default to fastest:async:1000
+ // default to fast:async:1
db_flags = DEFAULT_FLAGS;
}
@@ -348,7 +349,10 @@ namespace cryptonote
else if(options[0] == "fast")
db_flags = DBS_FAST_MODE;
else if(options[0] == "fastest")
+ {
db_flags = DBS_FASTEST_MODE;
+ blocks_per_sync = 1000; // default to fastest:async:1000
+ }
else
db_flags = DEFAULT_FLAGS;
}
@@ -452,7 +456,7 @@ namespace cryptonote
return false;
}
//-----------------------------------------------------------------------------------------------
- bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed)
+ bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{
tvc = boost::value_initialized<tx_verification_context>();
//want to process all transactions sequentially
@@ -494,6 +498,22 @@ namespace cryptonote
return false;
}
+ // resolve outPk references in rct txes
+ // outPk aren't the only thing that need resolving for a fully resolved tx,
+ // but outPk (1) are needed now to check range proof semantics, and
+ // (2) do not need access to the blockchain to find data
+ if (tx.version >= 2)
+ {
+ rct::rctSig &rv = tx.rct_signatures;
+ if (rv.outPk.size() != tx.vout.size())
+ {
+ LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad outPk size in tx " << tx_hash << ", rejected");
+ return false;
+ }
+ for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
+ rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
+ }
+
if(!check_tx_semantic(tx, keeped_by_block))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
@@ -501,7 +521,7 @@ namespace cryptonote
return false;
}
- bool r = add_new_tx(tx, tx_hash, tx_prefixt_hash, tx_blob.size(), tvc, keeped_by_block, relayed);
+ bool r = add_new_tx(tx, tx_hash, tx_prefixt_hash, tx_blob.size(), tvc, keeped_by_block, relayed, do_not_relay);
if(tvc.m_verifivation_failed)
{LOG_PRINT_RED_L1("Transaction verification failed: " << tx_hash);}
else if(tvc.m_verifivation_impossible)
@@ -584,6 +604,33 @@ namespace cryptonote
return false;
}
+ if (tx.version >= 2)
+ {
+ const rct::rctSig &rv = tx.rct_signatures;
+ switch (rv.type) {
+ case rct::RCTTypeNull:
+ // coinbase should not come here, so we reject for all other types
+ LOG_PRINT_RED_L1("Unexpected Null rctSig type");
+ return false;
+ case rct::RCTTypeSimple:
+ if (!rct::verRctSimple(rv, true))
+ {
+ LOG_PRINT_RED_L1("rct signature semantics check failed");
+ return false;
+ }
+ break;
+ case rct::RCTTypeFull:
+ if (!rct::verRct(rv, true))
+ {
+ LOG_PRINT_RED_L1("rct signature semantics check failed");
+ return false;
+ }
+ break;
+ default:
+ LOG_PRINT_RED_L1("Unknown rct type: " << rv.type);
+ return false;
+ }
+ }
return true;
}
@@ -640,13 +687,13 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
- bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed)
+ bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{
crypto::hash tx_hash = get_transaction_hash(tx);
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
blobdata bl;
t_serializable_object_to_blob(tx, bl);
- return add_new_tx(tx, tx_hash, tx_prefix_hash, bl.size(), tvc, keeped_by_block, relayed);
+ return add_new_tx(tx, tx_hash, tx_prefix_hash, bl.size(), tvc, keeped_by_block, relayed, do_not_relay);
}
//-----------------------------------------------------------------------------------------------
size_t core::get_blockchain_total_transactions() const
@@ -654,7 +701,7 @@ namespace cryptonote
return m_blockchain_storage.get_total_transactions();
}
//-----------------------------------------------------------------------------------------------
- bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed)
+ bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{
if(m_mempool.have_tx(tx_hash))
{
@@ -669,7 +716,7 @@ namespace cryptonote
}
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
- return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, keeped_by_block, relayed, version);
+ return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version);
}
//-----------------------------------------------------------------------------------------------
bool core::relay_txpool_transactions()
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index a9e80aeee..fa67ff265 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -107,10 +107,11 @@ namespace cryptonote
* @param tvc metadata about the transaction's validity
* @param keeped_by_block if the transaction has been in a block
* @param relayed whether or not the transaction was relayed to us
+ * @param do_not_relay whether to prevent the transaction from being relayed
*
* @return true if the transaction made it to the transaction pool, otherwise false
*/
- bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed);
+ bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
/**
* @brief handles an incoming block
@@ -641,9 +642,10 @@ namespace cryptonote
* @param tx_prefix_hash the transaction prefix' hash
* @param blob_size the size of the transaction
* @param relayed whether or not the transaction was relayed to us
+ * @param do_not_relay whether to prevent the transaction from being relayed
*
*/
- bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed);
+ bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
/**
* @brief add a new transaction to the transaction pool
@@ -654,12 +656,13 @@ namespace cryptonote
* @param tvc return-by-reference metadata about the transaction's verification process
* @param keeped_by_block whether or not the transaction has been in a block
* @param relayed whether or not the transaction was relayed to us
+ * @param do_not_relay whether to prevent the transaction from being relayed
*
* @return true if the transaction is already in the transaction pool,
* is already in a block on the Blockchain, or is successfully added
* to the transaction pool
*/
- bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed);
+ bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
/**
* @copydoc Blockchain::add_new_block
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 59ac534fe..78d75f41f 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -83,7 +83,7 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, uint8_t version)
+ bool tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
{
PERF_TIMER(add_tx);
if (tx.version == 0)
@@ -177,6 +177,8 @@ namespace cryptonote
return false;
}
+ time_t receive_time = time(nullptr);
+
crypto::hash max_used_block_id = null_hash;
uint64_t max_used_block_height = 0;
tx_details txd;
@@ -198,9 +200,10 @@ namespace cryptonote
txd_p.first->second.last_failed_height = 0;
txd_p.first->second.last_failed_id = null_hash;
txd_p.first->second.kept_by_block = kept_by_block;
- txd_p.first->second.receive_time = time(nullptr);
+ txd_p.first->second.receive_time = receive_time;
txd_p.first->second.last_relayed_time = time(NULL);
txd_p.first->second.relayed = relayed;
+ txd_p.first->second.do_not_relay = do_not_relay;
tvc.m_verifivation_impossible = true;
tvc.m_added_to_pool = true;
}else
@@ -221,12 +224,13 @@ namespace cryptonote
txd_p.first->second.max_used_block_height = max_used_block_height;
txd_p.first->second.last_failed_height = 0;
txd_p.first->second.last_failed_id = null_hash;
- txd_p.first->second.receive_time = time(nullptr);
+ txd_p.first->second.receive_time = receive_time;
txd_p.first->second.last_relayed_time = time(NULL);
txd_p.first->second.relayed = relayed;
+ txd_p.first->second.do_not_relay = do_not_relay;
tvc.m_added_to_pool = true;
- if(txd_p.first->second.fee > 0)
+ if(txd_p.first->second.fee > 0 && !do_not_relay)
tvc.m_should_be_relayed = true;
}
@@ -246,17 +250,17 @@ namespace cryptonote
tvc.m_verifivation_failed = false;
- m_txs_by_fee.emplace((double)blob_size / fee, id);
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>((double)blob_size / fee, receive_time), id);
return true;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::add_tx(const transaction &tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, uint8_t version)
+ bool tx_memory_pool::add_tx(const transaction &tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay, uint8_t version)
{
crypto::hash h = null_hash;
size_t blob_size = 0;
get_transaction_hash(tx, h, blob_size);
- return add_tx(tx, h, blob_size, tvc, keeped_by_block, relayed, version);
+ return add_tx(tx, h, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version);
}
//---------------------------------------------------------------------------------
//FIXME: Can return early before removal of all of the key images.
@@ -292,7 +296,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed)
+ bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed, bool &do_not_relay)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
auto it = m_transactions.find(id);
@@ -301,16 +305,17 @@ namespace cryptonote
auto sorted_it = find_tx_in_sorted_container(id);
- if (sorted_it == m_txs_by_fee.end())
+ if (sorted_it == m_txs_by_fee_and_receive_time.end())
return false;
tx = it->second.tx;
blob_size = it->second.blob_size;
fee = it->second.fee;
relayed = it->second.relayed;
+ do_not_relay = it->second.do_not_relay;
remove_transaction_keyimages(it->second.tx);
m_transactions.erase(it);
- m_txs_by_fee.erase(sorted_it);
+ m_txs_by_fee_and_receive_time.erase(sorted_it);
return true;
}
//---------------------------------------------------------------------------------
@@ -321,7 +326,7 @@ namespace cryptonote
//---------------------------------------------------------------------------------
sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(const crypto::hash& id) const
{
- return std::find_if( m_txs_by_fee.begin(), m_txs_by_fee.end()
+ return std::find_if( m_txs_by_fee_and_receive_time.begin(), m_txs_by_fee_and_receive_time.end()
, [&](const sorted_tx_container::value_type& a){
return a.second == id;
}
@@ -342,13 +347,13 @@ namespace cryptonote
LOG_PRINT_L1("Tx " << it->first << " removed from tx pool due to outdated, age: " << tx_age );
remove_transaction_keyimages(it->second.tx);
auto sorted_it = find_tx_in_sorted_container(it->first);
- if (sorted_it == m_txs_by_fee.end())
+ if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
LOG_PRINT_L1("Removing tx " << it->first << " from tx pool, but it was not found in the sorted txs container!");
}
else
{
- m_txs_by_fee.erase(sorted_it);
+ m_txs_by_fee_and_receive_time.erase(sorted_it);
}
m_timed_out_transactions.insert(it->first);
auto pit = it++;
@@ -367,7 +372,7 @@ namespace cryptonote
for(auto it = m_transactions.begin(); it!= m_transactions.end();)
{
// 0 fee transactions are never relayed
- if(it->second.fee > 0 && now - it->second.last_relayed_time > get_relay_delay(now, it->second.receive_time))
+ if(it->second.fee > 0 && !it->second.do_not_relay && now - it->second.last_relayed_time > get_relay_delay(now, it->second.receive_time))
{
// if the tx is older than half the max lifetime, we don't re-relay it, to avoid a problem
// mentioned by smooth where nodes would flush txes at slightly different times, causing
@@ -431,6 +436,7 @@ namespace cryptonote
txi.receive_time = txd.receive_time;
txi.relayed = txd.relayed;
txi.last_relayed_time = txd.last_relayed_time;
+ txi.do_not_relay = txd.do_not_relay;
tx_infos.push_back(txi);
}
@@ -608,9 +614,9 @@ namespace cryptonote
size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
std::unordered_set<crypto::key_image> k_images;
- LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee.size() << " txes in the pool");
- auto sorted_it = m_txs_by_fee.begin();
- while (sorted_it != m_txs_by_fee.end())
+ LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
+ auto sorted_it = m_txs_by_fee_and_receive_time.begin();
+ while (sorted_it != m_txs_by_fee_and_receive_time.end())
{
auto tx_it = m_transactions.find(sorted_it->second);
LOG_PRINT_L2("Considering " << tx_it->first << ", size " << tx_it->second.blob_size << ", current block size " << total_size << "/" << max_total_size << ", current coinbase " << print_money(best_coinbase));
@@ -675,13 +681,13 @@ namespace cryptonote
LOG_PRINT_L1("Transaction " << get_transaction_hash(it->second.tx) << " is too big (" << it->second.blob_size << " bytes), removing it from pool");
remove_transaction_keyimages(it->second.tx);
auto sorted_it = find_tx_in_sorted_container(it->first);
- if (sorted_it == m_txs_by_fee.end())
+ if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
LOG_PRINT_L1("Removing tx " << it->first << " from tx pool, but it was not found in the sorted txs container!");
}
else
{
- m_txs_by_fee.erase(sorted_it);
+ m_txs_by_fee_and_receive_time.erase(sorted_it);
}
auto pit = it++;
m_transactions.erase(pit);
@@ -712,14 +718,14 @@ namespace cryptonote
LOG_ERROR("Failed to load memory pool from file " << state_file_path);
m_transactions.clear();
- m_txs_by_fee.clear();
+ m_txs_by_fee_and_receive_time.clear();
m_spent_key_images.clear();
}
// no need to store queue of sorted transactions, as it's easy to generate.
for (const auto& tx : m_transactions)
{
- m_txs_by_fee.emplace((double)tx.second.blob_size / tx.second.fee, tx.first);
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>((double)tx.second.blob_size / tx.second.fee, tx.second.receive_time), tx.first);
}
// Ignore deserialization error
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 32a05b0f4..2712f75bb 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -54,23 +54,25 @@ namespace cryptonote
/************************************************************************/
//! pair of <transaction fee, transaction hash> for organization
- typedef std::pair<double, crypto::hash> tx_by_fee_entry;
+ typedef std::pair<std::pair<double, std::time_t>, crypto::hash> tx_by_fee_and_receive_time_entry;
class txCompare
{
public:
- bool operator()(const tx_by_fee_entry& a, const tx_by_fee_entry& b)
+ bool operator()(const tx_by_fee_and_receive_time_entry& a, const tx_by_fee_and_receive_time_entry& b)
{
// sort by greatest first, not least
- if (a.first > b.first) return true;
- else if (a.first < b.first) return false;
+ if (a.first.first > b.first.first) return true;
+ else if (a.first.first < b.first.first) return false;
+ else if (a.first.second < b.first.second) return true;
+ else if (a.first.second > b.first.second) return false;
else if (a.second != b.second) return true;
else return false;
}
};
//! container for sorting transactions by fee per unit size
- typedef std::set<tx_by_fee_entry, txCompare> sorted_tx_container;
+ typedef std::set<tx_by_fee_and_receive_time_entry, txCompare> sorted_tx_container;
/**
* @brief Transaction pool, handles transactions which are not part of a block
@@ -103,7 +105,7 @@ namespace cryptonote
* @param id the transaction's hash
* @param blob_size the transaction's size
*/
- bool add_tx(const transaction &tx, const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, uint8_t version);
+ bool add_tx(const transaction &tx, const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
/**
* @brief add a transaction to the transaction pool
@@ -117,11 +119,12 @@ namespace cryptonote
* @param tvc return-by-reference status about the transaction verification
* @param kept_by_block has this transaction been in a block?
* @param relayed was this transaction from the network or a local client?
+ * @param do_not_relay to avoid relaying the transaction to the network
* @param version the version used to create the transaction
*
* @return true if the transaction passes validations, otherwise false
*/
- bool add_tx(const transaction &tx, tx_verification_context& tvc, bool kept_by_block, bool relayed, uint8_t version);
+ bool add_tx(const transaction &tx, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
/**
* @brief takes a transaction with the given hash from the pool
@@ -131,10 +134,11 @@ namespace cryptonote
* @param blob_size return-by-reference the transaction's size
* @param fee the transaction fee
* @param relayed return-by-reference was transaction relayed to us by the network?
+ * @param do_not_relay return-by-reference is transaction not to be relayed to the network?
*
* @return true unless the transaction cannot be found in the pool
*/
- bool take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed);
+ bool take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed, bool &do_not_relay);
/**
* @brief checks if the pool has a transaction with the given hash
@@ -303,7 +307,7 @@ namespace cryptonote
#define CURRENT_MEMPOOL_ARCHIVE_VER 11
-#define CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER 11
+#define CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER 12
/**
* @brief serialize the transaction pool to/from disk
@@ -362,6 +366,7 @@ namespace cryptonote
time_t last_relayed_time; //!< the last time the transaction was relayed to the network
bool relayed; //!< whether or not the transaction has been relayed to the network
+ bool do_not_relay; //!< to avoid relay this transaction to the network
};
private:
@@ -473,7 +478,8 @@ private:
epee::math_helper::once_a_time_seconds<30> m_remove_stuck_tx_interval;
//TODO: look into doing this better
- sorted_tx_container m_txs_by_fee; //!< container for transactions organized by fee per size
+ //!< container for transactions organized by fee per size and receive time
+ sorted_tx_container m_txs_by_fee_and_receive_time;
/**
* @brief get an iterator to a transaction in the sorted container
@@ -515,6 +521,9 @@ namespace boost
if (version < 11)
return;
ar & td.kept_by_block;
+ if (version < 12)
+ return;
+ ar & td.do_not_relay;
}
}
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index b13c1f437..54f1c849e 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -328,7 +328,7 @@ namespace cryptonote
for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++)
{
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(*tx_blob_it, tvc, true, true);
+ m_core.handle_incoming_tx(*tx_blob_it, tvc, true, true, false);
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
@@ -478,7 +478,7 @@ namespace cryptonote
if(!m_core.get_pool_transaction(tx_hash, tx))
{
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true) || tvc.m_verifivation_failed)
+ if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true, false) || tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
m_p2p->drop_connection(context);
@@ -682,7 +682,7 @@ namespace cryptonote
for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end();)
{
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(*tx_blob_it, tvc, false, true);
+ m_core.handle_incoming_tx(*tx_blob_it, tvc, false, true, false);
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
@@ -874,7 +874,7 @@ namespace cryptonote
BOOST_FOREACH(auto& tx_blob, block_entry.txs)
{
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(tx_blob, tvc, true, true);
+ m_core.handle_incoming_tx(tx_blob, tvc, true, true, false);
if(tvc.m_verifivation_failed)
{
LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 7381dd06f..9d28cd41e 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -511,4 +511,22 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a
return m_executor.alt_chain_info();
}
+bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector<std::string>& args)
+{
+ if(args.size() != 1)
+ {
+ std::cout << "Exactly one parameter is needed" << std::endl;
+ return false;
+ }
+
+ uint64_t nblocks = 0;
+ if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]) || nblocks == 0)
+ {
+ std::cout << "wrong number of blocks" << std::endl;
+ return false;
+ }
+
+ return m_executor.print_blockchain_dynamic_stats(nblocks);
+}
+
} // namespace daemonize
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index cc929db00..7763ebed0 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -121,6 +121,8 @@ public:
bool print_coinbase_tx_sum(const std::vector<std::string>& args);
bool alt_chain_info(const std::vector<std::string>& args);
+
+ bool print_blockchain_dynamic_stats(const std::vector<std::string>& args);
};
} // namespace daemonize
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 88c49d111..086478a47 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -230,6 +230,11 @@ t_command_server::t_command_server(
, std::bind(&t_command_parser_executor::alt_chain_info, &m_parser, p::_1)
, "Print information about alternative chains"
);
+ m_command_lookup.set_handler(
+ "bc_dyn_stats"
+ , std::bind(&t_command_parser_executor::print_blockchain_dynamic_stats, &m_parser, p::_1)
+ , "Print information about current blockchain dynamic state"
+ );
}
bool t_command_server::process_command_str(const std::string& cmd)
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 447783d76..c7a122d00 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -743,6 +743,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() {
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
<< "relayed: " << [&](const cryptonote::tx_info &tx_info)->std::string { if (!tx_info.relayed) return "no"; return boost::lexical_cast<std::string>(tx_info.last_relayed_time) + " (" + get_human_time_ago(tx_info.last_relayed_time, now) + ")"; } (tx_info) << std::endl
+ << "do_not_relay: " << (tx_info.do_not_relay ? 'T' : 'F') << std::endl
<< "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl
<< "max_used_block_height: " << tx_info.max_used_block_height << std::endl
<< "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl
@@ -823,6 +824,7 @@ bool t_rpc_command_executor::print_transaction_pool_short() {
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
<< "relayed: " << [&](const cryptonote::tx_info &tx_info)->std::string { if (!tx_info.relayed) return "no"; return boost::lexical_cast<std::string>(tx_info.last_relayed_time) + " (" + get_human_time_ago(tx_info.last_relayed_time, now) + ")"; } (tx_info) << std::endl
+ << "do_not_relay: " << (tx_info.do_not_relay ? 'T' : 'F') << std::endl
<< "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl
<< "max_used_block_height: " << tx_info.max_used_block_height << std::endl
<< "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl
@@ -1406,5 +1408,108 @@ bool t_rpc_command_executor::alt_chain_info()
return true;
}
+bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks)
+{
+ cryptonote::COMMAND_RPC_GET_INFO::request ireq;
+ cryptonote::COMMAND_RPC_GET_INFO::response ires;
+ cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request bhreq;
+ cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response bhres;
+ cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request fereq;
+ cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response feres;
+ epee::json_rpc::error error_resp;
+
+ std::string fail_message = "Problem fetching info";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(ireq, ires, "/getinfo", fail_message.c_str()))
+ {
+ return true;
+ }
+ if (!m_rpc_client->rpc_request(fereq, feres, "/get_fee_estimate", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_info(ireq, ires) || ires.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << fail_message.c_str();
+ return true;
+ }
+ if (!m_rpc_server->on_get_per_kb_fee_estimate(fereq, feres, error_resp) || feres.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << fail_message.c_str();
+ return true;
+ }
+ }
+
+ tools::msg_writer() << "Height: " << ires.height << ", diff " << ires.difficulty << ", cum. diff " << ires.cumulative_difficulty
+ << ", target " << ires.target << " sec" << ", dyn fee " << cryptonote::print_money(feres.fee) << "/kB";
+
+ if (nblocks > 0)
+ {
+ if (nblocks > ires.height)
+ nblocks = ires.height;
+
+ bhreq.start_height = ires.height - nblocks;
+ bhreq.end_height = ires.height - 1;
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(bhreq, bhres, "/getblockheadersrange", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_block_headers_range(bhreq, bhres, error_resp) || bhres.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << fail_message.c_str();
+ return true;
+ }
+ }
+
+ double avgdiff = 0;
+ double avgnumtxes = 0;
+ double avgreward = 0;
+ std::vector<uint64_t> sizes;
+ sizes.reserve(nblocks);
+ std::vector<unsigned> major_versions(256, 0), minor_versions(256, 0);
+ for (const auto &bhr: bhres.headers)
+ {
+ avgdiff += bhr.difficulty;
+ avgnumtxes += bhr.num_txes;
+ avgreward += bhr.reward;
+ sizes.push_back(bhr.block_size);
+ static_assert(sizeof(bhr.major_version) == 1, "major_version expected to be uint8_t");
+ static_assert(sizeof(bhr.minor_version) == 1, "major_version expected to be uint8_t");
+ major_versions[(unsigned)bhr.major_version]++;
+ minor_versions[(unsigned)bhr.minor_version]++;
+ }
+ avgdiff /= nblocks;
+ avgnumtxes /= nblocks;
+ avgreward /= nblocks;
+ uint64_t median_block_size = epee::misc_utils::median(sizes);
+ tools::msg_writer() << "Last " << nblocks << ": avg. diff " << (uint64_t)avgdiff << ", avg num txes " << avgnumtxes
+ << ", avg. reward " << cryptonote::print_money(avgreward) << ", median block size " << median_block_size;
+
+ unsigned int max_major = 256, max_minor = 256;
+ while (max_major > 0 && !major_versions[--max_major]);
+ while (max_minor > 0 && !minor_versions[--max_minor]);
+ std::string s = "";
+ for (unsigned n = 0; n <= max_major; ++n)
+ if (major_versions[n])
+ s += (s.empty() ? "" : ", ") + boost::lexical_cast<std::string>(major_versions[n]) + std::string(" v") + boost::lexical_cast<std::string>(n);
+ tools::msg_writer() << "Block versions: " << s;
+ s = "";
+ for (unsigned n = 0; n <= max_minor; ++n)
+ if (minor_versions[n])
+ s += (s.empty() ? "" : ", ") + boost::lexical_cast<std::string>(minor_versions[n]) + std::string(" v") + boost::lexical_cast<std::string>(n);
+ tools::msg_writer() << "Voting for: " << s;
+ }
+ return true;
+}
}// namespace daemonize
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index a6c712c04..af283c1f1 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -139,6 +139,8 @@ public:
bool print_coinbase_tx_sum(uint64_t height, uint64_t count);
bool alt_chain_info();
+
+ bool print_blockchain_dynamic_stats(uint64_t nblocks);
};
} // namespace daemonize
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 4f8782cdf..1e4f1e852 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -710,45 +710,56 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
- bool verRct(const rctSig & rv) {
+ bool verRct(const rctSig & rv, bool semantics) {
PERF_TIMER(verRct);
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
- CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
- CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
- CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG");
+ if (semantics)
+ {
+ CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
+ CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
+ CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG");
+ }
+ else
+ {
+ // semantics check is early, we don't have the MGs resolved yet
+ }
// some rct ops can throw
try
{
- std::deque<bool> results(rv.outPk.size(), false);
- tools::thread_group threadpool(tools::thread_group::optimal_with_max(rv.outPk.size()));
+ if (semantics) {
+ std::deque<bool> results(rv.outPk.size(), false);
+ tools::thread_group threadpool(tools::thread_group::optimal_with_max(rv.outPk.size()));
+
+ tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
+ DP("range proofs verified?");
+ for (size_t i = 0; i < rv.outPk.size(); i++) {
+ region.run([&, i] {
+ results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
+ });
+ }
+ });
- tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
- DP("range proofs verified?");
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- region.run([&, i] {
- results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
- });
+ for (size_t i = 0; i < rv.outPk.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("Range proof verified failed for output " << i);
+ return false;
+ }
}
- });
+ }
- for (size_t i = 0; i < rv.outPk.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for output " << i);
+ if (!semantics) {
+ //compute txn fee
+ key txnFeeKey = scalarmultH(d2h(rv.txnFee));
+ bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
+ DP("mg sig verified?");
+ DP(mgVerd);
+ if (!mgVerd) {
+ LOG_PRINT_L1("MG signature verification failed");
return false;
}
}
- //compute txn fee
- key txnFeeKey = scalarmultH(d2h(rv.txnFee));
- bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
- DP("mg sig verified?");
- DP(mgVerd);
- if (!mgVerd) {
- LOG_PRINT_L1("MG signature verification failed");
- return false;
- }
-
return true;
}
catch(...)
@@ -759,76 +770,86 @@ namespace rct {
//ver RingCT simple
//assumes only post-rct style inputs (at least for max anonymity)
- bool verRctSimple(const rctSig & rv) {
+ bool verRctSimple(const rctSig & rv, bool semantics) {
try
{
PERF_TIMER(verRctSimple);
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
- CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
- CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
- CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
- CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
+ if (semantics)
+ {
+ CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
+ CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
+ }
+ else
+ {
+ // semantics check is early, and mixRing/MGs aren't resolved yet
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
+ }
const size_t threads = std::max(rv.outPk.size(), rv.mixRing.size());
std::deque<bool> results(threads);
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
- results.clear();
- results.resize(rv.outPk.size());
- tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- region.run([&, i] {
- results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
- });
- }
- });
+ if (semantics) {
+ results.clear();
+ results.resize(rv.outPk.size());
+ tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
+ for (size_t i = 0; i < rv.outPk.size(); i++) {
+ region.run([&, i] {
+ results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
+ });
+ }
+ });
- for (size_t i = 0; i < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for output " << i);
- return false;
+ for (size_t i = 0; i < results.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("Range proof verified failed for output " << i);
+ return false;
+ }
}
- }
-
- key sumOutpks = identity();
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
- }
- DP(sumOutpks);
- key txnFeeKey = scalarmultH(d2h(rv.txnFee));
- addKeys(sumOutpks, txnFeeKey, sumOutpks);
- key message = get_pre_mlsag_hash(rv);
+ key sumOutpks = identity();
+ for (size_t i = 0; i < rv.outPk.size(); i++) {
+ addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
+ }
+ DP(sumOutpks);
+ key txnFeeKey = scalarmultH(d2h(rv.txnFee));
+ addKeys(sumOutpks, txnFeeKey, sumOutpks);
- results.clear();
- results.resize(rv.mixRing.size());
- tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
- for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
- region.run([&, i] {
- results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
- });
+ key sumPseudoOuts = identity();
+ for (size_t i = 0 ; i < rv.pseudoOuts.size() ; i++) {
+ addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
}
- });
+ DP(sumPseudoOuts);
- for (size_t i = 0; i < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("verRctMGSimple failed for input " << i);
- return false;
+ //check pseudoOuts vs Outs..
+ if (!equalKeys(sumPseudoOuts, sumOutpks)) {
+ LOG_PRINT_L1("Sum check failed");
+ return false;
}
}
+ else {
+ const key message = get_pre_mlsag_hash(rv);
- key sumPseudoOuts = identity();
- for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
- addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
- }
- DP(sumPseudoOuts);
-
- //check pseudoOuts vs Outs..
- if (!equalKeys(sumPseudoOuts, sumOutpks)) {
- LOG_PRINT_L1("Sum check failed");
- return false;
+ results.clear();
+ results.resize(rv.mixRing.size());
+ tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
+ for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
+ region.run([&, i] {
+ results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
+ });
+ }
+ });
+
+ for (size_t i = 0; i < results.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("verRctMGSimple failed for input " << i);
+ return false;
+ }
+ }
}
return true;
diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h
index 1fe4aa074..ca40ddd85 100644
--- a/src/ringct/rctSigs.h
+++ b/src/ringct/rctSigs.h
@@ -126,8 +126,10 @@ namespace rct {
rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin);
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin);
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk);
- bool verRct(const rctSig & rv);
- bool verRctSimple(const rctSig & rv);
+ bool verRct(const rctSig & rv, bool semantics);
+ static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
+ bool verRctSimple(const rctSig & rv, bool semantics);
+ static inline bool verRctSimple(const rctSig & rv) { return verRctSimple(rv, true) && verRctSimple(rv, false); }
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask);
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i);
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index ddf892cae..0cec3c26e 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -528,7 +528,7 @@ namespace cryptonote
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) || tvc.m_verifivation_failed)
+ if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed)
{
if (tvc.m_verifivation_failed)
{
@@ -558,7 +558,7 @@ namespace cryptonote
return true;
}
- if(!tvc.m_should_be_relayed || req.do_not_relay)
+ if(!tvc.m_should_be_relayed)
{
LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed");
res.reason = "Not relayed";
@@ -896,6 +896,7 @@ namespace cryptonote
response.difficulty = m_core.get_blockchain_storage().block_difficulty(height);
response.reward = get_block_reward(blk);
response.block_size = m_core.get_blockchain_storage().get_db().get_block_size(height);
+ response.num_txes = blk.tx_hashes.size();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index fa86c08e4..c1dc9ed6c 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -49,7 +49,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 1
-#define CORE_RPC_VERSION_MINOR 4
+#define CORE_RPC_VERSION_MINOR 5
#define CORE_RPC_VERSION (((CORE_RPC_VERSION_MAJOR)<<16)|(CORE_RPC_VERSION_MINOR))
struct COMMAND_RPC_GET_HEIGHT
@@ -706,6 +706,7 @@ namespace cryptonote
difficulty_type difficulty;
uint64_t reward;
uint64_t block_size;
+ uint64_t num_txes;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(major_version)
@@ -720,6 +721,7 @@ namespace cryptonote
KV_SERIALIZE(difficulty)
KV_SERIALIZE(reward)
KV_SERIALIZE(block_size)
+ KV_SERIALIZE(num_txes)
END_KV_SERIALIZE_MAP()
};
@@ -920,6 +922,7 @@ namespace cryptonote
uint64_t receive_time;
bool relayed;
uint64_t last_relayed_time;
+ bool do_not_relay;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id_hash)
@@ -934,6 +937,7 @@ namespace cryptonote
KV_SERIALIZE(receive_time)
KV_SERIALIZE(relayed)
KV_SERIALIZE(last_relayed_time)
+ KV_SERIALIZE(do_not_relay)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index b878491ce..e397dac04 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -33,6 +33,7 @@
#include "wallet.h"
#include "crypto/hash.h"
#include "wallet/wallet2.h"
+#include "common_defines.h"
#include <vector>
@@ -43,30 +44,50 @@ AddressBook::~AddressBook() {}
AddressBookImpl::AddressBookImpl(WalletImpl *wallet)
: m_wallet(wallet) {}
-bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description)
+bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &payment_id_str, const std::string &description)
{
- LOG_PRINT_L2("Adding row");
-
clearStatus();
cryptonote::account_public_address addr;
- bool has_payment_id;
+ bool has_short_pid;
crypto::hash8 payment_id_short;
- if(!cryptonote::get_account_integrated_address_from_str(addr, has_payment_id, payment_id_short, m_wallet->m_wallet->testnet(), dst_addr)) {
- m_errorString = "Invalid destination address";
+ if(!cryptonote::get_account_integrated_address_from_str(addr, has_short_pid, payment_id_short, m_wallet->m_wallet->testnet(), dst_addr)) {
+ m_errorString = tr("Invalid destination address");
m_errorCode = Invalid_Address;
return false;
}
- crypto::hash pid32 = cryptonote::null_hash;
- bool long_pid = (payment_id.empty())? false : tools::wallet2::parse_long_payment_id(payment_id, pid32);
- if(!payment_id.empty() && !long_pid) {
- m_errorString = "Invalid payment ID";
+ crypto::hash payment_id = cryptonote::null_hash;
+ bool has_long_pid = (payment_id_str.empty())? false : tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
+
+ // Short payment id provided
+ if(payment_id_str.length() == 16) {
+ m_errorString = tr("Invalid payment ID. Short payment ID should only be used in an integrated address");
+ m_errorCode = Invalid_Payment_Id;
+ return false;
+ }
+
+ // long payment id provided but not valid
+ if(!payment_id_str.empty() && !has_long_pid) {
+ m_errorString = tr("Invalid payment ID");
+ m_errorCode = Invalid_Payment_Id;
+ return false;
+ }
+
+ // integrated + long payment id provided
+ if(has_long_pid && has_short_pid) {
+ m_errorString = tr("Integrated address and long payment id can't be used at the same time");
m_errorCode = Invalid_Payment_Id;
return false;
}
- bool r = m_wallet->m_wallet->add_address_book_row(addr,pid32,description);
+ // Pad short pid with zeros
+ if (has_short_pid)
+ {
+ memcpy(payment_id.data, payment_id_short.data, 8);
+ }
+
+ bool r = m_wallet->m_wallet->add_address_book_row(addr,payment_id,description);
if (r)
refresh();
else
@@ -87,7 +108,16 @@ void AddressBookImpl::refresh()
std::string payment_id = (row->m_payment_id == cryptonote::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id);
std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(),row->m_address);
-
+ // convert the zero padded short payment id to integrated address
+ if (payment_id.length() > 16 && payment_id.substr(16).find_first_not_of('0') == std::string::npos) {
+ payment_id = payment_id.substr(0,16);
+ crypto::hash8 payment_id_short;
+ if(tools::wallet2::parse_short_payment_id(payment_id, payment_id_short)) {
+ address = cryptonote::get_account_integrated_address_as_str(m_wallet->m_wallet->testnet(), row->m_address, payment_id_short);
+ // Don't show payment id when integrated address is used
+ payment_id = "";
+ }
+ }
AddressBookRow * abr = new AddressBookRow(i, address, payment_id, row->m_description);
m_rows.push_back(abr);
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index e8ae7c642..5f7d8e522 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -54,6 +54,8 @@ namespace {
static const int MAX_REFRESH_INTERVAL_MILLIS = 1000 * 60 * 1;
// Default refresh interval when connected to remote node
static const int DEFAULT_REMOTE_NODE_REFRESH_INTERVAL_MILLIS = 1000 * 10;
+ // Connection timeout 30 sec
+ static const int DEFAULT_CONNECTION_TIMEOUT_MILLIS = 1000 * 30;
}
struct Wallet2CallbackImpl : public tools::i_wallet2_callback
@@ -83,7 +85,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
virtual void on_new_block(uint64_t height, const cryptonote::block& block)
{
- LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height);
+ //LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height);
if (m_listener) {
m_listener->newBlock(height);
@@ -662,25 +664,68 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file
bool WalletImpl::submitTransaction(const string &fileName) {
clearStatus();
- PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
+ std::unique_ptr<PendingTransactionImpl> transaction(new PendingTransactionImpl(*this));
-// bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx, [&](const tools::wallet2::signed_tx_set &tx){ return accept_loaded_tx(tx); });
bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx);
if (!r) {
m_errorString = tr("Failed to load transaction from file");
m_status = Status_Ok;
- delete transaction;
return false;
}
if(!transaction->commit()) {
m_errorString = transaction->m_errorString;
m_status = Status_Error;
- delete transaction;
return false;
}
- delete transaction;
+ return true;
+}
+
+bool WalletImpl::exportKeyImages(const string &filename)
+{
+ if (m_wallet->watch_only())
+ {
+ m_errorString = tr("Wallet is view only");
+ m_status = Status_Error;
+ return false;
+ }
+
+ try
+ {
+ if (!m_wallet->export_key_images(filename))
+ {
+ m_errorString = tr("failed to save file ") + filename;
+ m_status = Status_Error;
+ return false;
+ }
+ }
+ catch (std::exception &e)
+ {
+ LOG_ERROR("Error exporting key images: " << e.what());
+ m_errorString = e.what();
+ m_status = Status_Error;
+ return false;
+ }
+ return true;
+}
+
+bool WalletImpl::importKeyImages(const string &filename)
+{
+ try
+ {
+ uint64_t spent = 0, unspent = 0;
+ uint64_t height = m_wallet->import_key_images(filename, spent, unspent);
+ LOG_PRINT_L2("Signed key images imported to height " << height << ", "
+ << print_money(spent) << " spent, " << print_money(unspent) << " unspent");
+ }
+ catch (const std::exception &e)
+ {
+ LOG_ERROR("Error exporting key images: " << e.what());
+ m_errorString = string(tr("Failed to import key images: ")) + e.what();
+ m_status = Status_Error;
+ return false;
+ }
return true;
}
@@ -1043,7 +1088,7 @@ bool WalletImpl::verifySignedMessage(const std::string &message, const std::stri
bool WalletImpl::connectToDaemon()
{
- bool result = m_wallet->check_connection();
+ bool result = m_wallet->check_connection(NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
m_status = result ? Status_Ok : Status_Error;
if (!result) {
m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address();
@@ -1056,7 +1101,7 @@ bool WalletImpl::connectToDaemon()
Wallet::ConnectionStatus WalletImpl::connected() const
{
uint32_t version = 0;
- m_is_connected = m_wallet->check_connection(&version);
+ m_is_connected = m_wallet->check_connection(&version, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
if (!m_is_connected)
return Wallet::ConnectionStatus_Disconnected;
if ((version >> 16) != CORE_RPC_VERSION_MAJOR)
@@ -1217,6 +1262,24 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st
return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
}
+bool WalletImpl::rescanSpent()
+{
+ clearStatus();
+ if (!trustedDaemon()) {
+ m_status = Status_Error;
+ m_errorString = tr("Rescan spent can only be used with a trusted daemon");
+ return false;
+ }
+ try {
+ m_wallet->rescan_spent();
+ } catch (const std::exception &e) {
+ LOG_ERROR(__FUNCTION__ << " error: " << e.what());
+ m_status = Status_Error;
+ m_errorString = e.what();
+ return false;
+ }
+ return true;
+}
} // namespace
namespace Bitmonero = Monero;
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 5b4064e8e..e26f30d70 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -93,7 +93,7 @@ public:
void setRefreshFromBlockHeight(uint64_t refresh_from_block_height);
void setRecoveringFromSeed(bool recoveringFromSeed);
bool watchOnly() const;
-
+ bool rescanSpent();
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
@@ -102,6 +102,8 @@ public:
virtual PendingTransaction * createSweepUnmixableTransaction();
bool submitTransaction(const std::string &fileName);
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename);
+ bool exportKeyImages(const std::string &filename);
+ bool importKeyImages(const std::string &filename);
virtual void disposeTransaction(PendingTransaction * t);
virtual TransactionHistory * history() const;
@@ -127,6 +129,7 @@ private:
bool isNewWallet() const;
void doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
+
private:
friend class PendingTransactionImpl;
friend class UnsignedTransactionImpl;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 0ad74f52a..ccfe86ee0 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -2234,7 +2234,7 @@ bool wallet2::prepare_file_names(const std::string& file_path)
return true;
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::check_connection(uint32_t *version)
+bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
{
boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
@@ -2248,7 +2248,7 @@ bool wallet2::check_connection(uint32_t *version)
u.port = m_testnet ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT;
}
- if (!m_http_client.connect(u.host, std::to_string(u.port), 10000))
+ if (!m_http_client.connect(u.host, std::to_string(u.port), timeout))
return false;
}
@@ -2733,7 +2733,7 @@ float wallet2::get_output_relatedness(const transfer_details &td0, const transfe
return 0.0f;
}
//----------------------------------------------------------------------------------------------------
-size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers) const
+size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers, bool smallest) const
{
std::vector<size_t> candidates;
float best_relatedness = 1.0f;
@@ -2761,13 +2761,30 @@ size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::ve
if (relatedness == best_relatedness)
candidates.push_back(n);
}
- size_t idx = crypto::rand<size_t>() % candidates.size();
+
+ // we have all the least related outputs in candidates, so we can pick either
+ // the smallest, or a random one, depending on request
+ size_t idx;
+ if (smallest)
+ {
+ idx = 0;
+ for (size_t n = 0; n < candidates.size(); ++n)
+ {
+ const transfer_details &td = transfers[unused_indices[candidates[n]]];
+ if (td.amount() < transfers[unused_indices[candidates[idx]]].amount())
+ idx = n;
+ }
+ }
+ else
+ {
+ idx = crypto::rand<size_t>() % candidates.size();
+ }
return pop_index (unused_indices, candidates[idx]);
}
//----------------------------------------------------------------------------------------------------
-size_t wallet2::pop_best_value(std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers) const
+size_t wallet2::pop_best_value(std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers, bool smallest) const
{
- return pop_best_value_from(m_transfers, unused_indices, selected_transfers);
+ return pop_best_value_from(m_transfers, unused_indices, selected_transfers, smallest);
}
//----------------------------------------------------------------------------------------------------
// Select random input sources for transaction.
@@ -4109,8 +4126,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
}
- // while we have something to send
- while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee) {
+ // while:
+ // - we have something to send
+ // - or we need to gather more fee
+ // - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2)
+ while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || (use_rct && txes.back().selected_transfers.size() == 1)) {
TX &tx = txes.back();
// if we need to spend money and don't have any left, we fail
@@ -4121,7 +4141,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
// This could be more clever, but maybe at the cost of making probabilistic inferences easier
- size_t idx = !prefered_inputs.empty() ? pop_back(prefered_inputs) : !unused_transfers_indices.empty() ? pop_best_value(unused_transfers_indices, tx.selected_transfers) : pop_best_value(unused_dust_indices, tx.selected_transfers);
+ size_t idx;
+ if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee)
+ // the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too
+ idx = pop_best_value(unused_dust_indices.empty() ? unused_transfers_indices : unused_dust_indices, tx.selected_transfers, true);
+ else if (!prefered_inputs.empty())
+ idx = pop_back(prefered_inputs);
+ else
+ idx = pop_best_value(unused_transfers_indices.empty() ? unused_dust_indices : unused_transfers_indices, tx.selected_transfers);
const transfer_details &td = m_transfers[idx];
LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()) << ", ki " << td.m_key_image);
@@ -4228,13 +4255,19 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
else
{
LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
- if (use_rct)
- transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
- test_tx, test_ptx);
- else
- transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
- detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
- txBlob = t_serializable_object_to_blob(test_ptx.tx);
+ do {
+ if (use_rct)
+ transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
+ test_tx, test_ptx);
+ else
+ transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
+ detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
+ txBlob = t_serializable_object_to_blob(test_ptx.tx);
+ needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
+ LOG_PRINT_L2("Made an attempt at a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) <<
+ " fee and " << print_money(test_ptx.change_dts.amount) << " change");
+ } while (needed_fee > test_ptx.fee);
+
LOG_PRINT_L2("Made a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) <<
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 7f25673d6..5a569950f 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -402,7 +402,7 @@ namespace tools
std::vector<wallet2::pending_tx> create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon);
std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
- bool check_connection(uint32_t *version = NULL);
+ bool check_connection(uint32_t *version = NULL, uint32_t timeout = 200000);
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0) const;
void get_payments(std::list<std::pair<crypto::hash,wallet2::payment_details>>& payments, uint64_t min_height, uint64_t max_height = (uint64_t)-1) const;
@@ -527,8 +527,8 @@ namespace tools
std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon);
std::vector<size_t> select_available_mixable_outputs(bool trusted_daemon);
- size_t pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers) const;
- size_t pop_best_value(std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers) const;
+ size_t pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers, bool smallest = false) const;
+ size_t pop_best_value(std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers, bool smallest = false) const;
void set_tx_note(const crypto::hash &txid, const std::string &note);
std::string get_tx_note(const crypto::hash &txid) const;
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index daffb48bf..5a13205c5 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -513,6 +513,21 @@ struct Wallet
*/
virtual void disposeTransaction(PendingTransaction * t) = 0;
+ /*!
+ * \brief exportKeyImages - exports key images to file
+ * \param filename
+ * \return - true on success
+ */
+ virtual bool exportKeyImages(const std::string &filename) = 0;
+
+ /*!
+ * \brief importKeyImages - imports key images from file
+ * \param filename
+ * \return - true on success
+ */
+ virtual bool importKeyImages(const std::string &filename) = 0;
+
+
virtual TransactionHistory * history() const = 0;
virtual AddressBook * addressBook() const = 0;
virtual void setListener(WalletListener *) = 0;
@@ -558,6 +573,11 @@ struct Wallet
virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
+ /*
+ * \brief rescanSpent - Rescan spent outputs - Can only be used with trusted daemon
+ * \return true on success
+ */
+ virtual bool rescanSpent() = 0;
};
/**
diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp
index 256faeccb..6202eea0d 100644
--- a/tests/core_proxy/core_proxy.cpp
+++ b/tests/core_proxy/core_proxy.cpp
@@ -165,7 +165,7 @@ string tx2str(const cryptonote::transaction& tx, const cryptonote::hash256& tx_h
return ss.str();
}*/
-bool tests::proxy_core::handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed) {
+bool tests::proxy_core::handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) {
if (!keeped_by_block)
return true;
diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h
index 31e876d06..bec9a83bb 100644
--- a/tests/core_proxy/core_proxy.h
+++ b/tests/core_proxy/core_proxy.h
@@ -74,7 +74,7 @@ namespace tests
bool get_stat_info(cryptonote::core_stat_info& st_inf){return true;}
bool have_block(const crypto::hash& id);
bool get_blockchain_top(uint64_t& height, crypto::hash& top_id);
- bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relaued);
+ bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
bool handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true);
void pause_mine(){}
void resume_mine(){}
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index 047d2c81c..ce204cd9d 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -368,7 +368,7 @@ public:
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
size_t pool_size = m_c.get_pool_transactions_count();
- m_c.handle_incoming_tx(t_serializable_object_to_blob(tx), tvc, m_txs_keeped_by_block, false);
+ m_c.handle_incoming_tx(t_serializable_object_to_blob(tx), tvc, m_txs_keeped_by_block, false, false);
bool tx_added = pool_size + 1 == m_c.get_pool_transactions_count();
bool r = check_tx_verification_context(tvc, tx_added, m_ev_index, tx, m_validator);
CHECK_AND_NO_ASSERT_MES(r, false, "tx verification context check failed");
@@ -425,7 +425,7 @@ public:
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
size_t pool_size = m_c.get_pool_transactions_count();
- m_c.handle_incoming_tx(sr_tx.data, tvc, m_txs_keeped_by_block, false);
+ m_c.handle_incoming_tx(sr_tx.data, tvc, m_txs_keeped_by_block, false, false);
bool tx_added = pool_size + 1 == m_c.get_pool_transactions_count();
cryptonote::transaction tx;
diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp
index 6b3f029d1..c6a3a14f0 100644
--- a/tests/unit_tests/ban.cpp
+++ b/tests/unit_tests/ban.cpp
@@ -49,7 +49,7 @@ public:
bool get_stat_info(cryptonote::core_stat_info& st_inf) const {return true;}
bool have_block(const crypto::hash& id) const {return true;}
bool get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=cryptonote::null_hash;return true;}
- bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relaued) { return true; }
+ bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
bool handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true) { return true; }
void pause_mine(){}
void resume_mine(){}
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index ca72f5e0e..be17f01ad 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -51,7 +51,7 @@ public:
virtual std::string get_db_name() const { return std::string(); }
virtual bool lock() { return true; }
virtual void unlock() { }
- virtual void batch_start(uint64_t batch_num_blocks=0) {}
+ virtual bool batch_start(uint64_t batch_num_blocks=0) {}
virtual void batch_stop() {}
virtual void set_batch_transactions(bool) {}
virtual void block_txn_start(bool readonly=false) {}
diff --git a/tests/unit_tests/main.cpp b/tests/unit_tests/main.cpp
index faaf9475a..856e81857 100644
--- a/tests/unit_tests/main.cpp
+++ b/tests/unit_tests/main.cpp
@@ -34,6 +34,7 @@
int main(int argc, char** argv)
{
+ epee::string_tools::set_module_name_and_folder(argv[0]);
epee::debug::get_set_enable_assert(true, false);
::testing::InitGoogleTest(&argc, argv);
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index 2be7bde8c..1083dd4cc 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -657,7 +657,7 @@ TEST(Serialization, portability_wallet)
const bool testnet = true;
const bool restricted = false;
tools::wallet2 w(testnet, restricted);
- string wallet_file = "../data/wallet_9svHk1";
+ string wallet_file = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/wallet_9svHk1";
string password = "test";
bool r = false;
try
@@ -777,7 +777,7 @@ TEST(Serialization, portability_wallet)
TEST(Serialization, portability_outputs)
{
// read file
- const std::string filename = "../data/outputs";
+ const std::string filename = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/outputs";
std::string data;
bool r = epee::file_io_utils::load_file_to_string(filename, data);
ASSERT_TRUE(r);
@@ -892,7 +892,7 @@ TEST(Serialization, portability_outputs)
#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003"
TEST(Serialization, portability_unsigned_tx)
{
- const string filename = "../data/unsigned_monero_tx";
+ const string filename = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/unsigned_monero_tx";
std::string s;
const bool testnet = true;
bool r = epee::file_io_utils::load_file_to_string(filename, s);
@@ -1042,7 +1042,7 @@ TEST(Serialization, portability_unsigned_tx)
#define SIGNED_TX_PREFIX "Monero signed tx set\003"
TEST(Serialization, portability_signed_tx)
{
- const string filename = "../data/signed_monero_tx";
+ const string filename = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/signed_monero_tx";
const bool testnet = true;
std::string s;
bool r = epee::file_io_utils::load_file_to_string(filename, s);