aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/blockchain_db/blockchain_db.h80
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp212
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h13
-rw-r--r--src/blockchain_db/testdb.h8
-rw-r--r--src/blockchain_utilities/blockchain_blackball.cpp1
-rw-r--r--src/blockchain_utilities/blockchain_export.cpp2
-rw-r--r--src/blocks/checkpoints.datbin221956 -> 234980 bytes
-rw-r--r--src/checkpoints/checkpoints.cpp1
-rw-r--r--src/common/dns_utils.cpp1
-rw-r--r--src/common/rpc_client.h4
-rw-r--r--src/crypto/keccak.c12
-rw-r--r--src/crypto/slow-hash.c1
-rw-r--r--src/crypto/tree-hash.c12
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h2
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp6
-rw-r--r--src/cryptonote_basic/miner.cpp14
-rw-r--r--src/cryptonote_basic/miner.h2
-rw-r--r--src/cryptonote_core/blockchain.cpp250
-rw-r--r--src/cryptonote_core/blockchain.h34
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp23
-rw-r--r--src/cryptonote_core/cryptonote_core.h1
-rw-r--r--src/cryptonote_core/tx_pool.cpp18
-rw-r--r--src/cryptonote_core/tx_sanity_check.cpp2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h7
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h1
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl43
-rw-r--r--src/daemon/command_parser_executor.cpp48
-rw-r--r--src/daemon/command_parser_executor.h8
-rw-r--r--src/daemon/command_server.cpp21
-rw-r--r--src/daemon/command_server.h2
-rw-r--r--src/daemon/daemon.cpp3
-rw-r--r--src/daemon/main.cpp6
-rw-r--r--src/daemon/rpc_command_executor.cpp124
-rw-r--r--src/daemon/rpc_command_executor.h16
-rw-r--r--src/debug_utilities/CMakeLists.txt22
-rw-r--r--src/debug_utilities/dns_checks.cpp149
-rw-r--r--src/device/device_ledger.cpp14
-rw-r--r--src/device/device_ledger.hpp1
-rw-r--r--src/net/error.h3
-rw-r--r--src/net/parse.cpp23
-rw-r--r--src/net/parse.h13
-rw-r--r--src/p2p/net_node.cpp2
-rw-r--r--src/p2p/net_node.h25
-rw-r--r--src/p2p/net_node.inl198
-rw-r--r--src/p2p/net_node_common.h11
-rw-r--r--src/p2p/net_peerlist.h20
-rw-r--r--src/p2p/net_peerlist_boost_serialization.h10
-rw-r--r--src/ringct/multiexp.cc1
-rw-r--r--src/ringct/rctTypes.cpp1
-rw-r--r--src/ringct/rctTypes.h8
-rw-r--r--src/rpc/core_rpc_server.cpp190
-rw-r--r--src/rpc/core_rpc_server.h6
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h81
-rw-r--r--src/rpc/daemon_handler.cpp5
-rw-r--r--src/rpc/rpc_args.cpp82
-rw-r--r--src/rpc/rpc_args.h18
-rw-r--r--src/serialization/binary_archive.h3
-rw-r--r--src/serialization/serialization.h2
-rw-r--r--src/simplewallet/simplewallet.cpp60
-rw-r--r--src/simplewallet/simplewallet.h1
-rw-r--r--src/version.cpp.in2
-rw-r--r--src/wallet/api/wallet.cpp11
-rw-r--r--src/wallet/api/wallet.h4
-rw-r--r--src/wallet/api/wallet2_api.h13
-rw-r--r--src/wallet/api/wallet_manager.cpp3
-rw-r--r--src/wallet/api/wallet_manager.h1
-rw-r--r--src/wallet/wallet2.cpp24
-rw-r--r--src/wallet/wallet2.h2
-rw-r--r--src/wallet/wallet_rpc_server.cpp71
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h1
71 files changed, 1466 insertions, 595 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index da6d76d97..8a21763c8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -133,7 +133,7 @@ if(NOT IOS)
add_subdirectory(blockchain_utilities)
endif()
-if(CMAKE_BUILD_TYPE STREQUAL Debug)
+if(BUILD_DEBUG_UTILITIES)
add_subdirectory(debug_utilities)
endif()
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 567be6a65..bb4de3ce6 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -129,6 +129,15 @@ struct tx_data_t
};
#pragma pack(pop)
+struct alt_block_data_t
+{
+ uint64_t height;
+ uint64_t cumulative_weight;
+ uint64_t cumulative_difficulty_low;
+ uint64_t cumulative_difficulty_high;
+ uint64_t already_generated_coins;
+};
+
/**
* @brief a struct containing txpool per transaction metadata
*/
@@ -754,6 +763,21 @@ public:
virtual void batch_stop() = 0;
/**
+ * @brief aborts a batch transaction
+ *
+ * If the subclass implements batching, this function should abort the
+ * batch it is currently on.
+ *
+ * If no batch is 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 any of this cannot be done, the subclass should throw the corresponding
+ * subclass of DB_EXCEPTION
+ */
+ virtual void batch_abort() = 0;
+
+ /**
* @brief sets whether or not to batch transactions
*
* If the subclass implements batching, this function tells it to begin
@@ -1528,8 +1552,45 @@ public:
*
* @param: sz the block size
*/
-
virtual void add_max_block_size(uint64_t sz) = 0;
+
+ /**
+ * @brief add a new alternative block
+ *
+ * @param: blkid the block hash
+ * @param: data: the metadata for the block
+ * @param: blob: the block's blob
+ */
+ virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob) = 0;
+
+ /**
+ * @brief get an alternative block by hash
+ *
+ * @param: blkid the block hash
+ * @param: data: the metadata for the block
+ * @param: blob: the block's blob
+ *
+ * @return true if the block was found in the alternative blocks list, false otherwise
+ */
+ virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob) = 0;
+
+ /**
+ * @brief remove an alternative block
+ *
+ * @param: blkid the block hash
+ */
+ virtual void remove_alt_block(const crypto::hash &blkid) = 0;
+
+ /**
+ * @brief get the number of alternative blocks stored
+ */
+ virtual uint64_t get_alt_block_count() = 0;
+
+ /**
+ * @brief drop all alternative blocks
+ */
+ virtual void drop_alt_blocks() = 0;
+
/**
* @brief runs a function over all txpool transactions
*
@@ -1619,6 +1680,23 @@ public:
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const = 0;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const = 0;
+ /**
+ * @brief runs a function over all alternative blocks stored
+ *
+ * The subclass should run the passed function for each alt block it has
+ * stored, passing (blkid, data, blob) as its parameters.
+ *
+ * If any call to the function returns false, the subclass should return
+ * false. Otherwise, the subclass returns true.
+ *
+ * The subclass should throw DB_ERROR if any of the expected values are
+ * not found. Current implementations simply return false.
+ *
+ * @param std::function f the function to run
+ *
+ * @return false if the function returns false for any output, otherwise true
+ */
+ virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const = 0;
//
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index a03a0989b..78db37b5a 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -194,6 +194,8 @@ namespace
* txpool_meta txn hash txn metadata
* txpool_blob txn hash txn blob
*
+ * alt_blocks block hash {block data, block blob}
+ *
* Note: where the data items are of uniform size, DUPFIXED tables have
* been used to save space. In most of these cases, a dummy "zerokval"
* key is used when accessing the table; the Key listed above will be
@@ -221,6 +223,8 @@ const char* const LMDB_SPENT_KEYS = "spent_keys";
const char* const LMDB_TXPOOL_META = "txpool_meta";
const char* const LMDB_TXPOOL_BLOB = "txpool_blob";
+const char* const LMDB_ALT_BLOCKS = "alt_blocks";
+
const char* const LMDB_HF_STARTING_HEIGHTS = "hf_starting_heights";
const char* const LMDB_HF_VERSIONS = "hf_versions";
@@ -707,7 +711,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks, uin
++num_blocks_used;
}
if (my_rtxn) block_rtxn_stop();
- avg_block_size = total_block_size / num_blocks_used;
+ avg_block_size = total_block_size / (num_blocks_used ? num_blocks_used : 1);
MDEBUG("average block size across recent " << num_blocks_used << " blocks: " << avg_block_size);
}
estim:
@@ -1077,11 +1081,11 @@ void BlockchainLMDB::add_tx_amount_output_indices(const uint64_t tx_id,
int result = 0;
- int num_outputs = amount_output_indices.size();
+ size_t num_outputs = amount_output_indices.size();
MDB_val_set(k_tx_id, tx_id);
MDB_val v;
- v.mv_data = (void *)amount_output_indices.data();
+ v.mv_data = num_outputs ? (void *)amount_output_indices.data() : (void*)"";
v.mv_size = sizeof(uint64_t) * num_outputs;
// LOG_PRINT_L1("tx_outputs[tx_hash] size: " << v.mv_size);
@@ -1400,6 +1404,8 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
lmdb_db_open(txn, LMDB_TXPOOL_META, MDB_CREATE, m_txpool_meta, "Failed to open db handle for m_txpool_meta");
lmdb_db_open(txn, LMDB_TXPOOL_BLOB, MDB_CREATE, m_txpool_blob, "Failed to open db handle for m_txpool_blob");
+ lmdb_db_open(txn, LMDB_ALT_BLOCKS, MDB_CREATE, m_alt_blocks, "Failed to open db handle for m_alt_blocks");
+
// this subdb is dropped on sight, so it may not be present when we open the DB.
// Since we use MDB_CREATE, we'll get an exception if we open read-only and it does not exist.
// So we don't open for read-only, and also not drop below. It is not used elsewhere.
@@ -1423,6 +1429,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
mdb_set_compare(txn, m_txpool_meta, compare_hash32);
mdb_set_compare(txn, m_txpool_blob, compare_hash32);
+ mdb_set_compare(txn, m_alt_blocks, compare_hash32);
mdb_set_compare(txn, m_properties, compare_string);
if (!(mdb_flags & MDB_RDONLY))
@@ -1953,7 +1960,7 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
TIME_MEASURE_START(t);
- size_t n_total_records = 0, n_prunable_records = 0, n_pruned_records = 0;
+ size_t n_total_records = 0, n_prunable_records = 0, n_pruned_records = 0, commit_counter = 0;
uint64_t n_bytes = 0;
mdb_txn_safe txn;
@@ -2056,6 +2063,7 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
{
MDEBUG("Pruning at height " << block_height << "/" << blockchain_height);
++n_pruned_records;
+ ++commit_counter;
n_bytes += k.mv_size + v.mv_size;
result = mdb_cursor_del(c_txs_prunable, 0);
if (result)
@@ -2065,6 +2073,25 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
result = mdb_cursor_del(c_txs_prunable_tip, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to delete transaction tip data: ", result).c_str()));
+
+ if (mode != prune_mode_check && commit_counter >= 4096)
+ {
+ MDEBUG("Committing txn at checkpoint...");
+ txn.commit();
+ 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_cursor_open(txn, m_txs_pruned, &c_txs_pruned);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_pruned: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_txs_prunable, &c_txs_prunable);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_prunable: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_txs_prunable_tip, &c_txs_prunable_tip);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_prunable_tip: ", result).c_str()));
+ commit_counter = 0;
+ }
}
}
}
@@ -2134,6 +2161,7 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
result = mdb_cursor_del(c_txs_prunable, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to delete transaction prunable data: ", result).c_str()));
+ ++commit_counter;
}
}
}
@@ -2150,6 +2178,34 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
", seed " << epee::string_tools::to_string_hex(pruning_seed));
}
}
+
+ if (mode != prune_mode_check && commit_counter >= 4096)
+ {
+ MDEBUG("Committing txn at checkpoint...");
+ txn.commit();
+ 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_cursor_open(txn, m_txs_pruned, &c_txs_pruned);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_pruned: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_txs_prunable, &c_txs_prunable);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_prunable: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_txs_prunable_tip, &c_txs_prunable_tip);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs_prunable_tip: ", result).c_str()));
+ result = mdb_cursor_open(txn, m_tx_indices, &c_tx_indices);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to open a cursor for tx_indices: ", result).c_str()));
+ MDB_val val;
+ val.mv_size = sizeof(ti);
+ val.mv_data = (void *)&ti;
+ result = mdb_cursor_get(c_tx_indices, (MDB_val*)&zerokval, &val, MDB_GET_BOTH);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to restore cursor for tx_indices: ", result).c_str()));
+ commit_counter = 0;
+ }
}
mdb_cursor_close(c_tx_indices);
}
@@ -2241,6 +2297,50 @@ bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&,
return ret;
}
+bool BlockchainLMDB::for_all_alt_blocks(std::function<bool(const crypto::hash&, const alt_block_data_t&, const cryptonote::blobdata*)> f, bool include_blob) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(alt_blocks);
+
+ MDB_val k;
+ MDB_val v;
+ bool ret = true;
+
+ MDB_cursor_op op = MDB_FIRST;
+ while (1)
+ {
+ int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, op);
+ op = MDB_NEXT;
+ if (result == MDB_NOTFOUND)
+ break;
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to enumerate alt blocks: ", result).c_str()));
+ const crypto::hash &blkid = *(const crypto::hash*)k.mv_data;
+ if (v.mv_size < sizeof(alt_block_data_t))
+ throw0(DB_ERROR("alt_blocks record is too small"));
+ const alt_block_data_t *data = (const alt_block_data_t*)v.mv_data;
+ const cryptonote::blobdata *passed_bd = NULL;
+ cryptonote::blobdata bd;
+ if (include_blob)
+ {
+ bd.assign(reinterpret_cast<const char*>(v.mv_data) + sizeof(alt_block_data_t), v.mv_size - sizeof(alt_block_data_t));
+ passed_bd = &bd;
+ }
+
+ if (!f(blkid, *data, passed_bd)) {
+ ret = false;
+ break;
+ }
+ }
+
+ TXN_POSTFIX_RDONLY();
+
+ return ret;
+}
+
bool BlockchainLMDB::block_exists(const crypto::hash& h, uint64_t *height) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -4062,6 +4162,110 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
return ret;
}
+void BlockchainLMDB::add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
+
+ CURSOR(alt_blocks)
+
+ MDB_val k = {sizeof(blkid), (void *)&blkid};
+ const size_t val_size = sizeof(alt_block_data_t) + blob.size();
+ std::unique_ptr<char[]> val(new char[val_size]);
+ memcpy(val.get(), &data, sizeof(alt_block_data_t));
+ memcpy(val.get() + sizeof(alt_block_data_t), blob.data(), blob.size());
+ MDB_val v = {val_size, (void *)val.get()};
+ if (auto result = mdb_cursor_put(m_cur_alt_blocks, &k, &v, MDB_NODUPDATA)) {
+ if (result == MDB_KEYEXIST)
+ throw1(DB_ERROR("Attempting to add alternate block that's already in the db"));
+ else
+ throw1(DB_ERROR(lmdb_error("Error adding alternate block to db transaction: ", result).c_str()));
+ }
+}
+
+bool BlockchainLMDB::get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob)
+{
+ LOG_PRINT_L3("BlockchainLMDB:: " << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(alt_blocks);
+
+ MDB_val_set(k, blkid);
+ MDB_val v;
+ int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, MDB_SET);
+ if (result == MDB_NOTFOUND)
+ return false;
+
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Error attempting to retrieve alternate block " + epee::string_tools::pod_to_hex(blkid) + " from the db: ", result).c_str()));
+ if (v.mv_size < sizeof(alt_block_data_t))
+ throw0(DB_ERROR("Record size is less than expected"));
+
+ const alt_block_data_t *ptr = (const alt_block_data_t*)v.mv_data;
+ if (data)
+ *data = *ptr;
+ if (blob)
+ blob->assign((const char*)(ptr + 1), v.mv_size - sizeof(alt_block_data_t));
+
+ TXN_POSTFIX_RDONLY();
+ return true;
+}
+
+void BlockchainLMDB::remove_alt_block(const crypto::hash &blkid)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
+
+ CURSOR(alt_blocks)
+
+ MDB_val k = {sizeof(blkid), (void *)&blkid};
+ MDB_val v;
+ int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, MDB_SET);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Error locating alternate block " + epee::string_tools::pod_to_hex(blkid) + " in the db: ", result).c_str()));
+ result = mdb_cursor_del(m_cur_alt_blocks, 0);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Error deleting alternate block " + epee::string_tools::pod_to_hex(blkid) + " from the db: ", result).c_str()));
+}
+
+uint64_t BlockchainLMDB::get_alt_block_count()
+{
+ LOG_PRINT_L3("BlockchainLMDB:: " << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(alt_blocks);
+
+ MDB_stat db_stats;
+ int result = mdb_stat(m_txn, m_alt_blocks, &db_stats);
+ uint64_t count = 0;
+ if (result != MDB_NOTFOUND)
+ {
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to query m_alt_blocks: ", result).c_str()));
+ count = db_stats.ms_entries;
+ }
+ TXN_POSTFIX_RDONLY();
+ return count;
+}
+
+void BlockchainLMDB::drop_alt_blocks()
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX(0);
+
+ auto result = mdb_drop(*txn_ptr, m_alt_blocks, 0);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Error dropping alternative blocks: ", result).c_str()));
+
+ TXN_POSTFIX_SUCCESS();
+}
+
bool BlockchainLMDB::is_read_only() const
{
unsigned int flags;
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 4b46f081e..61a551476 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -67,6 +67,8 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_txpool_meta;
MDB_cursor *m_txc_txpool_blob;
+ MDB_cursor *m_txc_alt_blocks;
+
MDB_cursor *m_txc_hf_versions;
MDB_cursor *m_txc_properties;
@@ -87,6 +89,7 @@ typedef struct mdb_txn_cursors
#define m_cur_spent_keys m_cursors->m_txc_spent_keys
#define m_cur_txpool_meta m_cursors->m_txc_txpool_meta
#define m_cur_txpool_blob m_cursors->m_txc_txpool_blob
+#define m_cur_alt_blocks m_cursors->m_txc_alt_blocks
#define m_cur_hf_versions m_cursors->m_txc_hf_versions
#define m_cur_properties m_cursors->m_txc_properties
@@ -108,6 +111,7 @@ typedef struct mdb_rflags
bool m_rf_spent_keys;
bool m_rf_txpool_meta;
bool m_rf_txpool_blob;
+ bool m_rf_alt_blocks;
bool m_rf_hf_versions;
bool m_rf_properties;
} mdb_rflags;
@@ -288,6 +292,12 @@ public:
virtual bool update_pruning();
virtual bool check_pruning();
+ virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob);
+ virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob);
+ virtual void remove_alt_block(const crypto::hash &blkid);
+ virtual uint64_t get_alt_block_count();
+ virtual void drop_alt_blocks();
+
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const;
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
@@ -295,6 +305,7 @@ public:
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const;
+ virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const;
virtual uint64_t add_block( const std::pair<block, blobdata>& blk
, size_t block_weight
@@ -452,6 +463,8 @@ private:
MDB_dbi m_txpool_meta;
MDB_dbi m_txpool_blob;
+ MDB_dbi m_alt_blocks;
+
MDB_dbi m_hf_starting_heights;
MDB_dbi m_hf_versions;
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 6c97713d5..ac19fae25 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -54,6 +54,7 @@ public:
virtual void unlock() override { }
virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) override { return true; }
virtual void batch_stop() override {}
+ virtual void batch_abort() override {}
virtual void set_batch_transactions(bool) override {}
virtual void block_wtxn_start() override {}
virtual void block_wtxn_stop() override {}
@@ -155,6 +156,13 @@ public:
virtual uint64_t get_max_block_size() override { return 100000000; }
virtual void add_max_block_size(uint64_t sz) override { }
+
+ virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob) override {}
+ virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob) override { return false; }
+ virtual void remove_alt_block(const crypto::hash &blkid) override {}
+ virtual uint64_t get_alt_block_count() override { return 0; }
+ virtual void drop_alt_blocks() override {}
+ virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const override { return true; }
};
}
diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp
index 6ff184041..f824d93a6 100644
--- a/src/blockchain_utilities/blockchain_blackball.cpp
+++ b/src/blockchain_utilities/blockchain_blackball.cpp
@@ -637,6 +637,7 @@ static void inc_per_amount_outputs(MDB_txn *txn, uint64_t amount, uint64_t total
v.mv_size = 2 * sizeof(uint64_t);
v.mv_data = (void*)data;
dbr = mdb_cursor_put(cur, &k, &v, 0);
+ CHECK_AND_ASSERT_THROW_MES(!dbr, "Failed to write record for per amount outputs: " + std::string(mdb_strerror(dbr)));
mdb_cursor_close(cur);
}
diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp
index fa1243c1f..85566efca 100644
--- a/src/blockchain_utilities/blockchain_export.cpp
+++ b/src/blockchain_utilities/blockchain_export.cpp
@@ -177,7 +177,7 @@ int main(int argc, char* argv[])
}
r = core_storage->init(db, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET);
- if (core_storage->get_blockchain_pruning_seed())
+ if (core_storage->get_blockchain_pruning_seed() && !opt_blocks_dat)
{
LOG_PRINT_L0("Blockchain is pruned, cannot export");
return 1;
diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat
index adc433522..a7d309753 100644
--- a/src/blocks/checkpoints.dat
+++ b/src/blocks/checkpoints.dat
Binary files differ
diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp
index e31b96646..11bbe2e24 100644
--- a/src/checkpoints/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -209,6 +209,7 @@ namespace cryptonote
ADD_CHECKPOINT(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241");
ADD_CHECKPOINT(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568");
ADD_CHECKPOINT(1775600, "1c6e01c661dc22cab939e79ec6a5272190624ce8356d2f7b958e4f9a57fdb05e");
+ ADD_CHECKPOINT(1856000, "9b57f17f29c71a3acd8a7904b93c41fa6eb8d2b7c73936ce4f1702d14880ba29");
return true;
}
diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp
index 5e03bf897..dc1f335a7 100644
--- a/src/common/dns_utils.cpp
+++ b/src/common/dns_utils.cpp
@@ -48,7 +48,6 @@ static const char *DEFAULT_DNS_PUBLIC_ADDR[] =
"80.67.169.40", // FDN (France)
"89.233.43.71", // http://censurfridns.dk (Denmark)
"109.69.8.51", // punCAT (Spain)
- "77.109.148.137", // Xiala.net (Switzerland)
"193.58.251.251", // SkyDNS (Russia)
};
diff --git a/src/common/rpc_client.h b/src/common/rpc_client.h
index cb5f79da8..dab3e562d 100644
--- a/src/common/rpc_client.h
+++ b/src/common/rpc_client.h
@@ -36,6 +36,7 @@
#include "storages/http_abstract_invoke.h"
#include "net/http_auth.h"
#include "net/http_client.h"
+#include "net/net_ssl.h"
#include "string_tools.h"
namespace tools
@@ -49,11 +50,12 @@ namespace tools
uint32_t ip
, uint16_t port
, boost::optional<epee::net_utils::http::login> user
+ , epee::net_utils::ssl_options_t ssl_options
)
: m_http_client{}
{
m_http_client.set_server(
- epee::string_tools::get_ip_string_from_int32(ip), std::to_string(port), std::move(user)
+ epee::string_tools::get_ip_string_from_int32(ip), std::to_string(port), std::move(user), std::move(ssl_options)
);
}
diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c
index 170911262..851c70a25 100644
--- a/src/crypto/keccak.c
+++ b/src/crypto/keccak.c
@@ -105,9 +105,12 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
memset(st, 0, sizeof(st));
for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) {
- for (i = 0; i < rsizw; i++)
- st[i] ^= swap64le(((uint64_t *) in)[i]);
- keccakf(st, KECCAK_ROUNDS);
+ for (i = 0; i < rsizw; i++) {
+ uint64_t ina;
+ memcpy(&ina, in + i * 8, 8);
+ st[i] ^= swap64le(ina);
+ }
+ keccakf(st, KECCAK_ROUNDS);
}
// last block and padding
@@ -116,7 +119,8 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
local_abort("Bad keccak use");
}
- memcpy(temp, in, inlen);
+ if (inlen > 0)
+ memcpy(temp, in, inlen);
temp[inlen++] = 1;
memset(temp + inlen, 0, rsiz - inlen);
temp[rsiz - 1] |= 0x80;
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index 7f36c9dc3..13835c823 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -897,7 +897,6 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
// locals to avoid constant TLS dereferencing
uint8_t *local_hp_state = hp_state;
- v4_random_math_JIT_func local_hp_jitfunc = hp_jitfunc;
/* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */
if (prehashed) {
diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c
index 7802fb67f..0a5860f3b 100644
--- a/src/crypto/tree-hash.c
+++ b/src/crypto/tree-hash.c
@@ -30,6 +30,7 @@
#include <assert.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include "hash-ops.h"
@@ -82,23 +83,24 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
size_t cnt = tree_hash_cnt( count );
- char ints[cnt][HASH_SIZE];
- memset(ints, 0 , sizeof(ints)); // zero out as extra protection for using uninitialized mem
+ char *ints = calloc(cnt, HASH_SIZE); // zero out as extra protection for using uninitialized mem
+ assert(ints);
memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE);
for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) {
- cn_fast_hash(hashes[i], 64, ints[j]);
+ cn_fast_hash(hashes[i], 64, ints + j * HASH_SIZE);
}
assert(i == count);
while (cnt > 2) {
cnt >>= 1;
for (i = 0, j = 0; j < cnt; i += 2, ++j) {
- cn_fast_hash(ints[i], 64, ints[j]);
+ cn_fast_hash(ints + i * HASH_SIZE, 64, ints + j * HASH_SIZE);
}
}
- cn_fast_hash(ints[0], 64, root_hash);
+ cn_fast_hash(ints, 64, root_hash);
+ free(ints);
}
}
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 20d92bdf1..055c4a22b 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -320,7 +320,7 @@ namespace cryptonote
}
if (!typename Archive<W>::is_saving())
pruned = true;
- return true;
+ return ar.stream().good();
}
private:
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 566622c1a..7d7de416d 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -221,8 +221,7 @@ namespace cryptonote
tx.invalidate_hashes();
//TODO: validate tx
- get_transaction_hash(tx, tx_hash);
- return true;
+ return get_transaction_hash(tx, tx_hash);
}
//---------------------------------------------------------------
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
@@ -975,6 +974,7 @@ namespace cryptonote
{
crypto::hash h = null_hash;
get_transaction_hash(t, h, NULL);
+ CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(t, h, NULL), "Failed to calculate transaction hash");
return h;
}
//---------------------------------------------------------------
@@ -1327,7 +1327,7 @@ namespace cryptonote
txs_ids.reserve(1 + b.tx_hashes.size());
crypto::hash h = null_hash;
size_t bl_sz = 0;
- get_transaction_hash(b.miner_tx, h, bl_sz);
+ CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.miner_tx, h, bl_sz), "Failed to calculate transaction hash");
txs_ids.push_back(h);
for(auto& th: b.tx_hashes)
txs_ids.push_back(th);
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 173679e21..e594eb049 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -123,7 +123,7 @@ namespace cryptonote
m_miner_extra_sleep(BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS),
m_block_reward(0)
{
-
+ m_attrs.set_stack_size(THREAD_STACK_SIZE);
}
//-----------------------------------------------------------------------------------------------------
miner::~miner()
@@ -360,7 +360,7 @@ namespace cryptonote
return m_threads_total;
}
//-----------------------------------------------------------------------------------------------------
- bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background, bool ignore_battery)
+ bool miner::start(const account_public_address& adr, size_t threads_count, bool do_background, bool ignore_battery)
{
m_block_reward = 0;
m_mine_address = adr;
@@ -371,7 +371,6 @@ namespace cryptonote
m_threads_autodetect.push_back({epee::misc_utils::get_ns_count(), m_total_hashes});
m_threads_total = 1;
}
- m_attrs = attrs;
m_starter_nonce = crypto::rand<uint32_t>();
CRITICAL_REGION_LOCAL(m_threads_lock);
if(is_mining())
@@ -395,7 +394,7 @@ namespace cryptonote
for(size_t i = 0; i != m_threads_total; i++)
{
- m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
+ m_threads.push_back(boost::thread(m_attrs, boost::bind(&miner::worker_thread, this)));
}
if (threads_count == 0)
@@ -405,7 +404,7 @@ namespace cryptonote
if( get_is_background_mining_enabled() )
{
- m_background_mining_thread = boost::thread(attrs, boost::bind(&miner::background_worker_thread, this));
+ m_background_mining_thread = boost::thread(m_attrs, boost::bind(&miner::background_worker_thread, this));
LOG_PRINT_L0("Background mining controller thread started" );
}
@@ -487,10 +486,7 @@ namespace cryptonote
{
if(m_do_mining)
{
- boost::thread::attributes attrs;
- attrs.set_stack_size(THREAD_STACK_SIZE);
-
- start(m_mine_address, m_threads_total, attrs, get_is_background_mining_enabled(), get_ignore_battery());
+ start(m_mine_address, m_threads_total, get_is_background_mining_enabled(), get_ignore_battery());
}
}
//-----------------------------------------------------------------------------------------------------
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
index 285075f51..ac7a0381c 100644
--- a/src/cryptonote_basic/miner.h
+++ b/src/cryptonote_basic/miner.h
@@ -64,7 +64,7 @@ namespace cryptonote
static void init_options(boost::program_options::options_description& desc);
bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height, uint64_t block_reward);
bool on_block_chain_update();
- bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background = false, bool ignore_battery = false);
+ bool start(const account_public_address& adr, size_t threads_count, bool do_background = false, bool ignore_battery = false);
uint64_t get_speed() const;
uint32_t get_threads_count() const;
void send_stop_signal();
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 39c9f8695..31e2ac136 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -182,7 +182,8 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_long_term_block_weights_cache_rolling_median(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
m_difficulty_for_next_block_top_hash(crypto::null_hash),
m_difficulty_for_next_block(1),
- m_btc_valid(false)
+ m_btc_valid(false),
+ m_batch_success(true)
{
LOG_PRINT_L3("Blockchain::" << __func__);
}
@@ -619,17 +620,13 @@ void Blockchain::pop_blocks(uint64_t nblocks)
CRITICAL_REGION_LOCAL(m_tx_pool);
CRITICAL_REGION_LOCAL1(m_blockchain_lock);
- while (!m_db->batch_start())
- {
- m_blockchain_lock.unlock();
- m_tx_pool.unlock();
- epee::misc_utils::sleep_no_w(1000);
- m_tx_pool.lock();
- m_blockchain_lock.lock();
- }
+ bool stop_batch = m_db->batch_start();
try
{
+ const uint64_t blockchain_height = m_db->height();
+ if (blockchain_height > 0)
+ nblocks = std::min(nblocks, blockchain_height - 1);
for (i=0; i < nblocks; ++i)
{
pop_block_from_blockchain();
@@ -637,10 +634,14 @@ void Blockchain::pop_blocks(uint64_t nblocks)
}
catch (const std::exception& e)
{
- LOG_ERROR("Error when popping blocks, only " << i << " blocks are popped: " << e.what());
+ LOG_ERROR("Error when popping blocks after processing " << i << " blocks: " << e.what());
+ if (stop_batch)
+ m_db->batch_abort();
+ return;
}
- m_db->batch_stop();
+ if (stop_batch)
+ m_db->batch_stop();
}
//------------------------------------------------------------------
// This function tells BlockchainDB to remove the top block from the
@@ -730,9 +731,9 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
- m_alternative_chains.clear();
invalidate_block_template_cache();
m_db->reset();
+ m_db->drop_alt_blocks();
m_hardfork->init();
db_wtxn_guard wtxn_guard(m_db);
@@ -857,10 +858,15 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
// try to find block in alternative chain
catch (const BLOCK_DNE& e)
{
- blocks_ext_by_hash::const_iterator it_alt = m_alternative_chains.find(h);
- if (m_alternative_chains.end() != it_alt)
+ alt_block_data_t data;
+ cryptonote::blobdata blob;
+ if (m_db->get_alt_block(h, &data, &blob))
{
- blk = it_alt->second.bl;
+ if (!cryptonote::parse_and_validate_block_from_blob(blob, blk))
+ {
+ MERROR("Found block " << h << " in alt chain, but failed to parse it");
+ throw std::runtime_error("Found block in alt chain, but failed to parse it");
+ }
if (orphan)
*orphan = true;
return true;
@@ -1018,7 +1024,7 @@ bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain,
//------------------------------------------------------------------
// This function attempts to switch to an alternate chain, returning
// boolean based on success therein.
-bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::const_iterator>& alt_chain, bool discard_disconnected_chain)
+bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>& alt_chain, bool discard_disconnected_chain)
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -1029,7 +1035,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed");
// verify that main chain has front of alt chain's parent block
- if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id))
+ if (!m_db->block_exists(alt_chain.front().bl.prev_id))
{
LOG_ERROR("Attempting to move to an alternate chain, but it doesn't appear to connect to the main chain!");
return false;
@@ -1038,7 +1044,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
// pop blocks from the blockchain until the top block is the parent
// of the front block of the alt chain.
std::list<block> disconnected_chain;
- while (m_db->top_block_hash() != alt_chain.front()->second.bl.prev_id)
+ while (m_db->top_block_hash() != alt_chain.front().bl.prev_id)
{
block b = pop_block_from_blockchain();
disconnected_chain.push_front(b);
@@ -1049,11 +1055,11 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
//connecting new alternative chain
for(auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++)
{
- auto ch_ent = *alt_ch_iter;
+ const auto &bei = *alt_ch_iter;
block_verification_context bvc = boost::value_initialized<block_verification_context>();
// add block to main chain
- bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc);
+ bool r = handle_block_to_main_chain(bei.bl, bvc);
// if adding block to main chain failed, rollback to previous state and
// return false
@@ -1069,14 +1075,18 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
// FIXME: Why do we keep invalid blocks around? Possibly in case we hear
// about them again so we can immediately dismiss them, but needs some
// looking into.
- add_block_as_invalid(ch_ent->second, get_block_hash(ch_ent->second.bl));
- MERROR("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl));
- m_alternative_chains.erase(*alt_ch_iter++);
+ const crypto::hash blkid = cryptonote::get_block_hash(bei.bl);
+ add_block_as_invalid(bei, blkid);
+ MERROR("The block was inserted as invalid while connecting new alternative chain, block_id: " << blkid);
+ m_db->remove_alt_block(blkid);
+ alt_ch_iter++;
for(auto alt_ch_to_orph_iter = alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); )
{
- add_block_as_invalid((*alt_ch_to_orph_iter)->second, (*alt_ch_to_orph_iter)->first);
- m_alternative_chains.erase(*alt_ch_to_orph_iter++);
+ const auto &bei = *alt_ch_to_orph_iter++;
+ const crypto::hash blkid = cryptonote::get_block_hash(bei.bl);
+ add_block_as_invalid(bei, blkid);
+ m_db->remove_alt_block(blkid);
}
return false;
}
@@ -1101,9 +1111,9 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
}
//removing alt_chain entries from alternative chains container
- for (auto ch_ent: alt_chain)
+ for (const auto &bei: alt_chain)
{
- m_alternative_chains.erase(ch_ent);
+ m_db->remove_alt_block(cryptonote::get_block_hash(bei.bl));
}
m_hardfork->reorganize_from_chain_height(split_height);
@@ -1119,7 +1129,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
//------------------------------------------------------------------
// This function calculates the difficulty target for the block being added to
// an alternate chain.
-difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::const_iterator>& alt_chain, block_extended_info& bei) const
+difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<block_extended_info>& alt_chain, block_extended_info& bei) const
{
if (m_fixed_difficulty)
{
@@ -1137,7 +1147,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
CRITICAL_REGION_LOCAL(m_blockchain_lock);
// Figure out start and stop offsets for main chain blocks
- size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front()->second.height : bei.height;
+ size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front().height : bei.height;
size_t main_chain_count = DIFFICULTY_BLOCKS_COUNT - std::min(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT), alt_chain.size());
main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;
@@ -1155,10 +1165,10 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
// make sure we haven't accidentally grabbed too many blocks...maybe don't need this check?
CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= DIFFICULTY_BLOCKS_COUNT, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << DIFFICULTY_BLOCKS_COUNT);
- for (auto it : alt_chain)
+ for (const auto &bei : alt_chain)
{
- timestamps.push_back(it->second.bl.timestamp);
- cumulative_difficulties.push_back(it->second.cumulative_difficulty);
+ timestamps.push_back(bei.bl.timestamp);
+ cumulative_difficulties.push_back(bei.cumulative_difficulty);
}
}
// if the alt chain is long enough for the difficulty calc, grab difficulties
@@ -1170,10 +1180,10 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
size_t count = 0;
size_t max_i = timestamps.size()-1;
// get difficulties and timestamps from most recent blocks in alt chain
- for(auto it: boost::adaptors::reverse(alt_chain))
+ for (const auto bei: boost::adaptors::reverse(alt_chain))
{
- timestamps[max_i - count] = it->second.bl.timestamp;
- cumulative_difficulties[max_i - count] = it->second.cumulative_difficulty;
+ timestamps[max_i - count] = bei.bl.timestamp;
+ cumulative_difficulties[max_i - count] = bei.cumulative_difficulty;
count++;
if(count >= DIFFICULTY_BLOCKS_COUNT)
break;
@@ -1373,7 +1383,8 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
// just as we compare it, we'll just use a slightly old template, but
// this would be the case anyway if we'd lock, and the change happened
// just after the block template was created
- if (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce && m_btc_pool_cookie == m_tx_pool.cookie()) {
+ if (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce
+ && m_btc_pool_cookie == m_tx_pool.cookie() && m_btc.prev_id == get_tail_id()) {
MDEBUG("Using cached template");
m_btc.timestamp = time(NULL); // update timestamp unconditionally
b = m_btc;
@@ -1391,16 +1402,17 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
//build alternative subchain, front -> mainchain, back -> alternative head
//block is not related with head of main chain
//first of all - look in alternative chains container
- auto it_prev = m_alternative_chains.find(*from_block);
+ alt_block_data_t prev_data;
+ bool parent_in_alt = m_db->get_alt_block(*from_block, &prev_data, NULL);
bool parent_in_main = m_db->block_exists(*from_block);
- if(it_prev == m_alternative_chains.end() && !parent_in_main)
+ if (!parent_in_alt && !parent_in_main)
{
MERROR("Unknown from block");
return false;
}
//we have new block in alternative chain
- std::list<blocks_ext_by_hash::const_iterator> alt_chain;
+ std::list<block_extended_info> alt_chain;
block_verification_context bvc = boost::value_initialized<block_verification_context>();
std::vector<uint64_t> timestamps;
if (!build_alt_chain(*from_block, alt_chain, timestamps, bvc))
@@ -1415,7 +1427,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
}
else
{
- height = alt_chain.back()->second.height + 1;
+ height = alt_chain.back().height + 1;
}
b.major_version = m_hardfork->get_ideal_version(height);
b.minor_version = m_hardfork->get_ideal_version();
@@ -1430,14 +1442,14 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
}
else
{
- median_weight = it_prev->second.block_cumulative_weight - it_prev->second.block_cumulative_weight / 20;
- already_generated_coins = alt_chain.back()->second.already_generated_coins;
+ median_weight = prev_data.cumulative_weight - prev_data.cumulative_weight / 20;
+ already_generated_coins = alt_chain.back().already_generated_coins;
}
// FIXME: consider moving away from block_extended_info at some point
block_extended_info bei = boost::value_initialized<block_extended_info>();
bei.bl = b;
- bei.height = alt_chain.size() ? it_prev->second.height + 1 : m_db->get_block_height(*from_block) + 1;
+ bei.height = alt_chain.size() ? prev_data.height + 1 : m_db->get_block_height(*from_block) + 1;
diffic = get_next_difficulty_for_alternative_chain(alt_chain, bei);
}
@@ -1616,16 +1628,25 @@ bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vect
return true;
}
//------------------------------------------------------------------
-bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<blocks_ext_by_hash::const_iterator>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const
+bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<block_extended_info>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const
{
//build alternative subchain, front -> mainchain, back -> alternative head
- blocks_ext_by_hash::const_iterator alt_it = m_alternative_chains.find(prev_id);
+ cryptonote::alt_block_data_t data;
+ cryptonote::blobdata blob;
+ bool found = m_db->get_alt_block(prev_id, &data, &blob);
timestamps.clear();
- while(alt_it != m_alternative_chains.end())
+ while(found)
{
- alt_chain.push_front(alt_it);
- timestamps.push_back(alt_it->second.bl.timestamp);
- alt_it = m_alternative_chains.find(alt_it->second.bl.prev_id);
+ block_extended_info bei;
+ CHECK_AND_ASSERT_MES(cryptonote::parse_and_validate_block_from_blob(blob, bei.bl), false, "Failed to parse alt block");
+ bei.height = data.height;
+ bei.block_cumulative_weight = data.cumulative_weight;
+ bei.cumulative_difficulty = data.cumulative_difficulty_high;
+ bei.cumulative_difficulty = (bei.cumulative_difficulty << 64) + data.cumulative_difficulty_low;
+ bei.already_generated_coins = data.already_generated_coins;
+ timestamps.push_back(bei.bl.timestamp);
+ alt_chain.push_front(std::move(bei));
+ found = m_db->get_alt_block(bei.bl.prev_id, &data, &blob);
}
// if block to be added connects to known blocks that aren't part of the
@@ -1633,20 +1654,20 @@ bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<blocks_e
if(!alt_chain.empty())
{
// make sure alt chain doesn't somehow start past the end of the main chain
- CHECK_AND_ASSERT_MES(m_db->height() > alt_chain.front()->second.height, false, "main blockchain wrong height");
+ CHECK_AND_ASSERT_MES(m_db->height() > alt_chain.front().height, false, "main blockchain wrong height");
// make sure that the blockchain contains the block that should connect
// this alternate chain with it.
- if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id))
+ if (!m_db->block_exists(alt_chain.front().bl.prev_id))
{
MERROR("alternate chain does not appear to connect to main chain...");
return false;
}
// make sure block connects correctly to the main chain
- auto h = m_db->get_block_hash_from_height(alt_chain.front()->second.height - 1);
- CHECK_AND_ASSERT_MES(h == alt_chain.front()->second.bl.prev_id, false, "alternative chain has wrong connection to main chain");
- complete_timestamps_vector(m_db->get_block_height(alt_chain.front()->second.bl.prev_id), timestamps);
+ auto h = m_db->get_block_hash_from_height(alt_chain.front().height - 1);
+ CHECK_AND_ASSERT_MES(h == alt_chain.front().bl.prev_id, false, "alternative chain has wrong connection to main chain");
+ complete_timestamps_vector(m_db->get_block_height(alt_chain.front().bl.prev_id), timestamps);
}
// if block not associated with known alternate chain
else
@@ -1701,12 +1722,13 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
//block is not related with head of main chain
//first of all - look in alternative chains container
- auto it_prev = m_alternative_chains.find(b.prev_id);
+ alt_block_data_t prev_data;
+ bool parent_in_alt = m_db->get_alt_block(b.prev_id, &prev_data, NULL);
bool parent_in_main = m_db->block_exists(b.prev_id);
- if(it_prev != m_alternative_chains.end() || parent_in_main)
+ if (parent_in_alt || parent_in_main)
{
//we have new block in alternative chain
- std::list<blocks_ext_by_hash::const_iterator> alt_chain;
+ std::list<block_extended_info> alt_chain;
std::vector<uint64_t> timestamps;
if (!build_alt_chain(b.prev_id, alt_chain, timestamps, bvc))
return false;
@@ -1714,10 +1736,10 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
// FIXME: consider moving away from block_extended_info at some point
block_extended_info bei = boost::value_initialized<block_extended_info>();
bei.bl = b;
- const uint64_t prev_height = alt_chain.size() ? it_prev->second.height : m_db->get_block_height(b.prev_id);
+ const uint64_t prev_height = alt_chain.size() ? prev_data.height : m_db->get_block_height(b.prev_id);
bei.height = prev_height + 1;
uint64_t block_reward = get_outs_money_amount(b.miner_tx);
- bei.already_generated_coins = block_reward + (alt_chain.size() ? it_prev->second.already_generated_coins : m_db->get_block_already_generated_coins(prev_height));
+ bei.already_generated_coins = block_reward + (alt_chain.size() ? prev_data.already_generated_coins : m_db->get_block_already_generated_coins(prev_height));
// verify that the block's timestamp is within the acceptable range
// (not earlier than the median of the last X blocks)
@@ -1761,7 +1783,8 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
difficulty_type main_chain_cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1);
if (alt_chain.size())
{
- bei.cumulative_difficulty = it_prev->second.cumulative_difficulty;
+ bei.cumulative_difficulty = prev_data.cumulative_difficulty_high;
+ bei.cumulative_difficulty = (bei.cumulative_difficulty << 64) + prev_data.cumulative_difficulty_low;
}
else
{
@@ -1772,15 +1795,21 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
// add block to alternate blocks storage,
// as well as the current "alt chain" container
- auto i_res = m_alternative_chains.insert(blocks_ext_by_hash::value_type(id, bei));
- CHECK_AND_ASSERT_MES(i_res.second, false, "insertion of new alternative block returned as it already exist");
- alt_chain.push_back(i_res.first);
+ CHECK_AND_ASSERT_MES(!m_db->get_alt_block(id, NULL, NULL), false, "insertion of new alternative block returned as it already exists");
+ cryptonote::alt_block_data_t data;
+ data.height = bei.height;
+ data.cumulative_weight = bei.block_cumulative_weight;
+ data.cumulative_difficulty_low = (bei.cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
+ data.cumulative_difficulty_high = ((bei.cumulative_difficulty >> 64) & 0xffffffffffffffff).convert_to<uint64_t>();
+ data.already_generated_coins = bei.already_generated_coins;
+ m_db->add_alt_block(id, data, cryptonote::block_to_blob(bei.bl));
+ alt_chain.push_back(bei);
// FIXME: is it even possible for a checkpoint to show up not on the main chain?
if(is_a_checkpoint)
{
//do reorganize!
- MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << ", checkpoint is found in alternative chain on height " << bei.height);
+ MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front().height << " of " << m_db->height() - 1 << ", checkpoint is found in alternative chain on height " << bei.height);
bool r = switch_to_alternative_blockchain(alt_chain, true);
@@ -1792,7 +1821,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
else if(main_chain_cumulative_difficulty < bei.cumulative_difficulty) //check if difficulty bigger then in main chain
{
//do reorganize!
- MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << " with cum_difficulty " << m_db->get_block_cumulative_difficulty(m_db->height() - 1) << std::endl << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty);
+ MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front().height << " of " << m_db->height() - 1 << " with cum_difficulty " << m_db->get_block_cumulative_difficulty(m_db->height() - 1) << std::endl << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty);
bool r = switch_to_alternative_blockchain(alt_chain, false);
if (r)
@@ -1812,7 +1841,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
//block orphaned
bvc.m_marked_as_orphaned = true;
MERROR_VER("Block recognized as orphaned and rejected, id = " << id << ", height " << block_height
- << ", parent in alt " << (it_prev != m_alternative_chains.end()) << ", parent in main " << parent_in_main
+ << ", parent in alt " << parent_in_alt << ", parent in main " << parent_in_main
<< " (parent " << b.prev_id << ", current top " << get_tail_id() << ", chain height " << get_current_blockchain_height() << ")");
}
@@ -1891,10 +1920,14 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
if (missed_tx_ids.size() != 0)
{
- LOG_ERROR("Error retrieving blocks, missed " << missed_tx_ids.size()
- << " transactions for block with hash: " << get_block_hash(bl.second)
- << std::endl
- );
+ // do not display an error if the peer asked for an unpruned block which we are not meant to have
+ if (tools::has_unpruned_block(get_block_height(bl.second), get_current_blockchain_height(), get_blockchain_pruning_seed()))
+ {
+ LOG_ERROR("Error retrieving blocks, missed " << missed_tx_ids.size()
+ << " transactions for block with hash: " << get_block_hash(bl.second)
+ << std::endl
+ );
+ }
// append missed transaction hashes to response missed_ids field,
// as done below if any standalone transactions were requested
@@ -1906,8 +1939,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
//pack block
e.block = std::move(bl.first);
}
- //get and pack other transactions, if needed
- get_transactions_blobs(arg.txs, rsp.txs, rsp.missed_ids);
return true;
}
@@ -1917,11 +1948,20 @@ bool Blockchain::get_alternative_blocks(std::vector<block>& blocks) const
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- blocks.reserve(m_alternative_chains.size());
- for (const auto& alt_bl: m_alternative_chains)
- {
- blocks.push_back(alt_bl.second.bl);
- }
+ blocks.reserve(m_db->get_alt_block_count());
+ m_db->for_all_alt_blocks([&blocks](const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata *blob) {
+ if (!blob)
+ {
+ MERROR("No blob, but blobs were requested");
+ return false;
+ }
+ cryptonote::block bl;
+ if (cryptonote::parse_and_validate_block_from_blob(*blob, bl))
+ blocks.push_back(std::move(bl));
+ else
+ MERROR("Failed to parse block from blob");
+ return true;
+ }, true);
return true;
}
//------------------------------------------------------------------
@@ -1929,7 +1969,7 @@ size_t Blockchain::get_alternative_blocks_count() const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- return m_alternative_chains.size();
+ return m_db->get_alt_block_count();
}
//------------------------------------------------------------------
// This function adds the output specified by <amount, i> to the result_outs container
@@ -2033,7 +2073,6 @@ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height,
if (to_height > 0 && to_height < from_height)
return false;
- const uint64_t real_start_height = start_height;
if (from_height > start_height)
start_height = from_height;
@@ -2047,7 +2086,7 @@ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height,
{
std::vector<uint64_t> heights;
heights.reserve(to_height + 1 - start_height);
- uint64_t real_start_height = start_height > 0 ? start_height-1 : start_height;
+ const uint64_t real_start_height = start_height > 0 ? start_height-1 : start_height;
for (uint64_t h = real_start_height; h <= to_height; ++h)
heights.push_back(h);
distribution = m_db->get_block_cumulative_rct_outputs(heights);
@@ -2417,9 +2456,9 @@ bool Blockchain::have_block(const crypto::hash& id) const
return true;
}
- if(m_alternative_chains.count(id))
+ if(m_db->get_alt_block(id, NULL, NULL))
{
- LOG_PRINT_L2("block " << id << " found in m_alternative_chains");
+ LOG_PRINT_L2("block " << id << " found in alternative chains");
return true;
}
@@ -3248,7 +3287,6 @@ uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_b
bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const
{
const uint8_t version = get_current_hard_fork_version();
- const uint64_t blockchain_height = m_db->height();
uint64_t median = 0;
uint64_t already_generated_coins = 0;
@@ -3844,6 +3882,7 @@ leave:
catch (const KEY_IMAGE_EXISTS& e)
{
LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what());
+ m_batch_success = false;
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
return false;
@@ -3852,6 +3891,7 @@ leave:
{
//TODO: figure out the best way to deal with this failure
LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what());
+ m_batch_success = false;
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
return false;
@@ -3954,14 +3994,12 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
const uint64_t db_height = m_db->height();
const uint8_t hf_version = get_current_hard_fork_version();
uint64_t full_reward_zone = get_min_block_weight(hf_version);
- uint64_t long_term_block_weight;
if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
{
std::vector<uint64_t> weights;
get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
m_current_block_cumul_weight_median = epee::misc_utils::median(weights);
- long_term_block_weight = weights.back();
}
else
{
@@ -3983,7 +4021,7 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
uint64_t short_term_constraint = m_long_term_effective_median_block_weight + m_long_term_effective_median_block_weight * 2 / 5;
- long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
+ uint64_t long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
if (db_height == 1)
{
@@ -4161,7 +4199,10 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
try
{
- m_db->batch_stop();
+ if (m_batch_success)
+ m_db->batch_stop();
+ else
+ m_db->batch_abort();
success = true;
}
catch (const std::exception &e)
@@ -4385,6 +4426,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
m_tx_pool.lock();
m_blockchain_lock.lock();
}
+ m_batch_success = true;
const uint64_t height = m_db->height();
if ((height + blocks_entry.size()) < m_blocks_hash_check.size())
@@ -4802,11 +4844,35 @@ std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>>
{
std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
- for (const auto &i: m_alternative_chains)
+ blocks_ext_by_hash alt_blocks;
+ alt_blocks.reserve(m_db->get_alt_block_count());
+ m_db->for_all_alt_blocks([&alt_blocks](const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata *blob) {
+ if (!blob)
+ {
+ MERROR("No blob, but blobs were requested");
+ return false;
+ }
+ cryptonote::block bl;
+ block_extended_info bei;
+ if (cryptonote::parse_and_validate_block_from_blob(*blob, bei.bl))
+ {
+ bei.height = data.height;
+ bei.block_cumulative_weight = data.cumulative_weight;
+ bei.cumulative_difficulty = data.cumulative_difficulty_high;
+ bei.cumulative_difficulty = (bei.cumulative_difficulty << 64) + data.cumulative_difficulty_low;
+ bei.already_generated_coins = data.already_generated_coins;
+ alt_blocks.insert(std::make_pair(cryptonote::get_block_hash(bei.bl), std::move(bei)));
+ }
+ else
+ MERROR("Failed to parse block from blob");
+ return true;
+ }, true);
+
+ for (const auto &i: alt_blocks)
{
- const crypto::hash &top = i.first;
+ const crypto::hash top = cryptonote::get_block_hash(i.second.bl);
bool found = false;
- for (const auto &j: m_alternative_chains)
+ for (const auto &j: alt_blocks)
{
if (j.second.bl.prev_id == top)
{
@@ -4820,7 +4886,7 @@ std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>>
auto h = i.second.bl.prev_id;
chain.push_back(top);
blocks_ext_by_hash::const_iterator prev;
- while ((prev = m_alternative_chains.find(h)) != m_alternative_chains.end())
+ while ((prev = alt_blocks.find(h)) != alt_blocks.end())
{
chain.push_back(h);
h = prev->second.bl.prev_id;
@@ -4837,7 +4903,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
-static const char expected_block_hashes_hash[] = "570ce2357b08fadac6058e34f95c5e08323f9325de260d07b091a281a948a7b0";
+static const char expected_block_hashes_hash[] = "7dafb40b414a0e59bfced6682ef519f0b416bc914dd3d622b72e0dd1a47117c2";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 6200ec87e..b1c23b704 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -92,24 +92,13 @@ namespace cryptonote
{
public:
/**
- * @brief Now-defunct (TODO: remove) struct from in-memory blockchain
- */
- struct transaction_chain_entry
- {
- transaction tx;
- uint64_t m_keeper_block_height;
- size_t m_blob_size;
- std::vector<uint64_t> m_global_output_indexes;
- };
-
- /**
* @brief container for passing a block and metadata about it on the blockchain
*/
struct block_extended_info
{
block bl; //!< the block
uint64_t height; //!< the height of the block in the blockchain
- size_t block_cumulative_weight; //!< the weight of the block
+ uint64_t block_cumulative_weight; //!< the weight of the block
difficulty_type cumulative_difficulty; //!< the accumulated difficulty after that block
uint64_t already_generated_coins; //!< the total coins minted after that block
};
@@ -1011,20 +1000,12 @@ namespace cryptonote
#endif
// TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage
- typedef std::unordered_map<crypto::hash, size_t> blocks_by_id_index;
-
- typedef std::unordered_map<crypto::hash, transaction_chain_entry> transactions_container;
-
typedef std::unordered_set<crypto::key_image> key_images_container;
typedef std::vector<block_extended_info> blocks_container;
typedef std::unordered_map<crypto::hash, block_extended_info> blocks_ext_by_hash;
- typedef std::unordered_map<crypto::hash, block> blocks_by_hash;
-
- typedef std::map<uint64_t, std::vector<std::pair<crypto::hash, size_t>>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction
-
BlockchainDB* m_db;
@@ -1033,7 +1014,6 @@ namespace cryptonote
mutable epee::critical_section m_blockchain_lock; // TODO: add here reader/writer lock
// main chain
- transactions_container m_transactions;
size_t m_current_block_cumul_weight_limit;
size_t m_current_block_cumul_weight_median;
@@ -1074,9 +1054,6 @@ namespace cryptonote
boost::thread_group m_async_pool;
std::unique_ptr<boost::asio::io_service::work> m_async_work_idle;
- // all alternative chains
- blocks_ext_by_hash m_alternative_chains; // crypto::hash -> block_extended_info
-
// some invalid blocks
blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info
@@ -1102,6 +1079,9 @@ namespace cryptonote
uint64_t m_btc_expected_reward;
bool m_btc_valid;
+
+ bool m_batch_success;
+
std::shared_ptr<tools::Notify> m_block_notify;
std::shared_ptr<tools::Notify> m_reorg_notify;
@@ -1183,7 +1163,7 @@ namespace cryptonote
*
* @return false if the reorganization fails, otherwise true
*/
- bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::const_iterator>& alt_chain, bool discard_disconnected_chain);
+ bool switch_to_alternative_blockchain(std::list<block_extended_info>& alt_chain, bool discard_disconnected_chain);
/**
* @brief removes the most recent block from the blockchain
@@ -1246,7 +1226,7 @@ namespace cryptonote
*
* @return true on success, false otherwise
*/
- bool build_alt_chain(const crypto::hash &prev_id, std::list<blocks_ext_by_hash::const_iterator>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const;
+ bool build_alt_chain(const crypto::hash &prev_id, std::list<block_extended_info>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const;
/**
* @brief gets the difficulty requirement for a new block on an alternate chain
@@ -1256,7 +1236,7 @@ namespace cryptonote
*
* @return the difficulty requirement
*/
- difficulty_type get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::const_iterator>& alt_chain, block_extended_info& bei) const;
+ difficulty_type get_next_difficulty_for_alternative_chain(const std::list<block_extended_info>& alt_chain, block_extended_info& bei) const;
/**
* @brief sanity checks a miner transaction before validating an entire block
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index be1ea5a17..2ebd99904 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -208,13 +208,17 @@ namespace cryptonote
"is acted upon."
, ""
};
+ static const command_line::arg_descriptor<bool> arg_keep_alt_blocks = {
+ "keep-alt-blocks"
+ , "Keep alternative blocks on restart"
+ , false
+ };
//-----------------------------------------------------------------------------------------------
core::core(i_cryptonote_protocol* pprotocol):
m_mempool(m_blockchain_storage),
m_blockchain_storage(m_mempool),
m_miner(this),
- m_miner_address(boost::value_initialized<account_public_address>()),
m_starter_message_showed(false),
m_target_blockchain_height(0),
m_checkpoints_path(""),
@@ -325,6 +329,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_prune_blockchain);
command_line::add_arg(desc, arg_reorg_notify);
command_line::add_arg(desc, arg_block_rate_notify);
+ command_line::add_arg(desc, arg_keep_alt_blocks);
miner::init_options(desc);
BlockchainDB::init_options(desc);
@@ -447,6 +452,7 @@ namespace cryptonote
m_nettype = FAKECHAIN;
}
bool r = handle_command_line(vm);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to handle command line");
std::string db_type = command_line::get_arg(vm, cryptonote::arg_db_type);
std::string db_sync_mode = command_line::get_arg(vm, cryptonote::arg_db_sync_mode);
@@ -456,6 +462,7 @@ namespace cryptonote
std::string check_updates_string = command_line::get_arg(vm, arg_check_updates);
size_t max_txpool_weight = command_line::get_arg(vm, arg_max_txpool_weight);
bool prune_blockchain = command_line::get_arg(vm, arg_prune_blockchain);
+ bool keep_alt_blocks = command_line::get_arg(vm, arg_keep_alt_blocks);
boost::filesystem::path folder(m_config_folder);
if (m_nettype == FAKECHAIN)
@@ -634,6 +641,7 @@ namespace cryptonote
};
const difficulty_type fixed_difficulty = command_line::get_arg(vm, arg_fixed_difficulty);
r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty, get_checkpoints);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
r = m_mempool.init(max_txpool_weight);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
@@ -671,12 +679,21 @@ namespace cryptonote
r = m_miner.init(vm, m_nettype);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance");
+ if (!keep_alt_blocks && !m_blockchain_storage.get_db().is_read_only())
+ m_blockchain_storage.get_db().drop_alt_blocks();
+
if (prune_blockchain)
{
// display a message if the blockchain is not pruned yet
- if (m_blockchain_storage.get_current_blockchain_height() > 1 && !m_blockchain_storage.get_blockchain_pruning_seed())
+ if (!m_blockchain_storage.get_blockchain_pruning_seed())
+ {
MGINFO("Pruning blockchain...");
- CHECK_AND_ASSERT_MES(m_blockchain_storage.prune_blockchain(), false, "Failed to prune blockchain");
+ CHECK_AND_ASSERT_MES(m_blockchain_storage.prune_blockchain(), false, "Failed to prune blockchain");
+ }
+ else
+ {
+ CHECK_AND_ASSERT_MES(m_blockchain_storage.update_blockchain_pruning(), false, "Failed to update blockchain pruning");
+ }
}
return load_state_data();
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 2fcf26a17..badbaf936 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -1014,7 +1014,6 @@ namespace cryptonote
//m_miner and m_miner_addres are probably temporary here
miner m_miner; //!< miner instance
- account_public_address m_miner_address; //!< address to mine to (for miner instance)
std::string m_config_folder; //!< folder to look in for configs and other files
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index c1cbe2acd..49d5a8ccc 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -95,13 +95,17 @@ namespace cryptonote
// the whole prepare/handle/cleanup incoming block sequence.
class LockedTXN {
public:
- LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false) {
+ LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false), m_active(false) {
m_batch = m_blockchain.get_db().batch_start();
+ m_active = true;
}
- ~LockedTXN() { try { if (m_batch) { m_blockchain.get_db().batch_stop(); } } catch (const std::exception &e) { MWARNING("LockedTXN dtor filtering exception: " << e.what()); } }
+ void commit() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_stop(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::commit filtering exception: " << e.what()); } }
+ void abort() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_abort(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::abort filtering exception: " << e.what()); } }
+ ~LockedTXN() { abort(); }
private:
Blockchain &m_blockchain;
bool m_batch;
+ bool m_active;
};
}
//---------------------------------------------------------------------------------
@@ -255,6 +259,7 @@ namespace cryptonote
if (!insert_key_images(tx, id, kept_by_block))
return false;
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
+ lock.commit();
}
catch (const std::exception &e)
{
@@ -299,6 +304,7 @@ namespace cryptonote
if (!insert_key_images(tx, id, kept_by_block))
return false;
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)tx_weight, receive_time), id);
+ lock.commit();
}
catch (const std::exception &e)
{
@@ -398,6 +404,7 @@ namespace cryptonote
return;
}
}
+ lock.commit();
if (changed)
++m_cookie;
if (m_txpool_weight > bytes)
@@ -494,6 +501,7 @@ namespace cryptonote
m_blockchain.remove_txpool_tx(id);
m_txpool_weight -= tx_weight;
remove_transaction_keyimages(tx, id);
+ lock.commit();
}
catch (const std::exception &e)
{
@@ -578,6 +586,7 @@ namespace cryptonote
// ignore error
}
}
+ lock.commit();
++m_cookie;
}
return true;
@@ -641,6 +650,7 @@ namespace cryptonote
// continue
}
}
+ lock.commit();
}
//---------------------------------------------------------------------------------
size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const
@@ -1119,6 +1129,7 @@ namespace cryptonote
}
}
}
+ lock.commit();
if (changed)
++m_cookie;
}
@@ -1271,6 +1282,7 @@ namespace cryptonote
append_key_images(k_images, tx);
LOG_PRINT_L2(" added, new block weight " << total_weight << "/" << max_total_weight << ", coinbase " << print_money(best_coinbase));
}
+ lock.commit();
expected_reward = best_coinbase;
LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, weight "
@@ -1336,6 +1348,7 @@ namespace cryptonote
// continue
}
}
+ lock.commit();
}
if (n_removed > 0)
++m_cookie;
@@ -1395,6 +1408,7 @@ namespace cryptonote
// ignore error
}
}
+ lock.commit();
}
m_cookie = 0;
diff --git a/src/cryptonote_core/tx_sanity_check.cpp b/src/cryptonote_core/tx_sanity_check.cpp
index 10198a3d3..36be91f2c 100644
--- a/src/cryptonote_core/tx_sanity_check.cpp
+++ b/src/cryptonote_core/tx_sanity_check.cpp
@@ -88,7 +88,7 @@ bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob
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)
+ if (median < n_available * 6 / 10)
{
MERROR("median is " << median << "/" << n_available);
return false;
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index 3083a5b4c..0fc6f40f3 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -172,11 +172,8 @@ namespace cryptonote
struct request_t
{
- std::vector<crypto::hash> txs;
- std::vector<crypto::hash> blocks;
-
+ std::vector<crypto::hash> blocks;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE_CONTAINER_POD_AS_BLOB(txs)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blocks)
END_KV_SERIALIZE_MAP()
};
@@ -189,13 +186,11 @@ namespace cryptonote
struct request_t
{
- std::vector<blobdata> txs;
std::vector<block_complete_entry> blocks;
std::vector<crypto::hash> missed_ids;
uint64_t current_blockchain_height;
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(txs)
KV_SERIALIZE(blocks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missed_ids)
KV_SERIALIZE(current_blockchain_height)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index 0927b5d7f..dcc5ec6ed 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -52,6 +52,7 @@ PUSH_WARNINGS
DISABLE_VS_WARNINGS(4355)
#define LOCALHOST_INT 2130706433
+#define CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT 500
namespace cryptonote
{
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 8958af7c7..940d35581 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -341,6 +341,11 @@ namespace cryptonote
if(m_core.have_block(hshd.top_id))
{
+ if (target > hshd.current_height)
+ {
+ MINFO(context << "peer is not ahead of us and we're syncing, disconnecting");
+ return false;
+ }
context.m_state = cryptonote_connection_context::state_normal;
if(is_inital && target == m_core.get_current_blockchain_height())
on_connection_synchronized();
@@ -809,12 +814,27 @@ namespace cryptonote
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
fluffy_response.b.block = t_serializable_object_to_blob(b);
fluffy_response.current_blockchain_height = arg.current_blockchain_height;
+ std::vector<bool> seen(b.tx_hashes.size(), false);
for(auto& tx_idx: arg.missing_tx_indices)
{
if(tx_idx < b.tx_hashes.size())
{
MDEBUG(" tx " << b.tx_hashes[tx_idx]);
+ if (seen[tx_idx])
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
+ << ", request is asking for duplicate tx "
+ << ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
+ << ", block_height = " << arg.current_blockchain_height
+ << ", dropping connection"
+ );
+ drop_connection(context, true, false);
+ return 1;
+ }
txids.push_back(b.tx_hashes[tx_idx]);
+ seen[tx_idx] = true;
}
else
{
@@ -913,7 +933,17 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
+ if (arg.blocks.size() > CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT)
+ {
+ LOG_ERROR_CCONTEXT(
+ "Requested objects count is too big ("
+ << arg.blocks.size() << ") expected not more then "
+ << CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT);
+ drop_connection(context, false, false);
+ return 1;
+ }
+
NOTIFY_RESPONSE_GET_OBJECTS::request rsp;
if(!m_core.handle_get_objects(arg, rsp, context))
{
@@ -921,8 +951,9 @@ namespace cryptonote
drop_connection(context, false, false);
return 1;
}
- MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size()
- << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height << ", missed_ids.size()=" << rsp.missed_ids.size());
+ MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
+ << rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
+ << ", missed_ids.size()=" << rsp.missed_ids.size());
post_notify<NOTIFY_RESPONSE_GET_OBJECTS>(rsp, context);
//handler_response_blocks_now(sizeof(rsp)); // XXX
//handler_response_blocks_now(200);
@@ -947,7 +978,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
+ MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
MLOG_PEER_STATE("received objects");
boost::posix_time::ptime request_time = context.m_last_request_time;
@@ -955,8 +986,6 @@ namespace cryptonote
// calculate size of request
size_t size = 0;
- for (const auto &element : arg.txs) size += element.size();
-
size_t blocks_size = 0;
for (const auto &element : arg.blocks) {
blocks_size += element.block.size();
@@ -1916,7 +1945,7 @@ skip:
}
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
- MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size() << ", txs.size()=" << req.txs.size()
+ MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
<< "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
//epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 17b945c9a..778d7b4d8 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -40,10 +40,11 @@ t_command_parser_executor::t_command_parser_executor(
uint32_t ip
, uint16_t port
, const boost::optional<tools::login>& login
+ , const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc
, cryptonote::core_rpc_server* rpc_server
)
- : m_executor(ip, port, login, is_rpc, rpc_server)
+ : m_executor(ip, port, login, ssl_options, is_rpc, rpc_server)
{}
bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& args)
@@ -493,11 +494,14 @@ bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& a
bool t_command_parser_executor::out_peers(const std::vector<std::string>& args)
{
- if (args.empty()) return false;
-
- unsigned int limit;
+ bool set = false;
+ uint32_t limit = 0;
try {
- limit = std::stoi(args[0]);
+ if (!args.empty())
+ {
+ limit = std::stoi(args[0]);
+ set = true;
+ }
}
catch(const std::exception& ex) {
@@ -505,16 +509,19 @@ bool t_command_parser_executor::out_peers(const std::vector<std::string>& args)
return false;
}
- return m_executor.out_peers(limit);
+ return m_executor.out_peers(set, limit);
}
bool t_command_parser_executor::in_peers(const std::vector<std::string>& args)
{
- if (args.empty()) return false;
-
- unsigned int limit;
+ bool set = false;
+ uint32_t limit = 0;
try {
- limit = std::stoi(args[0]);
+ if (!args.empty())
+ {
+ limit = std::stoi(args[0]);
+ set = true;
+ }
}
catch(const std::exception& ex) {
@@ -522,19 +529,7 @@ bool t_command_parser_executor::in_peers(const std::vector<std::string>& args)
return false;
}
- return m_executor.in_peers(limit);
-}
-
-bool t_command_parser_executor::start_save_graph(const std::vector<std::string>& args)
-{
- if (!args.empty()) return false;
- return m_executor.start_save_graph();
-}
-
-bool t_command_parser_executor::stop_save_graph(const std::vector<std::string>& args)
-{
- if (!args.empty()) return false;
- return m_executor.stop_save_graph();
+ return m_executor.in_peers(set, limit);
}
bool t_command_parser_executor::hard_fork_info(const std::vector<std::string>& args)
@@ -595,6 +590,13 @@ bool t_command_parser_executor::unban(const std::vector<std::string>& args)
return m_executor.unban(ip);
}
+bool t_command_parser_executor::banned(const std::vector<std::string>& args)
+{
+ if (args.size() != 1) return false;
+ std::string address = args[0];
+ return m_executor.banned(address);
+}
+
bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& args)
{
if (args.size() > 1) return false;
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index 098018642..d39bc1c9b 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -40,6 +40,7 @@
#include "daemon/rpc_command_executor.h"
#include "common/common_fwd.h"
+#include "net/net_fwd.h"
#include "rpc/core_rpc_server.h"
namespace daemonize {
@@ -53,6 +54,7 @@ public:
uint32_t ip
, uint16_t port
, const boost::optional<tools::login>& login
+ , const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc
, cryptonote::core_rpc_server* rpc_server = NULL
);
@@ -113,10 +115,6 @@ public:
bool in_peers(const std::vector<std::string>& args);
- bool start_save_graph(const std::vector<std::string>& args);
-
- bool stop_save_graph(const std::vector<std::string>& args);
-
bool hard_fork_info(const std::vector<std::string>& args);
bool show_bans(const std::vector<std::string>& args);
@@ -125,6 +123,8 @@ public:
bool unban(const std::vector<std::string>& args);
+ bool banned(const std::vector<std::string>& args);
+
bool flush_txpool(const std::vector<std::string>& args);
bool output_histogram(const std::vector<std::string>& args);
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 69ad6ff10..aecdda52c 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -43,10 +43,11 @@ t_command_server::t_command_server(
uint32_t ip
, uint16_t port
, const boost::optional<tools::login>& login
+ , const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc
, cryptonote::core_rpc_server* rpc_server
)
- : m_parser(ip, port, login, is_rpc, rpc_server)
+ : m_parser(ip, port, login, ssl_options, is_rpc, rpc_server)
, m_command_lookup()
, m_is_rpc(is_rpc)
{
@@ -214,16 +215,6 @@ t_command_server::t_command_server(
, "Set the <max_number> of in peers."
);
m_command_lookup.set_handler(
- "start_save_graph"
- , std::bind(&t_command_parser_executor::start_save_graph, &m_parser, p::_1)
- , "Start saving data for dr monero."
- );
- m_command_lookup.set_handler(
- "stop_save_graph"
- , std::bind(&t_command_parser_executor::stop_save_graph, &m_parser, p::_1)
- , "Stop saving data for dr monero."
- );
- m_command_lookup.set_handler(
"hard_fork_info"
, std::bind(&t_command_parser_executor::hard_fork_info, &m_parser, p::_1)
, "Print the hard fork voting information."
@@ -242,10 +233,16 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"unban"
, std::bind(&t_command_parser_executor::unban, &m_parser, p::_1)
- , "unban <IP>"
+ , "unban <address>"
, "Unban a given <IP>."
);
m_command_lookup.set_handler(
+ "banned"
+ , std::bind(&t_command_parser_executor::banned, &m_parser, p::_1)
+ , "banned <address>"
+ , "Check whether an <address> is banned."
+ );
+ m_command_lookup.set_handler(
"flush_txpool"
, std::bind(&t_command_parser_executor::flush_txpool, &m_parser, p::_1)
, "flush_txpool [<txid>]"
diff --git a/src/daemon/command_server.h b/src/daemon/command_server.h
index c8e77f551..da532223e 100644
--- a/src/daemon/command_server.h
+++ b/src/daemon/command_server.h
@@ -43,6 +43,7 @@ Passing RPC commands:
#include "common/common_fwd.h"
#include "console_handler.h"
#include "daemon/command_parser_executor.h"
+#include "net/net_fwd.h"
namespace daemonize {
@@ -57,6 +58,7 @@ public:
uint32_t ip
, uint16_t port
, const boost::optional<tools::login>& login
+ , const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc = true
, cryptonote::core_rpc_server* rpc_server = NULL
);
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 531c080de..5084b6283 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -45,6 +45,7 @@
#include "daemon/command_server.h"
#include "daemon/command_server.h"
#include "daemon/command_line_args.h"
+#include "net/net_ssl.h"
#include "version.h"
using namespace epee;
@@ -163,7 +164,7 @@ bool t_daemon::run(bool interactive)
if (interactive && mp_internals->rpcs.size())
{
// The first three variables are not used when the fourth is false
- rpc_commands.reset(new daemonize::t_command_server(0, 0, boost::none, false, mp_internals->rpcs.front()->get_server()));
+ rpc_commands.reset(new daemonize::t_command_server(0, 0, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_disabled, false, mp_internals->rpcs.front()->get_server()));
rpc_commands->start_handling(std::bind(&daemonize::t_daemon::stop_p2p, this));
}
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index dbbb2308c..690d4d60e 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -324,7 +324,11 @@ int main(int argc, char const * argv[])
}
}
- daemonize::t_command_server rpc_commands{rpc_ip, rpc_port, std::move(login)};
+ auto ssl_options = cryptonote::rpc_args::process_ssl(vm, true);
+ if (!ssl_options)
+ return 1;
+
+ daemonize::t_command_server rpc_commands{rpc_ip, rpc_port, std::move(login), std::move(*ssl_options)};
if (rpc_commands.process_command_vec(command))
{
return 0;
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 151baa33f..f3b9ea6ec 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -54,7 +54,7 @@ namespace {
std::string id_str;
std::string port_str;
- std::string elapsed = epee::misc_utils::get_time_interval_string(now - last_seen);
+ std::string elapsed = peer.last_seen == 0 ? "never" : epee::misc_utils::get_time_interval_string(now - last_seen);
std::string ip_str = epee::string_tools::get_ip_string_from_int32(peer.ip);
std::stringstream peer_id_str;
peer_id_str << std::hex << std::setw(16) << peer.id;
@@ -127,6 +127,7 @@ t_rpc_command_executor::t_rpc_command_executor(
uint32_t ip
, uint16_t port
, const boost::optional<tools::login>& login
+ , const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc
, cryptonote::core_rpc_server* rpc_server
)
@@ -137,7 +138,7 @@ t_rpc_command_executor::t_rpc_command_executor(
boost::optional<epee::net_utils::http::login> http_login{};
if (login)
http_login.emplace(login->username, login->password.password());
- m_rpc_client = new tools::t_rpc_client(ip, port, std::move(http_login));
+ m_rpc_client = new tools::t_rpc_client(ip, port, std::move(http_login), ssl_options);
}
else
{
@@ -337,6 +338,7 @@ bool t_rpc_command_executor::show_difficulty() {
tools::success_msg_writer() << "BH: " << res.height
<< ", TH: " << res.top_block_hash
<< ", DIFF: " << res.difficulty
+ << ", CUM_DIFF: " << res.cumulative_difficulty
<< ", HR: " << res.difficulty / res.target << " H/s";
return true;
@@ -1465,13 +1467,14 @@ bool t_rpc_command_executor::get_limit_down()
return true;
}
-bool t_rpc_command_executor::out_peers(uint64_t limit)
+bool t_rpc_command_executor::out_peers(bool set, uint32_t limit)
{
cryptonote::COMMAND_RPC_OUT_PEERS::request req;
cryptonote::COMMAND_RPC_OUT_PEERS::response res;
epee::json_rpc::error error_resp;
+ req.set = set;
req.out_peers = limit;
std::string fail_message = "Unsuccessful";
@@ -1492,18 +1495,20 @@ bool t_rpc_command_executor::out_peers(uint64_t limit)
}
}
- tools::msg_writer() << "Max number of out peers set to " << limit << std::endl;
+ const std::string s = res.out_peers == (uint32_t)-1 ? "unlimited" : std::to_string(res.out_peers);
+ tools::msg_writer() << "Max number of out peers set to " << s << std::endl;
return true;
}
-bool t_rpc_command_executor::in_peers(uint64_t limit)
+bool t_rpc_command_executor::in_peers(bool set, uint32_t limit)
{
cryptonote::COMMAND_RPC_IN_PEERS::request req;
cryptonote::COMMAND_RPC_IN_PEERS::response res;
epee::json_rpc::error error_resp;
+ req.set = set;
req.in_peers = limit;
std::string fail_message = "Unsuccessful";
@@ -1524,64 +1529,12 @@ bool t_rpc_command_executor::in_peers(uint64_t limit)
}
}
- tools::msg_writer() << "Max number of in peers set to " << limit << std::endl;
+ const std::string s = res.in_peers == (uint32_t)-1 ? "unlimited" : std::to_string(res.in_peers);
+ tools::msg_writer() << "Max number of in peers set to " << s << std::endl;
return true;
}
-bool t_rpc_command_executor::start_save_graph()
-{
- cryptonote::COMMAND_RPC_START_SAVE_GRAPH::request req;
- cryptonote::COMMAND_RPC_START_SAVE_GRAPH::response res;
- std::string fail_message = "Unsuccessful";
-
- if (m_is_rpc)
- {
- if (!m_rpc_client->rpc_request(req, res, "/start_save_graph", fail_message.c_str()))
- {
- return true;
- }
- }
-
- else
- {
- if (!m_rpc_server->on_start_save_graph(req, res) || res.status != CORE_RPC_STATUS_OK)
- {
- tools::fail_msg_writer() << make_error(fail_message, res.status);
- return true;
- }
- }
-
- tools::success_msg_writer() << "Saving graph is now on";
- return true;
-}
-
-bool t_rpc_command_executor::stop_save_graph()
-{
- cryptonote::COMMAND_RPC_STOP_SAVE_GRAPH::request req;
- cryptonote::COMMAND_RPC_STOP_SAVE_GRAPH::response res;
- std::string fail_message = "Unsuccessful";
-
- if (m_is_rpc)
- {
- if (!m_rpc_client->rpc_request(req, res, "/stop_save_graph", fail_message.c_str()))
- {
- return true;
- }
- }
-
- else
- {
- if (!m_rpc_server->on_stop_save_graph(req, res) || res.status != CORE_RPC_STATUS_OK)
- {
- tools::fail_msg_writer() << make_error(fail_message, res.status);
- return true;
- }
- }
- tools::success_msg_writer() << "Saving graph is now off";
- return true;
-}
-
bool t_rpc_command_executor::hard_fork_info(uint8_t version)
{
cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req;
@@ -1640,14 +1593,14 @@ bool t_rpc_command_executor::print_bans()
for (auto i = res.bans.begin(); i != res.bans.end(); ++i)
{
- tools::msg_writer() << epee::string_tools::get_ip_string_from_int32(i->ip) << " banned for " << i->seconds << " seconds";
+ tools::msg_writer() << i->host << " banned for " << i->seconds << " seconds";
}
return true;
}
-bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds)
+bool t_rpc_command_executor::ban(const std::string &address, time_t seconds)
{
cryptonote::COMMAND_RPC_SETBANS::request req;
cryptonote::COMMAND_RPC_SETBANS::response res;
@@ -1655,11 +1608,8 @@ bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds)
epee::json_rpc::error error_resp;
cryptonote::COMMAND_RPC_SETBANS::ban ban;
- if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip))
- {
- tools::fail_msg_writer() << "Invalid IP";
- return true;
- }
+ ban.host = address;
+ ban.ip = 0;
ban.ban = true;
ban.seconds = seconds;
req.bans.push_back(ban);
@@ -1683,7 +1633,7 @@ bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds)
return true;
}
-bool t_rpc_command_executor::unban(const std::string &ip)
+bool t_rpc_command_executor::unban(const std::string &address)
{
cryptonote::COMMAND_RPC_SETBANS::request req;
cryptonote::COMMAND_RPC_SETBANS::response res;
@@ -1691,11 +1641,8 @@ bool t_rpc_command_executor::unban(const std::string &ip)
epee::json_rpc::error error_resp;
cryptonote::COMMAND_RPC_SETBANS::ban ban;
- if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip))
- {
- tools::fail_msg_writer() << "Invalid IP";
- return true;
- }
+ ban.host = address;
+ ban.ip = 0;
ban.ban = false;
ban.seconds = 0;
req.bans.push_back(ban);
@@ -1719,6 +1666,39 @@ bool t_rpc_command_executor::unban(const std::string &ip)
return true;
}
+bool t_rpc_command_executor::banned(const std::string &address)
+{
+ cryptonote::COMMAND_RPC_BANNED::request req;
+ cryptonote::COMMAND_RPC_BANNED::response res;
+ std::string fail_message = "Unsuccessful";
+ epee::json_rpc::error error_resp;
+
+ req.address = address;
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->json_rpc_request(req, res, "banned", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_banned(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, res.status);
+ return true;
+ }
+ }
+
+ if (res.banned)
+ tools::msg_writer() << address << " is banned for " << res.seconds << " seconds";
+ else
+ tools::msg_writer() << address << " is not banned";
+
+ return true;
+}
+
bool t_rpc_command_executor::flush_txpool(const std::string &txid)
{
cryptonote::COMMAND_RPC_FLUSH_TRANSACTION_POOL::request req;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 3c2686b3f..4622609ae 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -43,6 +43,7 @@
#include "common/common_fwd.h"
#include "common/rpc_client.h"
#include "cryptonote_basic/cryptonote_basic.h"
+#include "net/net_fwd.h"
#include "rpc/core_rpc_server.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -61,6 +62,7 @@ public:
uint32_t ip
, uint16_t port
, const boost::optional<tools::login>& user
+ , const epee::net_utils::ssl_options_t& ssl_options
, bool is_rpc = true
, cryptonote::core_rpc_server* rpc_server = NULL
);
@@ -123,21 +125,19 @@ public:
bool set_limit(int64_t limit_down, int64_t limit_up);
- bool out_peers(uint64_t limit);
+ bool out_peers(bool set, uint32_t limit);
- bool in_peers(uint64_t limit);
+ bool in_peers(bool set, uint32_t limit);
- bool start_save_graph();
-
- bool stop_save_graph();
-
bool hard_fork_info(uint8_t version);
bool print_bans();
- bool ban(const std::string &ip, time_t seconds);
+ bool ban(const std::string &address, time_t seconds);
- bool unban(const std::string &ip);
+ bool unban(const std::string &address);
+
+ bool banned(const std::string &address);
bool flush_txpool(const std::string &txid);
diff --git a/src/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt
index 7bc2c324f..03c2b3e20 100644
--- a/src/debug_utilities/CMakeLists.txt
+++ b/src/debug_utilities/CMakeLists.txt
@@ -69,3 +69,25 @@ set_property(TARGET object_sizes
PROPERTY
OUTPUT_NAME "monero-utils-object-sizes")
+
+set(dns_checks_sources
+ dns_checks.cpp
+ )
+
+monero_add_executable(dns_checks
+ ${dns_checks_sources}
+ ${dns_checks_private_headers})
+
+target_link_libraries(dns_checks
+ LINK_PRIVATE
+ common
+ epee
+ version
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_SYSTEM_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT})
+
+set_property(TARGET dns_checks
+ PROPERTY
+ OUTPUT_NAME "monero-utils-dns-checks")
+
diff --git a/src/debug_utilities/dns_checks.cpp b/src/debug_utilities/dns_checks.cpp
new file mode 100644
index 000000000..3c9daa769
--- /dev/null
+++ b/src/debug_utilities/dns_checks.cpp
@@ -0,0 +1,149 @@
+// 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 <string>
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <boost/program_options.hpp>
+#include "misc_log_ex.h"
+#include "common/util.h"
+#include "common/command_line.h"
+#include "common/dns_utils.h"
+#include "version.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "debugtools.dnschecks"
+
+namespace po = boost::program_options;
+
+enum lookup_t { LOOKUP_A, LOOKUP_TXT };
+
+static std::vector<std::string> lookup(lookup_t type, const char *hostname)
+{
+ bool dnssec_available = false, dnssec_valid = false;
+ std::vector<std::string> res;
+ switch (type)
+ {
+ case LOOKUP_A: res = tools::DNSResolver::instance().get_ipv4(hostname, dnssec_available, dnssec_valid); break;
+ case LOOKUP_TXT: res = tools::DNSResolver::instance().get_txt_record(hostname, dnssec_available, dnssec_valid); break;
+ default: MERROR("Invalid lookup type: " << (int)type); return {};
+ }
+ if (!dnssec_available)
+ {
+ MWARNING("No DNSSEC for " << hostname);
+ return {};
+ }
+ if (!dnssec_valid)
+ {
+ MWARNING("Invalid DNSSEC check for " << hostname);
+ return {};
+ }
+ MINFO(res.size() << " valid signed result(s) for " << hostname);
+ return res;
+}
+
+static void lookup(lookup_t type, const std::vector<std::string> hostnames)
+{
+ std::vector<std::vector<std::string>> results;
+ for (const std::string &hostname: hostnames)
+ {
+ auto res = lookup(type, hostname.c_str());
+ if (!res.empty())
+ {
+ std::sort(res.begin(), res.end());
+ results.push_back(res);
+ }
+ }
+ std::map<std::vector<std::string>, size_t> counter;
+ for (const auto &e: results)
+ counter[e]++;
+ size_t count = 0;
+ for (const auto &e: counter)
+ count = std::max(count, e.second);
+ if (results.size() > 1)
+ {
+ if (count < results.size())
+ MERROR("Only " << count << "/" << results.size() << " records match");
+ else
+ MINFO(count << "/" << results.size() << " records match");
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ TRY_ENTRY();
+
+ tools::on_startup();
+
+ po::options_description desc_cmd_only("Command line options");
+ po::options_description desc_cmd_sett("Command line options and settings options");
+
+ command_line::add_arg(desc_cmd_only, command_line::arg_help);
+
+ po::options_description desc_options("Allowed options");
+ desc_options.add(desc_cmd_only).add(desc_cmd_sett);
+
+ po::variables_map vm;
+ bool r = command_line::handle_error_helper(desc_options, [&]()
+ {
+ po::store(po::parse_command_line(argc, argv, desc_options), vm);
+ po::notify(vm);
+ return true;
+ });
+ if (! r)
+ return 1;
+
+ if (command_line::get_arg(vm, command_line::arg_help))
+ {
+ std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
+ std::cout << desc_options << std::endl;
+ return 1;
+ }
+
+ mlog_configure("", true);
+ mlog_set_categories("+" MONERO_DEFAULT_LOG_CATEGORY ":INFO");
+
+ lookup(LOOKUP_A, {"seeds.moneroseeds.se", "seeds.moneroseeds.ae.org", "seeds.moneroseeds.ch", "seeds.moneroseeds.li"});
+
+ lookup(LOOKUP_TXT, {"updates.moneropulse.org", "updates.moneropulse.net", "updates.moneropulse.co", "updates.moneropulse.se"});
+
+ lookup(LOOKUP_TXT, {"checkpoints.moneropulse.org", "checkpoints.moneropulse.net", "checkpoints.moneropulse.co", "checkpoints.moneropulse.se"});
+
+ // those are in the code, but don't seem to actually exist
+#if 0
+ lookup(LOOKUP_TXT, {"testpoints.moneropulse.org", "testpoints.moneropulse.net", "testpoints.moneropulse.co", "testpoints.moneropulse.se");
+
+ lookup(LOOKUP_TXT, {"stagenetpoints.moneropulse.org", "stagenetpoints.moneropulse.net", "stagenetpoints.moneropulse.co", "stagenetpoints.moneropulse.se"});
+#endif
+
+ lookup(LOOKUP_TXT, {"segheights.moneropulse.org", "segheights.moneropulse.net", "segheights.moneropulse.co", "segheights.moneropulse.se"});
+
+ return 0;
+ CATCH_ENTRY_L0("main", 1);
+}
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index 200370564..eba633da8 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -90,6 +90,20 @@ namespace hw {
AKout = keys.AKout;
}
+ ABPkeys &ABPkeys::operator=(const ABPkeys& keys) {
+ if (&keys == this)
+ return *this;
+ Aout = keys.Aout;
+ Bout = keys.Bout;
+ is_subaddress = keys.is_subaddress;
+ is_change_address = keys.is_change_address;
+ additional_key = keys.additional_key;
+ index = keys.index;
+ Pout = keys.Pout;
+ AKout = keys.AKout;
+ return *this;
+ }
+
bool Keymap::find(const rct::key& P, ABPkeys& keys) const {
size_t sz = ABP.size();
for (size_t i=0; i<sz; i++) {
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index d4d98ce4a..fe9028733 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -77,6 +77,7 @@ namespace hw {
ABPkeys(const rct::key& A, const rct::key& B, const bool is_subaddr, bool is_subaddress, bool is_change_address, size_t index, const rct::key& P,const rct::key& AK);
ABPkeys(const ABPkeys& keys) ;
ABPkeys() {index=0;is_subaddress=false;is_subaddress=false;is_change_address=false;}
+ ABPkeys &operator=(const ABPkeys &keys);
};
class Keymap {
diff --git a/src/net/error.h b/src/net/error.h
index c8338f7e2..7c852dd20 100644
--- a/src/net/error.h
+++ b/src/net/error.h
@@ -42,7 +42,8 @@ namespace net
invalid_i2p_address,
invalid_port, //!< Outside of 0-65535 range
invalid_tor_address,//!< Invalid base32 or length
- unsupported_address //!< Type not supported by `get_network_address`
+ unsupported_address,//!< Type not supported by `get_network_address`
+ invalid_mask, //!< Outside of 0-32 range
};
//! \return `std::error_category` for `net` namespace.
diff --git a/src/net/parse.cpp b/src/net/parse.cpp
index eaaadb67e..d93d7d352 100644
--- a/src/net/parse.cpp
+++ b/src/net/parse.cpp
@@ -58,4 +58,27 @@ namespace net
return {epee::net_utils::ipv4_network_address{ip, port}};
return make_error_code(net::error::unsupported_address);
}
+
+ expect<epee::net_utils::ipv4_network_subnet>
+ get_ipv4_subnet_address(const boost::string_ref address, bool allow_implicit_32)
+ {
+ uint32_t mask = 32;
+ const boost::string_ref::size_type slash = address.find_first_of('/');
+ if (slash != boost::string_ref::npos)
+ {
+ if (!epee::string_tools::get_xtype_from_string(mask, std::string{address.substr(slash + 1)}))
+ return make_error_code(net::error::invalid_mask);
+ if (mask > 32)
+ return make_error_code(net::error::invalid_mask);
+ }
+ else if (!allow_implicit_32)
+ return make_error_code(net::error::invalid_mask);
+
+ std::uint32_t ip = 0;
+ boost::string_ref S(address.data(), slash != boost::string_ref::npos ? slash : address.size());
+ if (!epee::string_tools::get_ip_int32_from_string(ip, std::string(S)))
+ return make_error_code(net::error::invalid_host);
+
+ return {epee::net_utils::ipv4_network_subnet{ip, (uint8_t)mask}};
+ }
}
diff --git a/src/net/parse.h b/src/net/parse.h
index 5804c4128..9f0d66ea6 100644
--- a/src/net/parse.h
+++ b/src/net/parse.h
@@ -50,5 +50,18 @@ namespace net
*/
expect<epee::net_utils::network_address>
get_network_address(boost::string_ref address, std::uint16_t default_port);
+
+ /*!
+ Identifies an IPv4 subnet in CIDR notatioa and returns it as a generic
+ `network_address`. If the type is unsupported, it might be a hostname,
+ and `error() == net::error::kUnsupportedAddress` is returned.
+
+ \param address An ipv4 address.
+ \param allow_implicit_32 whether to accept "raw" IPv4 addresses, with CIDR notation
+
+ \return A tor or IPv4 address, else error.
+ */
+ expect<epee::net_utils::ipv4_network_subnet>
+ get_ipv4_subnet_address(boost::string_ref address, bool allow_implicit_32 = false);
}
diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp
index fcbcce58c..b55003d75 100644
--- a/src/p2p/net_node.cpp
+++ b/src/p2p/net_node.cpp
@@ -143,8 +143,6 @@ namespace nodetool
const command_line::arg_descriptor<int64_t> arg_limit_rate_down = {"limit-rate-down", "set limit-rate-down [kB/s]", P2P_DEFAULT_LIMIT_RATE_DOWN};
const command_line::arg_descriptor<int64_t> arg_limit_rate = {"limit-rate", "set limit-rate [kB/s]", -1};
- const command_line::arg_descriptor<bool> arg_save_graph = {"save-graph", "Save data for dr monero", false};
-
boost::optional<std::vector<proxy>> get_proxies(boost::program_options::variables_map const& vm)
{
namespace ip = boost::asio::ip;
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 42bb3b061..5d9e19d5d 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -216,7 +216,6 @@ namespace nodetool
m_hide_my_port(false),
m_no_igd(false),
m_offline(false),
- m_save_graph(false),
is_closing(false),
m_network_id()
{}
@@ -245,10 +244,16 @@ namespace nodetool
size_t get_zone_count() const { return m_network_zones.size(); }
void change_max_out_public_peers(size_t count);
+ uint32_t get_max_out_public_peers() const;
void change_max_in_public_peers(size_t count);
+ uint32_t get_max_in_public_peers() const;
virtual bool block_host(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME);
virtual bool unblock_host(const epee::net_utils::network_address &address);
- virtual std::map<std::string, time_t> get_blocked_hosts() { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return m_blocked_hosts; }
+ virtual bool block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds = P2P_IP_BLOCKTIME);
+ virtual bool unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet);
+ virtual bool is_host_blocked(const epee::net_utils::network_address &address, time_t *seconds) { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return !is_remote_host_allowed(address, seconds); }
+ virtual std::map<epee::net_utils::network_address, time_t> get_blocked_hosts() { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return m_blocked_hosts; }
+ virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets() { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return m_blocked_subnets; }
virtual void add_used_stripe_peer(const typename t_payload_net_handler::connection_context &context);
virtual void remove_used_stripe_peer(const typename t_payload_net_handler::connection_context &context);
@@ -319,7 +324,7 @@ namespace nodetool
virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f);
virtual bool add_host_fail(const epee::net_utils::network_address &address);
//----------------- i_connection_filter --------------------------------------------------------
- virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address);
+ virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address, time_t *t = NULL);
//-----------------------------------------------------------------------------------------------
bool parse_peer_from_string(epee::net_utils::network_address& pe, const std::string& node_addr, uint16_t default_port = 0);
bool handle_command_line(
@@ -396,12 +401,6 @@ namespace nodetool
public:
- void set_save_graph(bool save_graph)
- {
- m_save_graph = save_graph;
- epee::net_utils::connection_basic::set_save_graph(save_graph);
- }
-
void set_rpc_port(uint16_t rpc_port)
{
m_rpc_port = rpc_port;
@@ -419,7 +418,6 @@ namespace nodetool
bool m_hide_my_port;
bool m_no_igd;
bool m_offline;
- std::atomic<bool> m_save_graph;
std::atomic<bool> is_closing;
std::unique_ptr<boost::thread> mPeersLoggerThread;
//critical_section m_connections_lock;
@@ -461,8 +459,9 @@ namespace nodetool
std::map<epee::net_utils::network_address, time_t> m_conn_fails_cache;
epee::critical_section m_conn_fails_cache_lock;
- epee::critical_section m_blocked_hosts_lock;
- std::map<std::string, time_t> m_blocked_hosts;
+ epee::critical_section m_blocked_hosts_lock; // for both hosts and subnets
+ std::map<epee::net_utils::network_address, time_t> m_blocked_hosts;
+ std::map<epee::net_utils::ipv4_network_subnet, time_t> m_blocked_subnets;
epee::critical_section m_host_fails_score_lock;
std::map<std::string, uint64_t> m_host_fails_score;
@@ -500,8 +499,6 @@ namespace nodetool
extern const command_line::arg_descriptor<int64_t> arg_limit_rate_up;
extern const command_line::arg_descriptor<int64_t> arg_limit_rate_down;
extern const command_line::arg_descriptor<int64_t> arg_limit_rate;
-
- extern const command_line::arg_descriptor<bool> arg_save_graph;
}
POP_WARNINGS
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index ba29d92c9..ba7326286 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -111,7 +111,6 @@ namespace nodetool
command_line::add_arg(desc, arg_limit_rate_up);
command_line::add_arg(desc, arg_limit_rate_down);
command_line::add_arg(desc, arg_limit_rate);
- command_line::add_arg(desc, arg_save_graph);
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@@ -155,19 +154,55 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::is_remote_host_allowed(const epee::net_utils::network_address &address)
+ bool node_server<t_payload_net_handler>::is_remote_host_allowed(const epee::net_utils::network_address &address, time_t *t)
{
CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
- auto it = m_blocked_hosts.find(address.host_str());
- if(it == m_blocked_hosts.end())
- return true;
- if(time(nullptr) >= it->second)
+
+ const time_t now = time(nullptr);
+
+ // look in the hosts list
+ auto it = m_blocked_hosts.find(address);
+ if (it != m_blocked_hosts.end())
{
- m_blocked_hosts.erase(it);
- MCLOG_CYAN(el::Level::Info, "global", "Host " << address.host_str() << " unblocked.");
- return true;
+ if (now >= it->second)
+ {
+ m_blocked_hosts.erase(it);
+ MCLOG_CYAN(el::Level::Info, "global", "Host " << address.host_str() << " unblocked.");
+ it = m_blocked_hosts.end();
+ }
+ else
+ {
+ if (t)
+ *t = it->second - now;
+ return false;
+ }
}
- return false;
+
+ // manually loop in subnets
+ if (address.get_type_id() == epee::net_utils::address_type::ipv4)
+ {
+ auto ipv4_address = address.template as<epee::net_utils::ipv4_network_address>();
+ std::map<epee::net_utils::ipv4_network_subnet, time_t>::iterator it;
+ for (it = m_blocked_subnets.begin(); it != m_blocked_subnets.end(); )
+ {
+ if (now >= it->second)
+ {
+ it = m_blocked_subnets.erase(it);
+ MCLOG_CYAN(el::Level::Info, "global", "Subnet " << it->first.host_str() << " unblocked.");
+ continue;
+ }
+ if (it->first.matches(ipv4_address))
+ {
+ if (t)
+ *t = it->second - now;
+ return false;
+ }
+ ++it;
+ }
+ }
+
+ // not found in hosts or subnets, allowed
+ return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@@ -184,7 +219,7 @@ namespace nodetool
limit = std::numeric_limits<time_t>::max();
else
limit = now + seconds;
- m_blocked_hosts[addr.host_str()] = limit;
+ m_blocked_hosts[addr] = 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
@@ -214,7 +249,7 @@ namespace nodetool
bool node_server<t_payload_net_handler>::unblock_host(const epee::net_utils::network_address &address)
{
CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
- auto i = m_blocked_hosts.find(address.host_str());
+ auto i = m_blocked_hosts.find(address);
if (i == m_blocked_hosts.end())
return false;
m_blocked_hosts.erase(i);
@@ -223,6 +258,58 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds)
+ {
+ const time_t now = time(nullptr);
+
+ CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
+ 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_subnets[subnet] = limit;
+
+ // drop any connection to that subnet. This should only have to look into
+ // the zone related to the connection, but really make sure everything is
+ // swept ...
+ std::vector<boost::uuids::uuid> conns;
+ for(auto& zone : m_network_zones)
+ {
+ zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if (cntxt.m_remote_address.get_type_id() != epee::net_utils::ipv4_network_address::get_type_id())
+ return true;
+ auto ipv4_address = cntxt.m_remote_address.template as<epee::net_utils::ipv4_network_address>();
+ if (subnet.matches(ipv4_address))
+ {
+ conns.push_back(cntxt.m_connection_id);
+ }
+ return true;
+ });
+ for (const auto &c: conns)
+ zone.second.m_net_server.get_config_object().close(c);
+
+ conns.clear();
+ }
+
+ MCLOG_CYAN(el::Level::Info, "global", "Subnet " << subnet.host_str() << " blocked.");
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet)
+ {
+ CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
+ auto i = m_blocked_subnets.find(subnet);
+ if (i == m_blocked_subnets.end())
+ return false;
+ m_blocked_subnets.erase(i);
+ MCLOG_CYAN(el::Level::Info, "global", "Subnet " << subnet.host_str() << " unblocked.");
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::add_host_fail(const epee::net_utils::network_address &address)
{
if(!address.is_blockable())
@@ -292,11 +379,6 @@ namespace nodetool
}
}
- if(command_line::has_arg(vm, arg_save_graph))
- {
- set_save_graph(true);
- }
-
if (command_line::has_arg(vm,arg_p2p_add_exclusive_node))
{
if (!parse_peers_and_add_to_container(vm, arg_p2p_add_exclusive_node, m_exclusive_peers))
@@ -944,7 +1026,10 @@ namespace nodetool
}
if(!context.m_is_income)
m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port);
- m_payload_handler.process_payload_sync_data(rsp.payload_data, context, false);
+ if (!m_payload_handler.process_payload_sync_data(rsp.payload_data, context, false))
+ {
+ m_network_zones.at(context.m_remote_address.get_zone()).m_net_server.get_config_object().close(context.m_connection_id );
+ }
});
if(!r)
@@ -1090,6 +1175,7 @@ namespace nodetool
LOG_PRINT_CC_PRIORITY_NODE(is_priority, *con, "Failed to HANDSHAKE with peer "
<< na.str()
/*<< ", try " << try_count*/);
+ zone.m_net_server.get_config_object().close(con->m_connection_id);
return false;
}
@@ -1149,7 +1235,7 @@ namespace nodetool
bool is_priority = is_priority_node(na);
LOG_PRINT_CC_PRIORITY_NODE(is_priority, *con, "Failed to HANDSHAKE with peer " << na.str());
-
+ zone.m_net_server.get_config_object().close(con->m_connection_id);
return false;
}
@@ -1226,19 +1312,53 @@ namespace nodetool
size_t random_index;
const uint32_t next_needed_pruning_stripe = m_payload_handler.get_next_needed_pruning_stripe().second;
+ // build a set of all the /16 we're connected to, and prefer a peer that's not in that set
+ std::set<uint32_t> classB;
+ if (&zone == &m_network_zones.at(epee::net_utils::zone::public_)) // at returns reference, not copy
+ {
+ zone.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
+ {
+
+ const epee::net_utils::network_address na = cntxt.m_remote_address;
+ const uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
+ classB.insert(actual_ip & 0x0000ffff);
+ }
+ return true;
+ });
+ }
+
std::deque<size_t> filtered;
const size_t limit = use_white_list ? 20 : std::numeric_limits<size_t>::max();
- size_t idx = 0;
- zone.m_peerlist.foreach (use_white_list, [&filtered, &idx, limit, next_needed_pruning_stripe](const peerlist_entry &pe){
- if (filtered.size() >= limit)
- return false;
- if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0)
- filtered.push_back(idx);
- else if (next_needed_pruning_stripe == tools::get_pruning_stripe(pe.pruning_seed))
- filtered.push_front(idx);
- ++idx;
- return true;
- });
+ size_t idx = 0, skipped = 0;
+ for (int step = 0; step < 2; ++step)
+ {
+ bool skip_duplicate_class_B = step == 0;
+ zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe](const peerlist_entry &pe){
+ if (filtered.size() >= limit)
+ return false;
+ bool skip = false;
+ if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
+ {
+ const epee::net_utils::network_address na = pe.adr;
+ uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
+ skip = classB.find(actual_ip & 0x0000ffff) != classB.end();
+ }
+ if (skip)
+ ++skipped;
+ else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0)
+ filtered.push_back(idx);
+ else if (next_needed_pruning_stripe == tools::get_pruning_stripe(pe.pruning_seed))
+ filtered.push_front(idx);
+ ++idx;
+ return true;
+ });
+ if (skipped == 0 || !filtered.empty())
+ break;
+ if (skipped)
+ MGINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers");
+ }
if (filtered.empty())
{
MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
@@ -2217,6 +2337,15 @@ namespace nodetool
}
template<class t_payload_net_handler>
+ uint32_t node_server<t_payload_net_handler>::get_max_out_public_peers() const
+ {
+ const auto public_zone = m_network_zones.find(epee::net_utils::zone::public_);
+ if (public_zone == m_network_zones.end())
+ return 0;
+ return public_zone->second.m_config.m_net_config.max_out_connection_count;
+ }
+
+ template<class t_payload_net_handler>
void node_server<t_payload_net_handler>::change_max_in_public_peers(size_t count)
{
auto public_zone = m_network_zones.find(epee::net_utils::zone::public_);
@@ -2230,6 +2359,15 @@ namespace nodetool
}
template<class t_payload_net_handler>
+ uint32_t node_server<t_payload_net_handler>::get_max_in_public_peers() const
+ {
+ const auto public_zone = m_network_zones.find(epee::net_utils::zone::public_);
+ if (public_zone == m_network_zones.end())
+ return 0;
+ return public_zone->second.m_config.m_net_config.max_in_connection_count;
+ }
+
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::set_tos_flag(const boost::program_options::variables_map& vm, int flag)
{
if(flag==-1){
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 26451b333..34d151f5f 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -56,7 +56,8 @@ namespace nodetool
virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds = 0)=0;
virtual bool unblock_host(const epee::net_utils::network_address &address)=0;
- virtual std::map<std::string, time_t> get_blocked_hosts()=0;
+ virtual std::map<epee::net_utils::network_address, time_t> get_blocked_hosts()=0;
+ virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()=0;
virtual bool add_host_fail(const epee::net_utils::network_address &address)=0;
virtual void add_used_stripe_peer(const t_connection_context &context)=0;
virtual void remove_used_stripe_peer(const t_connection_context &context)=0;
@@ -112,9 +113,13 @@ namespace nodetool
{
return true;
}
- virtual std::map<std::string, time_t> get_blocked_hosts()
+ virtual std::map<epee::net_utils::network_address, time_t> get_blocked_hosts()
{
- return std::map<std::string, time_t>();
+ return std::map<epee::net_utils::network_address, time_t>();
+ }
+ virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()
+ {
+ return std::map<epee::net_utils::ipv4_network_subnet, time_t>();
}
virtual bool add_host_fail(const epee::net_utils::network_address &address)
{
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index f4fa921e2..883997fd6 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -344,8 +344,14 @@ namespace nodetool
trim_white_peerlist();
}else
{
- //update record in white list
- m_peers_white.replace(by_addr_it_wt, ple);
+ //update record in white list
+ peerlist_entry new_ple = ple;
+ if (by_addr_it_wt->pruning_seed && ple.pruning_seed == 0) // guard against older nodes not passing pruning info around
+ new_ple.pruning_seed = by_addr_it_wt->pruning_seed;
+ if (by_addr_it_wt->rpc_port && ple.rpc_port == 0) // guard against older nodes not passing RPC port around
+ new_ple.rpc_port = by_addr_it_wt->rpc_port;
+ new_ple.last_seen = by_addr_it_wt->last_seen; // do not overwrite the last seen timestamp, incoming peer list are untrusted
+ m_peers_white.replace(by_addr_it_wt, new_ple);
}
//remove from gray list, if need
auto by_addr_it_gr = m_peers_gray.get<by_addr>().find(ple.adr);
@@ -379,8 +385,14 @@ namespace nodetool
trim_gray_peerlist();
}else
{
- //update record in white list
- m_peers_gray.replace(by_addr_it_gr, ple);
+ //update record in gray list
+ peerlist_entry new_ple = ple;
+ if (by_addr_it_gr->pruning_seed && ple.pruning_seed == 0) // guard against older nodes not passing pruning info around
+ new_ple.pruning_seed = by_addr_it_gr->pruning_seed;
+ if (by_addr_it_gr->rpc_port && ple.rpc_port == 0) // guard against older nodes not passing RPC port around
+ new_ple.rpc_port = by_addr_it_gr->rpc_port;
+ new_ple.last_seen = by_addr_it_gr->last_seen; // do not overwrite the last seen timestamp, incoming peer list are untrusted
+ m_peers_gray.replace(by_addr_it_gr, new_ple);
}
return true;
CATCH_ENTRY_L0("peerlist_manager::append_with_peer_gray()", false);
diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h
index 40ef2ebcd..32f30adca 100644
--- a/src/p2p/net_peerlist_boost_serialization.h
+++ b/src/p2p/net_peerlist_boost_serialization.h
@@ -134,10 +134,11 @@ namespace boost
a & port;
a & length;
- if (length > net::tor_address::buffer_size())
+ const size_t buffer_size = net::tor_address::buffer_size();
+ if (length > buffer_size)
MONERO_THROW(net::error::invalid_tor_address, "Tor address too long");
- char host[net::tor_address::buffer_size()] = {0};
+ char host[buffer_size] = {0};
a.load_binary(host, length);
host[sizeof(host) - 1] = 0;
@@ -155,10 +156,11 @@ namespace boost
a & port;
a & length;
- if (length > net::i2p_address::buffer_size())
+ const size_t buffer_size = net::i2p_address::buffer_size();
+ if (length > buffer_size)
MONERO_THROW(net::error::invalid_i2p_address, "i2p address too long");
- char host[net::i2p_address::buffer_size()] = {0};
+ char host[buffer_size] = {0};
a.load_binary(host, length);
host[sizeof(host) - 1] = 0;
diff --git a/src/ringct/multiexp.cc b/src/ringct/multiexp.cc
index 6f77fed34..f69b4a12c 100644
--- a/src/ringct/multiexp.cc
+++ b/src/ringct/multiexp.cc
@@ -447,7 +447,6 @@ rct::key straus(const std::vector<MultiexpData> &data, const std::shared_ptr<str
{
CHECK_AND_ASSERT_THROW_MES(cache == NULL || cache->size >= data.size(), "Cache is too small");
MULTIEXP_PERF(PERF_TIMER_UNIT(straus, 1000000));
- bool HiGi = cache != NULL;
STEP = STEP ? STEP : 192;
MULTIEXP_PERF(PERF_TIMER_START_UNIT(setup, 1000000));
diff --git a/src/ringct/rctTypes.cpp b/src/ringct/rctTypes.cpp
index f01e683cb..2c4e5fc3b 100644
--- a/src/ringct/rctTypes.cpp
+++ b/src/ringct/rctTypes.cpp
@@ -190,7 +190,6 @@ namespace rct {
int byte, i, j;
for (j = 0; j < 8; j++) {
byte = 0;
- i = 8 * j;
for (i = 7; i > -1; i--) {
byte = byte * 2 + amountb2[8 * j + i];
}
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index e5413f1dc..f8729b872 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -252,7 +252,7 @@ namespace rct {
{
FIELD(type)
if (type == RCTTypeNull)
- return true;
+ return ar.stream().good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
return false;
VARINT_FIELD(txnFee)
@@ -312,7 +312,7 @@ namespace rct {
ar.delimit_array();
}
ar.end_array();
- return true;
+ return ar.stream().good();
}
};
struct rctSigPrunable {
@@ -325,7 +325,7 @@ namespace rct {
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
{
if (type == RCTTypeNull)
- return true;
+ return ar.stream().good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
return false;
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2)
@@ -429,7 +429,7 @@ namespace rct {
}
ar.end_array();
}
- return true;
+ return ar.stream().good();
}
};
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 5777370fc..f41ba6c37 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -59,6 +59,8 @@ using namespace epee;
#define MAX_RESTRICTED_FAKE_OUTS_COUNT 40
#define MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT 5000
+#define OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION (3 * 86400) // 3 days max, the wallet requests 1.8 days
+
namespace
{
void add_reason(std::string &reasons, const char *reason)
@@ -90,15 +92,9 @@ namespace cryptonote
command_line::add_arg(desc, arg_rpc_bind_port);
command_line::add_arg(desc, arg_rpc_restricted_bind_port);
command_line::add_arg(desc, arg_restricted_rpc);
- command_line::add_arg(desc, arg_rpc_ssl);
- command_line::add_arg(desc, arg_rpc_ssl_private_key);
- command_line::add_arg(desc, arg_rpc_ssl_certificate);
- command_line::add_arg(desc, arg_rpc_ssl_ca_certificates);
- command_line::add_arg(desc, arg_rpc_ssl_allowed_fingerprints);
- command_line::add_arg(desc, arg_rpc_ssl_allow_any_cert);
command_line::add_arg(desc, arg_bootstrap_daemon_address);
command_line::add_arg(desc, arg_bootstrap_daemon_login);
- cryptonote::rpc_args::init_options(desc);
+ cryptonote::rpc_args::init_options(desc, true);
}
//------------------------------------------------------------------------------------------------------------------------------
core_rpc_server::core_rpc_server(
@@ -118,7 +114,7 @@ namespace cryptonote
m_restricted = restricted;
m_net_server.set_threads_prefix("RPC");
- auto rpc_config = cryptonote::rpc_args::process(vm);
+ auto rpc_config = cryptonote::rpc_args::process(vm, true);
if (!rpc_config)
return false;
@@ -151,46 +147,9 @@ namespace cryptonote
if (rpc_config->login)
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
- epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect;
- if (command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert))
- ssl_options.verification = epee::net_utils::ssl_verification_t::none;
- else
- {
- std::string ssl_ca_path = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
- const std::vector<std::string> ssl_allowed_fingerprint_strings = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
- std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ ssl_allowed_fingerprint_strings.size() };
- std::transform(ssl_allowed_fingerprint_strings.begin(), ssl_allowed_fingerprint_strings.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
- for (const auto &fpr: ssl_allowed_fingerprints)
- {
- if (fpr.size() != SSL_FINGERPRINT_SIZE)
- {
- MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long.");
- return false;
- }
- }
-
- if (!ssl_ca_path.empty() || !ssl_allowed_fingerprints.empty())
- ssl_options = epee::net_utils::ssl_options_t{std::move(ssl_allowed_fingerprints), std::move(ssl_ca_path)};
- }
-
- ssl_options.auth = epee::net_utils::ssl_authentication_t{
- command_line::get_arg(vm, arg_rpc_ssl_private_key), command_line::get_arg(vm, arg_rpc_ssl_certificate)
- };
-
- // user specified CA file or fingeprints implies enabled SSL by default
- if (ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
- {
- const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl);
- if (!epee::net_utils::ssl_support_from_string(ssl_options.support, ssl))
- {
- MFATAL("Invalid RPC SSL support: " << ssl);
- return false;
- }
- }
-
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
- rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(ssl_options)
+ rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -861,6 +820,7 @@ namespace cryptonote
res.sanity_check_failed = true;
return true;
}
+ res.sanity_check_failed = false;
cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
@@ -948,16 +908,13 @@ namespace cryptonote
return true;
}
- boost::thread::attributes attrs;
- attrs.set_stack_size(THREAD_STACK_SIZE);
-
cryptonote::miner &miner= m_core.get_miner();
if (miner.is_mining())
{
res.status = "Already mining";
return true;
}
- if(!miner.start(info.address, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
+ if(!miner.start(info.address, static_cast<size_t>(req.threads_count), req.do_background_mining, req.ignore_battery))
{
res.status = "Failed, mining not started";
LOG_PRINT_L0(res.status);
@@ -1519,7 +1476,7 @@ namespace cryptonote
ok = ok && getheight_res.status == CORE_RPC_STATUS_OK;
m_should_use_bootstrap_daemon = ok && top_height + 10 < getheight_res.height;
- MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << getheight_res.height << ")");
+ MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << (ok ? getheight_res.height : 0) << ")");
}
if (!m_should_use_bootstrap_daemon)
return false;
@@ -1815,20 +1772,60 @@ namespace cryptonote
PERF_TIMER(on_get_bans);
auto now = time(nullptr);
- std::map<std::string, time_t> blocked_hosts = m_p2p.get_blocked_hosts();
- for (std::map<std::string, time_t>::const_iterator i = blocked_hosts.begin(); i != blocked_hosts.end(); ++i)
+ std::map<epee::net_utils::network_address, time_t> blocked_hosts = m_p2p.get_blocked_hosts();
+ for (std::map<epee::net_utils::network_address, time_t>::const_iterator i = blocked_hosts.begin(); i != blocked_hosts.end(); ++i)
{
if (i->second > now) {
COMMAND_RPC_GETBANS::ban b;
- b.host = i->first;
+ b.host = i->first.host_str();
b.ip = 0;
uint32_t ip;
- if (epee::string_tools::get_ip_int32_from_string(ip, i->first))
+ if (epee::string_tools::get_ip_int32_from_string(ip, b.host))
b.ip = ip;
b.seconds = i->second - now;
res.bans.push_back(b);
}
}
+ std::map<epee::net_utils::ipv4_network_subnet, time_t> blocked_subnets = m_p2p.get_blocked_subnets();
+ for (std::map<epee::net_utils::ipv4_network_subnet, time_t>::const_iterator i = blocked_subnets.begin(); i != blocked_subnets.end(); ++i)
+ {
+ if (i->second > now) {
+ COMMAND_RPC_GETBANS::ban b;
+ b.host = i->first.host_str();
+ b.ip = 0;
+ b.seconds = i->second - now;
+ res.bans.push_back(b);
+ }
+ }
+
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_banned(const COMMAND_RPC_BANNED::request& req, COMMAND_RPC_BANNED::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx)
+ {
+ PERF_TIMER(on_banned);
+
+ auto na_parsed = net::get_network_address(req.address, 0);
+ if (!na_parsed)
+ {
+ error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ error_resp.message = "Unsupported host type";
+ return false;
+ }
+ epee::net_utils::network_address na = std::move(*na_parsed);
+
+ time_t seconds;
+ if (m_p2p.is_host_blocked(na, &seconds))
+ {
+ res.banned = true;
+ res.seconds = seconds;
+ }
+ else
+ {
+ res.banned = false;
+ res.seconds = 0;
+ }
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -1841,13 +1838,29 @@ namespace cryptonote
for (auto i = req.bans.begin(); i != req.bans.end(); ++i)
{
epee::net_utils::network_address na;
+
+ // try subnet first
+ if (!i->host.empty())
+ {
+ auto ns_parsed = net::get_ipv4_subnet_address(i->host);
+ if (ns_parsed)
+ {
+ if (i->ban)
+ m_p2p.block_subnet(*ns_parsed, i->seconds);
+ else
+ m_p2p.unblock_subnet(*ns_parsed);
+ continue;
+ }
+ }
+
+ // then host
if (!i->host.empty())
{
auto na_parsed = net::get_network_address(i->host, 0);
if (!na_parsed)
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
- error_resp.message = "Unsupported host type";
+ error_resp.message = "Unsupported host/subnet type";
return false;
}
na = std::move(*na_parsed);
@@ -1928,6 +1941,13 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC, "get_output_histogram", req, res, r))
return r;
+ const bool restricted = m_restricted && ctx;
+ if (restricted && req.recent_cutoff > 0 && req.recent_cutoff < (uint64_t)time(NULL) - OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION)
+ {
+ res.status = "Recent cutoff is too old";
+ return true;
+ }
+
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
try
{
@@ -2075,7 +2095,9 @@ namespace cryptonote
bool core_rpc_server::on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res, const connection_context *ctx)
{
PERF_TIMER(on_out_peers);
- m_p2p.change_max_out_public_peers(req.out_peers);
+ if (req.set)
+ m_p2p.change_max_out_public_peers(req.out_peers);
+ res.out_peers = m_p2p.get_max_out_public_peers();
res.status = CORE_RPC_STATUS_OK;
return true;
}
@@ -2083,27 +2105,13 @@ namespace cryptonote
bool core_rpc_server::on_in_peers(const COMMAND_RPC_IN_PEERS::request& req, COMMAND_RPC_IN_PEERS::response& res, const connection_context *ctx)
{
PERF_TIMER(on_in_peers);
- m_p2p.change_max_in_public_peers(req.in_peers);
+ if (req.set)
+ m_p2p.change_max_in_public_peers(req.in_peers);
+ res.in_peers = m_p2p.get_max_in_public_peers();
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res, const connection_context *ctx)
- {
- PERF_TIMER(on_start_save_graph);
- m_p2p.set_save_graph(true);
- res.status = CORE_RPC_STATUS_OK;
- return true;
- }
- //------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res, const connection_context *ctx)
- {
- PERF_TIMER(on_stop_save_graph);
- m_p2p.set_save_graph(false);
- res.status = CORE_RPC_STATUS_OK;
- return true;
- }
- //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_update(const COMMAND_RPC_UPDATE::request& req, COMMAND_RPC_UPDATE::response& res, const connection_context *ctx)
{
PERF_TIMER(on_update);
@@ -2439,40 +2447,6 @@ namespace cryptonote
, false
};
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl = {
- "rpc-ssl"
- , "Enable SSL on RPC connections: enabled|disabled|autodetect"
- , "autodetect"
- };
-
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_private_key = {
- "rpc-ssl-private-key"
- , "Path to a PEM format private key"
- , ""
- };
-
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_certificate = {
- "rpc-ssl-certificate"
- , "Path to a PEM format certificate"
- , ""
- };
-
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_ca_certificates = {
- "rpc-ssl-ca-certificates"
- , "Path to file containing concatenated PEM format certificate(s) to replace system CA(s)."
- };
-
- const command_line::arg_descriptor<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_fingerprints = {
- "rpc-ssl-allowed-fingerprints"
- , "List of certificate fingerprints to allow"
- };
-
- const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_ssl_allow_any_cert = {
- "rpc-ssl-allow-any-cert"
- , "Allow any peer certificate"
- , false
- };
-
const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_address = {
"bootstrap-daemon-address"
, "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced"
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index e4683bbe2..7c9bb6dc4 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -123,8 +123,6 @@ namespace cryptonote
MAP_URI_AUTO_JON2_IF("/set_limit", on_set_limit, COMMAND_RPC_SET_LIMIT, !m_restricted)
MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted)
MAP_URI_AUTO_JON2_IF("/in_peers", on_in_peers, COMMAND_RPC_IN_PEERS, !m_restricted)
- MAP_URI_AUTO_JON2_IF("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH, !m_restricted)
- MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted)
MAP_URI_AUTO_JON2("/get_outs", on_get_outs, COMMAND_RPC_GET_OUTPUTS)
MAP_URI_AUTO_JON2_IF("/update", on_update, COMMAND_RPC_UPDATE, !m_restricted)
MAP_URI_AUTO_BIN2("/get_output_distribution.bin", on_get_output_distribution_bin, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION)
@@ -154,6 +152,7 @@ namespace cryptonote
MAP_JON_RPC_WE("hard_fork_info", on_hard_fork_info, COMMAND_RPC_HARD_FORK_INFO)
MAP_JON_RPC_WE_IF("set_bans", on_set_bans, COMMAND_RPC_SETBANS, !m_restricted)
MAP_JON_RPC_WE_IF("get_bans", on_get_bans, COMMAND_RPC_GETBANS, !m_restricted)
+ MAP_JON_RPC_WE_IF("banned", on_banned, COMMAND_RPC_BANNED, !m_restricted)
MAP_JON_RPC_WE_IF("flush_txpool", on_flush_txpool, COMMAND_RPC_FLUSH_TRANSACTION_POOL, !m_restricted)
MAP_JON_RPC_WE("get_output_histogram", on_get_output_histogram, COMMAND_RPC_GET_OUTPUT_HISTOGRAM)
MAP_JON_RPC_WE("get_version", on_get_version, COMMAND_RPC_GET_VERSION)
@@ -198,8 +197,6 @@ namespace cryptonote
bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res, const connection_context *ctx = NULL);
bool on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res, const connection_context *ctx = NULL);
bool on_in_peers(const COMMAND_RPC_IN_PEERS::request& req, COMMAND_RPC_IN_PEERS::response& res, const connection_context *ctx = NULL);
- bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res, const connection_context *ctx = NULL);
- bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res, const connection_context *ctx = NULL);
bool on_update(const COMMAND_RPC_UPDATE::request& req, COMMAND_RPC_UPDATE::response& res, const connection_context *ctx = NULL);
bool on_get_output_distribution_bin(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, const connection_context *ctx = NULL);
bool on_pop_blocks(const COMMAND_RPC_POP_BLOCKS::request& req, COMMAND_RPC_POP_BLOCKS::response& res, const connection_context *ctx = NULL);
@@ -220,6 +217,7 @@ namespace cryptonote
bool on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request& req, COMMAND_RPC_HARD_FORK_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_set_bans(const COMMAND_RPC_SETBANS::request& req, COMMAND_RPC_SETBANS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
+ bool on_banned(const COMMAND_RPC_BANNED::request& req, COMMAND_RPC_BANNED::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_flush_txpool(const COMMAND_RPC_FLUSH_TRANSACTION_POOL::request& req, COMMAND_RPC_FLUSH_TRANSACTION_POOL::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
bool on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL);
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index cfe4bbf23..53c975392 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -84,7 +84,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 2
-#define CORE_RPC_VERSION_MINOR 6
+#define CORE_RPC_VERSION_MINOR 7
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -1682,8 +1682,10 @@ namespace cryptonote
{
struct request_t
{
- uint64_t out_peers;
+ bool set;
+ uint32_t out_peers;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_OPT(set, true)
KV_SERIALIZE(out_peers)
END_KV_SERIALIZE_MAP()
};
@@ -1691,9 +1693,11 @@ namespace cryptonote
struct response_t
{
+ uint32_t out_peers;
std::string status;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(out_peers)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
@@ -1704,8 +1708,10 @@ namespace cryptonote
{
struct request_t
{
- uint64_t in_peers;
+ bool set;
+ uint32_t in_peers;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_OPT(set, true)
KV_SERIALIZE(in_peers)
END_KV_SERIALIZE_MAP()
};
@@ -1713,55 +1719,17 @@ namespace cryptonote
struct response_t
{
+ uint32_t in_peers;
std::string status;
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(in_peers)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
- struct COMMAND_RPC_START_SAVE_GRAPH
- {
- struct request_t
- {
- BEGIN_KV_SERIALIZE_MAP()
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<request_t> request;
-
- struct response_t
- {
- std::string status;
-
- BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<response_t> response;
- };
-
- struct COMMAND_RPC_STOP_SAVE_GRAPH
- {
- struct request_t
- {
- BEGIN_KV_SERIALIZE_MAP()
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<request_t> request;
-
- struct response_t
- {
- std::string status;
-
- BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(status)
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<response_t> response;
- };
-
struct COMMAND_RPC_HARD_FORK_INFO
{
struct request_t
@@ -1876,6 +1844,33 @@ namespace cryptonote
typedef epee::misc_utils::struct_init<response_t> response;
};
+ struct COMMAND_RPC_BANNED
+ {
+ struct request_t
+ {
+ std::string address;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(address)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t
+ {
+ std::string status;
+ bool banned;
+ uint32_t seconds;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(banned)
+ KV_SERIALIZE(seconds)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
struct COMMAND_RPC_FLUSH_TRANSACTION_POOL
{
struct request_t
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index 5c214581c..612b2cab6 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -408,10 +408,7 @@ namespace rpc
return;
}
- boost::thread::attributes attrs;
- attrs.set_stack_size(THREAD_STACK_SIZE);
-
- if(!m_core.get_miner().start(info.address, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
+ if(!m_core.get_miner().start(info.address, static_cast<size_t>(req.threads_count), req.do_background_mining, req.ignore_battery))
{
res.error_details = "Failed, mining not started";
LOG_PRINT_L0(res.error_details);
diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp
index f2be94f51..4479bd1f1 100644
--- a/src/rpc/rpc_args.cpp
+++ b/src/rpc/rpc_args.cpp
@@ -33,28 +33,95 @@
#include <boost/bind.hpp>
#include "common/command_line.h"
#include "common/i18n.h"
+#include "hex.h"
namespace cryptonote
{
+ namespace
+ {
+ boost::optional<epee::net_utils::ssl_options_t> do_process_ssl(const boost::program_options::variables_map& vm, const rpc_args::descriptors& arg, const bool any_cert_option)
+ {
+ bool ssl_required = false;
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ if (any_cert_option && command_line::get_arg(vm, arg.rpc_ssl_allow_any_cert))
+ ssl_options.verification = epee::net_utils::ssl_verification_t::none;
+ else
+ {
+ std::string ssl_ca_file = command_line::get_arg(vm, arg.rpc_ssl_ca_certificates);
+ const std::vector<std::string> ssl_allowed_fingerprints = command_line::get_arg(vm, arg.rpc_ssl_allowed_fingerprints);
+
+ std::vector<std::vector<uint8_t>> allowed_fingerprints{ ssl_allowed_fingerprints.size() };
+ std::transform(ssl_allowed_fingerprints.begin(), ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
+ for (const auto &fpr: allowed_fingerprints)
+ {
+ if (fpr.size() != SSL_FINGERPRINT_SIZE)
+ {
+ MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long.");
+ return boost::none;
+ }
+ }
+
+ if (!allowed_fingerprints.empty() || !ssl_ca_file.empty())
+ {
+ ssl_required = true;
+ ssl_options = epee::net_utils::ssl_options_t{
+ std::move(allowed_fingerprints), std::move(ssl_ca_file)
+ };
+
+ if (command_line::get_arg(vm, arg.rpc_ssl_allow_chained))
+ ssl_options.verification = epee::net_utils::ssl_verification_t::user_ca;
+ }
+ }
+
+ // user specified CA file or fingeprints implies enabled SSL by default
+ if (!ssl_required && !epee::net_utils::ssl_support_from_string(ssl_options.support, command_line::get_arg(vm, arg.rpc_ssl)))
+ {
+ MERROR("Invalid argument for " << std::string(arg.rpc_ssl.name));
+ return boost::none;
+ }
+
+ ssl_options.auth = epee::net_utils::ssl_authentication_t{
+ command_line::get_arg(vm, arg.rpc_ssl_private_key), command_line::get_arg(vm, arg.rpc_ssl_certificate)
+ };
+
+ return {std::move(ssl_options)};
+ }
+ } // anonymous
+
rpc_args::descriptors::descriptors()
: rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"})
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
, confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")})
, rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""})
+ , rpc_ssl({"rpc-ssl", rpc_args::tr("Enable SSL on RPC connections: enabled|disabled|autodetect"), "autodetect"})
+ , rpc_ssl_private_key({"rpc-ssl-private-key", rpc_args::tr("Path to a PEM format private key"), ""})
+ , rpc_ssl_certificate({"rpc-ssl-certificate", rpc_args::tr("Path to a PEM format certificate"), ""})
+ , rpc_ssl_ca_certificates({"rpc-ssl-ca-certificates", rpc_args::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s)."), ""})
+ , rpc_ssl_allowed_fingerprints({"rpc-ssl-allowed-fingerprints", rpc_args::tr("List of certificate fingerprints to allow")})
+ , rpc_ssl_allow_chained({"rpc-ssl-allow-chained", rpc_args::tr("Allow user (via --rpc-ssl-certificates) chain certificates"), false})
+ , rpc_ssl_allow_any_cert({"rpc-ssl-allow-any-cert", rpc_args::tr("Allow any peer certificate"), false})
{}
const char* rpc_args::tr(const char* str) { return i18n_translate(str, "cryptonote::rpc_args"); }
- void rpc_args::init_options(boost::program_options::options_description& desc)
+ void rpc_args::init_options(boost::program_options::options_description& desc, const bool any_cert_option)
{
const descriptors arg{};
command_line::add_arg(desc, arg.rpc_bind_ip);
command_line::add_arg(desc, arg.rpc_login);
command_line::add_arg(desc, arg.confirm_external_bind);
command_line::add_arg(desc, arg.rpc_access_control_origins);
+ command_line::add_arg(desc, arg.rpc_ssl);
+ command_line::add_arg(desc, arg.rpc_ssl_private_key);
+ command_line::add_arg(desc, arg.rpc_ssl_certificate);
+ command_line::add_arg(desc, arg.rpc_ssl_ca_certificates);
+ command_line::add_arg(desc, arg.rpc_ssl_allowed_fingerprints);
+ command_line::add_arg(desc, arg.rpc_ssl_allow_chained);
+ if (any_cert_option)
+ command_line::add_arg(desc, arg.rpc_ssl_allow_any_cert);
}
- boost::optional<rpc_args> rpc_args::process(const boost::program_options::variables_map& vm)
+ boost::optional<rpc_args> rpc_args::process(const boost::program_options::variables_map& vm, const bool any_cert_option)
{
const descriptors arg{};
rpc_args config{};
@@ -118,6 +185,17 @@ namespace cryptonote
config.access_control_origins = std::move(access_control_origins);
}
+ auto ssl_options = do_process_ssl(vm, arg, any_cert_option);
+ if (!ssl_options)
+ return boost::none;
+ config.ssl_options = std::move(*ssl_options);
+
return {std::move(config)};
}
+
+ boost::optional<epee::net_utils::ssl_options_t> rpc_args::process_ssl(const boost::program_options::variables_map& vm, const bool any_cert_option)
+ {
+ const descriptors arg{};
+ return do_process_ssl(vm, arg, any_cert_option);
+ }
}
diff --git a/src/rpc/rpc_args.h b/src/rpc/rpc_args.h
index 216ba3712..619f02b42 100644
--- a/src/rpc/rpc_args.h
+++ b/src/rpc/rpc_args.h
@@ -35,6 +35,7 @@
#include "common/command_line.h"
#include "common/password.h"
+#include "net/net_ssl.h"
namespace cryptonote
{
@@ -54,16 +55,29 @@ namespace cryptonote
const command_line::arg_descriptor<std::string> rpc_login;
const command_line::arg_descriptor<bool> confirm_external_bind;
const command_line::arg_descriptor<std::string> rpc_access_control_origins;
+ const command_line::arg_descriptor<std::string> rpc_ssl;
+ const command_line::arg_descriptor<std::string> rpc_ssl_private_key;
+ const command_line::arg_descriptor<std::string> rpc_ssl_certificate;
+ const command_line::arg_descriptor<std::string> rpc_ssl_ca_certificates;
+ const command_line::arg_descriptor<std::vector<std::string>> rpc_ssl_allowed_fingerprints;
+ const command_line::arg_descriptor<bool> rpc_ssl_allow_chained;
+ const command_line::arg_descriptor<bool> rpc_ssl_allow_any_cert;
};
+ // `allow_any_cert` bool toggles `--rpc-ssl-allow-any-cert` configuration
+
static const char* tr(const char* str);
- static void init_options(boost::program_options::options_description& desc);
+ static void init_options(boost::program_options::options_description& desc, const bool any_cert_option = false);
//! \return Arguments specified by user, or `boost::none` if error
- static boost::optional<rpc_args> process(const boost::program_options::variables_map& vm);
+ static boost::optional<rpc_args> process(const boost::program_options::variables_map& vm, const bool any_cert_option = false);
+
+ //! \return SSL arguments specified by user, or `boost::none` if error
+ static boost::optional<epee::net_utils::ssl_options_t> process_ssl(const boost::program_options::variables_map& vm, const bool any_cert_option = false);
std::string bind_ip;
std::vector<std::string> access_control_origins;
boost::optional<tools::login> login; // currently `boost::none` if unspecified by user
+ epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
};
}
diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h
index a0e4eff9d..9f60cf311 100644
--- a/src/serialization/binary_archive.h
+++ b/src/serialization/binary_archive.h
@@ -146,7 +146,8 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false>
void serialize_uvarint(T &v)
{
typedef std::istreambuf_iterator<char> it;
- tools::read_varint(it(stream_), it(), v); // XXX handle failure
+ if (tools::read_varint(it(stream_), it(), v) < 0)
+ stream_.setstate(std::ios_base::failbit);
}
void begin_array(size_t &s)
diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h
index 007bf265f..553e9951f 100644
--- a/src/serialization/serialization.h
+++ b/src/serialization/serialization.h
@@ -212,7 +212,7 @@ inline bool do_serialize(Archive &ar, bool &v)
* \brief self-explanatory
*/
#define END_SERIALIZE() \
- return true; \
+ return ar.stream().good(); \
}
/*! \macro VALUE(f)
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 43323be2c..f95da1058 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -92,6 +92,8 @@ typedef cryptonote::simple_wallet sw;
#define MIN_RING_SIZE 11 // Used to inform user about min ring size -- does not track actual protocol
+#define OLD_AGE_WARN_THRESHOLD (30 * 86400 / DIFFICULTY_TARGET_V2) // 30 days
+
#define LOCK_IDLE_SCOPE() \
bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \
m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \
@@ -5608,6 +5610,43 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::prompt_if_old(const std::vector<tools::wallet2::pending_tx> &ptx_vector)
+{
+ // count the number of old outputs
+ std::string err;
+ uint64_t bc_height = get_daemon_blockchain_height(err);
+ if (!err.empty())
+ return true;
+
+ int max_n_old = 0;
+ for (const auto &ptx: ptx_vector)
+ {
+ int n_old = 0;
+ for (const auto i: ptx.selected_transfers)
+ {
+ const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(i);
+ uint64_t age = bc_height - td.m_block_height;
+ if (age > OLD_AGE_WARN_THRESHOLD)
+ ++n_old;
+ }
+ max_n_old = std::max(max_n_old, n_old);
+ }
+ if (max_n_old > 1)
+ {
+ std::stringstream prompt;
+ prompt << tr("Transaction spends more than one very old output. Privacy would be better if they were sent separately.");
+ prompt << ENDL << tr("Spend them now anyway?");
+ std::string accepted = input_line(prompt.str(), true);
+ if (std::cin.eof())
+ return false;
+ if (!command_line::is_yes(accepted))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::string> &args_, bool called_by_mms)
{
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
@@ -5909,6 +5948,12 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
}
+ if (!prompt_if_old(ptx_vector))
+ {
+ fail_msg_writer() << tr("transaction cancelled.");
+ return false;
+ }
+
// if more than one tx necessary, prompt user to confirm
if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1)
{
@@ -6092,7 +6137,8 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
{
- return sweep_main(0, true, args_);
+ sweep_main(0, true, args_);
+ return true;
}
//----------------------------------------------------------------------------------------------------
@@ -6412,6 +6458,12 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
return true;
}
+ if (!prompt_if_old(ptx_vector))
+ {
+ fail_msg_writer() << tr("transaction cancelled.");
+ return false;
+ }
+
// give user total and fee, and prompt to confirm
uint64_t total_fee = 0, total_sent = 0;
for (size_t n = 0; n < ptx_vector.size(); ++n)
@@ -6758,7 +6810,8 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
{
- return sweep_main(0, false, args_);
+ sweep_main(0, false, args_);
+ return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
@@ -6774,7 +6827,8 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
fail_msg_writer() << tr("invalid amount threshold");
return true;
}
- return sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
+ sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
+ return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::donate(const std::vector<std::string> &args_)
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 33b18612c..4bf7fa334 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -261,6 +261,7 @@ namespace cryptonote
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
std::pair<std::string, std::string> show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height = std::numeric_limits<uint64_t>::max()) const;
bool freeze_thaw(const std::vector<std::string>& args, bool freeze);
+ bool prompt_if_old(const std::vector<tools::wallet2::pending_tx> &ptx_vector);
struct transfer_view
{
diff --git a/src/version.cpp.in b/src/version.cpp.in
index 8aaa41b19..28ce38df7 100644
--- a/src/version.cpp.in
+++ b/src/version.cpp.in
@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
-#define DEF_MONERO_VERSION "0.14.1.0"
+#define DEF_MONERO_VERSION "0.14.1.2"
#define DEF_MONERO_RELEASE_NAME "Boron Butterfly"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index a85e31474..03db385a4 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1697,6 +1697,17 @@ void WalletImpl::setDefaultMixin(uint32_t arg)
m_wallet->default_mixin(arg);
}
+bool WalletImpl::setCacheAttribute(const std::string &key, const std::string &val)
+{
+ m_wallet->set_attribute(key, val);
+ return true;
+}
+
+std::string WalletImpl::getCacheAttribute(const std::string &key) const
+{
+ return m_wallet->get_attribute(key);
+}
+
bool WalletImpl::setUserNote(const std::string &txid, const std::string &note)
{
cryptonote::blobdata txid_data;
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 57265470c..a367a1917 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -168,6 +168,10 @@ public:
virtual void setListener(WalletListener * l) override;
virtual uint32_t defaultMixin() const override;
virtual void setDefaultMixin(uint32_t arg) override;
+
+ virtual bool setCacheAttribute(const std::string &key, const std::string &val) override;
+ virtual std::string getCacheAttribute(const std::string &key) const override;
+
virtual bool setUserNote(const std::string &txid, const std::string &note) override;
virtual std::string getUserNote(const std::string &txid) const override;
virtual std::string getTxKey(const std::string &txid) const override;
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index 7193eddd7..9e556cb2f 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -891,6 +891,19 @@ struct Wallet
virtual void setDefaultMixin(uint32_t arg) = 0;
/*!
+ * \brief setCacheAttribute - attach an arbitrary string to a wallet cache attribute
+ * \param key - the key
+ * \param val - the value
+ * \return true if successful, false otherwise
+ */
+ virtual bool setCacheAttribute(const std::string &key, const std::string &val) = 0;
+ /*!
+ * \brief getCacheAttribute - return an arbitrary string attached to a wallet cache attribute
+ * \param key - the key
+ * \return the attached string, or empty string if there is none
+ */
+ virtual std::string getCacheAttribute(const std::string &key) const = 0;
+ /*!
* \brief setUserNote - attach an arbitrary string note to a txid
* \param txid - the transaction id to attach the note to
* \param note - the note
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index ef2ed2015..d589dcc75 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -227,9 +227,6 @@ std::string WalletManagerImpl::errorString() const
void WalletManagerImpl::setDaemonAddress(const std::string &address)
{
- m_daemonAddress = address;
- if(m_http_client.is_connected())
- m_http_client.disconnect();
m_http_client.set_server(address, boost::none);
}
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 235f96e17..537fc5ba6 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -95,7 +95,6 @@ public:
private:
WalletManagerImpl() {}
friend struct WalletManagerFactory;
- std::string m_daemonAddress;
epee::net_utils::http::http_simple_client m_http_client;
std::string m_errorString;
};
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 8462c659d..e352917dd 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -399,8 +399,11 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
{
const boost::string_ref real_daemon = boost::string_ref{daemon_address}.substr(0, daemon_address.rfind(':'));
+ /* If SSL or proxy is enabled, then a specific cert, CA or fingerprint must
+ be specified. This is specific to the wallet. */
const bool verification_required =
- ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy;
+ ssl_options.verification != epee::net_utils::ssl_verification_t::none &&
+ (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy);
THROW_WALLET_EXCEPTION_IF(
verification_required && !ssl_options.has_strong_verification(real_daemon),
@@ -6928,7 +6931,7 @@ uint64_t wallet2::get_base_fee() const
else
return m_light_wallet_per_kb_fee;
}
- bool use_dyn_fee = use_fork_rules(HF_VERSION_DYNAMIC_FEE, -720 * 1);
+ bool use_dyn_fee = use_fork_rules(HF_VERSION_DYNAMIC_FEE, -30 * 1);
if (!use_dyn_fee)
return FEE_PER_KB;
@@ -6959,7 +6962,7 @@ int wallet2::get_fee_algorithm() const
return 3;
if (use_fork_rules(5, 0))
return 2;
- if (use_fork_rules(3, -720 * 14))
+ if (use_fork_rules(3, -30 * 14))
return 1;
return 0;
}
@@ -7723,7 +7726,6 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
uint64_t num_found = 0;
// if we have a known ring, use it
- bool existing_ring_found = false;
if (td.m_key_image_known && !td.m_key_image_partial)
{
std::vector<uint64_t> ring;
@@ -7735,7 +7737,6 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
std::to_string(ring.size()) + ", it cannot be spent now with ring size " +
std::to_string(fake_outputs_count + 1) + " as it is smaller: use a higher ring size");
bool own_found = false;
- existing_ring_found = true;
for (const auto &out: ring)
{
MINFO("Ring has output " << out);
@@ -7981,7 +7982,6 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
outs.back().push_back(std::make_tuple(td.m_global_output_index, boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key, mask));
// then pick outs from an existing ring, if any
- bool existing_ring_found = false;
if (td.m_key_image_known && !td.m_key_image_partial)
{
std::vector<uint64_t> ring;
@@ -11414,12 +11414,13 @@ void wallet2::set_attribute(const std::string &key, const std::string &value)
m_attributes[key] = value;
}
-std::string wallet2::get_attribute(const std::string &key) const
+bool wallet2::get_attribute(const std::string &key, std::string &value) const
{
std::unordered_map<std::string, std::string>::const_iterator i = m_attributes.find(key);
if (i == m_attributes.end())
- return std::string();
- return i->second;
+ return false;
+ value = i->second;
+ return true;
}
void wallet2::set_description(const std::string &description)
@@ -11429,7 +11430,10 @@ void wallet2::set_description(const std::string &description)
std::string wallet2::get_description() const
{
- return get_attribute(ATTRIBUTE_DESCRIPTION);
+ std::string s;
+ if (get_attribute(ATTRIBUTE_DESCRIPTION, s))
+ return s;
+ return "";
}
const std::pair<std::map<std::string, std::string>, std::vector<std::string>>& wallet2::get_account_tags()
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 1ea10d333..43fa8cb6d 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1249,7 +1249,7 @@ private:
*/
const char* const ATTRIBUTE_DESCRIPTION = "wallet2.description";
void set_attribute(const std::string &key, const std::string &value);
- std::string get_attribute(const std::string &key) const;
+ bool get_attribute(const std::string &key, std::string &value) const;
crypto::public_key get_multisig_signer_public_key(const crypto::secret_key &spend_skey) const;
crypto::public_key get_multisig_signer_public_key() const;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 16a2b3808..9d3605d11 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -66,11 +66,6 @@ namespace
const command_line::arg_descriptor<bool> arg_restricted = {"restricted-rpc", "Restricts to view-only commands", false};
const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"};
const command_line::arg_descriptor<bool> arg_prompt_for_password = {"prompt-for-password", "Prompts for password when not provided", false};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_ca_certificates = {"rpc-ssl-ca-certificates", tools::wallet2::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s).")};
- const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints = {"rpc-ssl-allowed-fingerprints", tools::wallet2::tr("List of certificate fingerprints to allow")};
constexpr const char default_rpc_username[] = "monero";
@@ -244,45 +239,6 @@ namespace tools
assert(bool(http_login));
} // end auth enabled
- auto rpc_ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
- auto rpc_ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
- auto rpc_ssl_ca_file = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
- auto rpc_ssl_allowed_fingerprints = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
- auto rpc_ssl = command_line::get_arg(vm, arg_rpc_ssl);
- epee::net_utils::ssl_options_t rpc_ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
-
- if (!rpc_ssl_ca_file.empty() || !rpc_ssl_allowed_fingerprints.empty())
- {
- std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
- std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
- for (const auto &fpr: allowed_fingerprints)
- {
- if (fpr.size() != SSL_FINGERPRINT_SIZE)
- {
- MERROR("SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long.");
- return false;
- }
- }
-
- rpc_ssl_options = epee::net_utils::ssl_options_t{
- std::move(allowed_fingerprints), std::move(rpc_ssl_ca_file)
- };
- }
-
- // user specified CA file or fingeprints implies enabled SSL by default
- if (rpc_ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
- {
- if (!epee::net_utils::ssl_support_from_string(rpc_ssl_options.support, rpc_ssl))
- {
- MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
- return false;
- }
- }
-
- rpc_ssl_options.auth = epee::net_utils::ssl_authentication_t{
- std::move(rpc_ssl_private_key), std::move(rpc_ssl_certificate)
- };
-
m_auto_refresh_period = DEFAULT_AUTO_REFRESH_PERIOD;
m_last_auto_refresh_time = boost::posix_time::min_date_time;
@@ -292,7 +248,7 @@ namespace tools
auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); };
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
- std::move(rpc_ssl_options)
+ std::move(rpc_config->ssl_options)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -1789,6 +1745,11 @@ namespace tools
else if (payment_id_str.size() == 2 * sizeof(payment_id8))
{
r = epee::string_tools::hex_to_pod(payment_id_str, payment_id8);
+ if (r)
+ {
+ memcpy(payment_id.data, payment_id8.data, 8);
+ memset(payment_id.data + 8, 0, 24);
+ }
}
else
{
@@ -1850,14 +1811,12 @@ namespace tools
wallet2::transfer_container transfers;
m_wallet->get_transfers(transfers);
- bool transfers_found = false;
for (const auto& td : transfers)
{
if (!filter || available != td.m_spent)
{
if (req.account_index != td.m_subaddr_index.major || (!req.subaddr_indices.empty() && req.subaddr_indices.count(td.m_subaddr_index.minor) == 0))
continue;
- transfers_found = true;
wallet_rpc::transfer_details rpc_transfers;
rpc_transfers.amount = td.amount();
rpc_transfers.spent = td.m_spent;
@@ -2143,7 +2102,12 @@ namespace tools
return false;
}
- res.value = m_wallet->get_attribute(req.key);
+ if (!m_wallet->get_attribute(req.key, res.value))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_ATTRIBUTE_NOT_FOUND;
+ er.message = "Attribute not found.";
+ return false;
+ }
return true;
}
bool wallet_rpc_server::on_get_tx_key(const wallet_rpc::COMMAND_RPC_GET_TX_KEY::request& req, wallet_rpc::COMMAND_RPC_GET_TX_KEY::response& res, epee::json_rpc::error& er, const connection_context *ctx)
@@ -4167,7 +4131,11 @@ namespace tools
std::move(req.ssl_private_key_path), std::move(req.ssl_certificate_path)
};
- if (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled && !ssl_options.has_strong_verification(boost::string_ref{}))
+ const bool verification_required =
+ ssl_options.verification != epee::net_utils::ssl_verification_t::none &&
+ ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+
+ if (verification_required && !ssl_options.has_strong_verification(boost::string_ref{}))
{
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
er.message = "SSL is enabled but no user certificate or fingerprints were provided";
@@ -4412,11 +4380,6 @@ int main(int argc, char** argv) {
command_line::add_arg(desc_params, arg_from_json);
command_line::add_arg(desc_params, arg_wallet_dir);
command_line::add_arg(desc_params, arg_prompt_for_password);
- command_line::add_arg(desc_params, arg_rpc_ssl);
- command_line::add_arg(desc_params, arg_rpc_ssl_private_key);
- command_line::add_arg(desc_params, arg_rpc_ssl_certificate);
- command_line::add_arg(desc_params, arg_rpc_ssl_ca_certificates);
- command_line::add_arg(desc_params, arg_rpc_ssl_allowed_fingerprints);
daemonizer::init_options(hidden_options, desc_params);
desc_params.add(hidden_options);
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 011d146d4..9434fbc3e 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -75,3 +75,4 @@
#define WALLET_RPC_ERROR_CODE_SIGN_UNSIGNED -42
#define WALLET_RPC_ERROR_CODE_NON_DETERMINISTIC -43
#define WALLET_RPC_ERROR_CODE_INVALID_LOG_LEVEL -44
+#define WALLET_RPC_ERROR_CODE_ATTRIBUTE_NOT_FOUND -45