From a74348e1155e6c18b0748795848f56669011cd9b Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 16 Mar 2016 10:24:48 +0000 Subject: Add destructor for readtxns Only if we created the readtxn. Was missing cleanups from exceptions before. --- src/blockchain_db/lmdb/db_lmdb.cpp | 27 ++++++++++++++++++--------- src/blockchain_db/lmdb/db_lmdb.h | 4 +++- 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index d2939bf96..9ae7b404b 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -228,17 +228,24 @@ mdb_threadinfo::~mdb_threadinfo() mdb_txn_abort(m_ti_rtxn); } -mdb_txn_safe::mdb_txn_safe() : m_txn(NULL) +mdb_txn_safe::mdb_txn_safe(const bool check) : m_txn(NULL), m_tinfo(NULL), m_check(check) { - while (creation_gate.test_and_set()); - num_active_txns++; - creation_gate.clear(); + if (check) + { + while (creation_gate.test_and_set()); + num_active_txns++; + creation_gate.clear(); + } } mdb_txn_safe::~mdb_txn_safe() { LOG_PRINT_L3("mdb_txn_safe: destructor"); - if (m_txn != nullptr) + if (m_tinfo != nullptr) + { + mdb_txn_reset(m_tinfo->m_ti_rtxn); + memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags)); + } else if (m_txn != nullptr) { if (m_batch_txn) // this is a batch txn and should have been handled before this point for safety { @@ -256,7 +263,8 @@ mdb_txn_safe::~mdb_txn_safe() } mdb_txn_abort(m_txn); } - num_active_txns--; + if (m_check) + num_active_txns--; } void mdb_txn_safe::commit(std::string message) @@ -1303,9 +1311,10 @@ void BlockchainLMDB::unlock() #define TXN_PREFIX_RDONLY() \ MDB_txn *m_txn; \ mdb_txn_cursors *m_cursors; \ - bool my_rtxn = block_rtxn_start(&m_txn, &m_cursors); -#define TXN_POSTFIX_RDONLY() \ - if (my_rtxn) block_rtxn_stop() + bool my_rtxn = block_rtxn_start(&m_txn, &m_cursors); \ + mdb_txn_safe auto_txn(my_rtxn); \ + if (my_rtxn) auto_txn.m_tinfo = m_tinfo.get() +#define TXN_POSTFIX_RDONLY() #define TXN_POSTFIX_SUCCESS() \ do { \ diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 718ee1058..a3f32ffaa 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -115,7 +115,7 @@ typedef struct mdb_threadinfo struct mdb_txn_safe { - mdb_txn_safe(); + mdb_txn_safe(const bool check=true); ~mdb_txn_safe(); void commit(std::string message = ""); @@ -142,8 +142,10 @@ struct mdb_txn_safe static void wait_no_active_txns(); static void allow_new_txns(); + mdb_threadinfo* m_tinfo; MDB_txn* m_txn; bool m_batch_txn = false; + bool m_check; static std::atomic num_active_txns; // could use a mutex here, but this should be sufficient. -- cgit v1.2.3 From e4c2e9e5e0d5169c44ae7ac7f1f1fd8ec3676523 Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Wed, 16 Mar 2016 21:59:21 +0200 Subject: baked-in block headers now go all the way up to 1 million. 1 MILLION --- src/blocks/checkpoints.dat | Bin 31824036 -> 32000004 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'src') diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat index a9085c2bc..8a6bed31a 100644 Binary files a/src/blocks/checkpoints.dat and b/src/blocks/checkpoints.dat differ -- cgit v1.2.3 From 435b6e4e32a46740270c67775a9c0c8fbcc1da1d Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Wed, 16 Mar 2016 22:00:50 +0200 Subject: bump the version --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/version.h.in b/src/version.h.in index 08e39c00c..073129810 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define MONERO_VERSION_TAG "@VERSIONTAG@" -#define MONERO_VERSION "0.9.1.0" +#define MONERO_VERSION "0.9.2.0" #define MONERO_RELEASE_NAME "Hydrogen Helix" #define MONERO_VERSION_FULL MONERO_VERSION "-" MONERO_VERSION_TAG -- cgit v1.2.3 From 9b3e43c3270877f905efc375ddd6f2cf7f64f460 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sat, 19 Mar 2016 12:57:47 +0000 Subject: Fix issue #706 --- src/cryptonote_core/blockchain.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index f540697dc..8b7f298ee 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2798,6 +2798,7 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor { const auto& pts = points.get_points(); + CRITICAL_REGION_LOCAL(m_blockchain_lock); m_db->batch_start(); for (const auto& pt : pts) { -- cgit v1.2.3 From db1b2db4d5fd6b4d441faa4bc7c7381e3d88a268 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sat, 19 Mar 2016 12:59:05 +0000 Subject: Reduce log noise --- src/blockchain_db/lmdb/db_lmdb.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 9ae7b404b..4e30548fc 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -240,6 +240,8 @@ mdb_txn_safe::mdb_txn_safe(const bool check) : m_txn(NULL), m_tinfo(NULL), m_che mdb_txn_safe::~mdb_txn_safe() { + if (!m_check) + return; LOG_PRINT_L3("mdb_txn_safe: destructor"); if (m_tinfo != nullptr) { @@ -263,8 +265,7 @@ mdb_txn_safe::~mdb_txn_safe() } mdb_txn_abort(m_txn); } - if (m_check) - num_active_txns--; + num_active_txns--; } void mdb_txn_safe::commit(std::string message) -- cgit v1.2.3 From fff238ec94ac6d45fc18c315d7bc590ddfaad63d Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 19 Mar 2016 21:48:36 +0000 Subject: Print stack trace upon exceptions Useful for debugging users' logs --- CMakeLists.txt | 12 ++++ cmake/FindLibunwind.cmake | 25 +++++++ contrib/epee/include/misc_log_ex.h | 2 +- contrib/epee/include/net/abstract_tcp_server2.inl | 2 +- .../include/storages/portable_storage_from_bin.h | 4 +- src/blockchain_db/blockchain_db.h | 3 +- src/blockchain_utilities/blockchain_export.cpp | 2 +- src/blockchain_utilities/blockchain_import.cpp | 6 +- src/blockchain_utilities/bootstrap_file.cpp | 44 ++++++------ src/blockchain_utilities/fake_core.h | 4 +- src/common/CMakeLists.txt | 3 + src/common/exception.cpp | 84 ++++++++++++++++++++++ src/common/exception.h | 53 ++++++++++++++ src/cryptonote_core/blockchain_storage.h | 3 +- src/cryptonote_core/checkpoints_create.cpp | 1 + src/cryptonote_core/cryptonote_core.cpp | 2 +- src/cryptonote_core/cryptonote_core.h | 1 + src/cryptonote_core/miner.cpp | 1 + .../cryptonote_protocol_handler.h | 1 + src/daemon/command_parser_executor.cpp | 1 + src/daemon/command_server.cpp | 1 + src/daemon/daemon.cpp | 6 +- src/daemon/p2p.h | 2 +- src/daemon/protocol.h | 2 +- src/daemon/rpc.h | 4 +- src/daemon/rpc_command_executor.cpp | 3 +- src/daemonizer/posix_fork.cpp | 3 +- src/miner/simpleminer.cpp | 1 + src/p2p/data_logger.cpp | 7 +- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/wallet2.cpp | 5 +- src/wallet/wallet2.h | 1 + src/wallet/wallet2_api.cpp | 1 + tests/core_proxy/core_proxy.h | 2 +- tests/core_tests/chaingen.cpp | 12 ++-- tests/core_tests/chaingen.h | 6 +- tests/core_tests/tx_validation.cpp | 2 +- tests/net_load_tests/clt.cpp | 1 + tests/net_load_tests/srv.cpp | 1 + tests/unit_tests/ban.cpp | 2 +- tests/unit_tests/epee_boosted_tcp_server.cpp | 2 +- tests/unit_tests/mnemonics.cpp | 1 + tests/unit_tests/test_protocol_pack.cpp | 1 + 43 files changed, 259 insertions(+), 63 deletions(-) create mode 100644 cmake/FindLibunwind.cmake create mode 100644 src/common/exception.cpp create mode 100644 src/common/exception.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 9674404bb..ea1d5d7e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,14 @@ endif() add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}") +find_package(Libunwind) +if(LIBUNWIND_FOUND) + message(STATUS "Using libunwind to provide stack traces") + add_definitions("-DHAVE_LIBUNWIND") +else() + message(STATUS "Stack traces disabled") +endif() + if (UNIX AND NOT APPLE) # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail set(THREADS_PREFER_PTHREAD_FLAG ON) @@ -274,6 +282,10 @@ if (BERKELEY_DB) include_directories(${BDB_INCLUDE}) endif() +# Final setup for libunwind +include_directories(${LIBUNWIND_INCLUDE}) +link_directories(${LIBUNWIND_LIBRARY_DIRS}) + if(MSVC) add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake new file mode 100644 index 000000000..9946e7cdd --- /dev/null +++ b/cmake/FindLibunwind.cmake @@ -0,0 +1,25 @@ +# - Try to find libunwind +# Once done this will define +# +# LIBUNWIND_FOUND - system has libunwind +# LIBUNWIND_INCLUDE_DIR - the libunwind include directory +# LIBUNWIND_LIBRARIES - Link these to use libunwind +# LIBUNWIND_DEFINITIONS - Compiler switches required for using libunwind + +# Copyright (c) 2006, Alexander Dymo, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +find_path(LIBUNWIND_INCLUDE_DIR libunwind.h + /usr/include + /usr/local/include +) + +find_library(LIBUNWIND_LIBRARIES NAMES unwind ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libunwind "Could not find libunwind" LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES) +# show the LIBUNWIND_INCLUDE_DIR and LIBUNWIND_LIBRARIES variables only in the advanced view +mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES ) + diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index d1451ff12..58d47c472 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -1426,7 +1426,7 @@ POP_WARNINGS #define CATCH_ENTRY_L4(lacation, return_val) CATCH_ENTRY(lacation, return_val) -#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());} +#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw tools::runtime_error(ss.str());} #define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message);} diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 698e1947a..e4a461203 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -777,7 +777,7 @@ POP_WARNINGS { m_thread_name_prefix = prefix_name; auto it = server_type_map.find(m_thread_name_prefix); - if (it==server_type_map.end()) throw std::runtime_error("Unknown prefix/server type:" + std::string(prefix_name)); + if (it==server_type_map.end()) throw tools::runtime_error("Unknown prefix/server type:" + std::string(prefix_name)); auto connection_type = it->second; // the value of type _info_c("net/RPClog", "Set server type to: " << connection_type << " from name: " << m_thread_name_prefix); _info_c("net/RPClog", "prefix_name = " << prefix_name); diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h index bc2fb1463..4cb2003e0 100644 --- a/contrib/epee/include/storages/portable_storage_from_bin.h +++ b/contrib/epee/include/storages/portable_storage_from_bin.h @@ -84,9 +84,9 @@ namespace epee inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz) { if(!ptr) - throw std::runtime_error("throwable_buffer_reader: ptr==nullptr"); + throw tools::runtime_error("throwable_buffer_reader: ptr==nullptr"); if(!sz) - throw std::runtime_error("throwable_buffer_reader: sz==0"); + throw tools::runtime_error("throwable_buffer_reader: sz==0"); m_ptr = (uint8_t*)ptr; m_count = sz; m_recursion_count = 0; diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 3396b8c20..b9db6d196 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -33,6 +33,7 @@ #include #include #include +#include "common/exception.h" #include "crypto/hash.h" #include "cryptonote_core/cryptonote_basic.h" #include "cryptonote_core/difficulty.h" @@ -151,7 +152,7 @@ struct output_data_t /*********************************** * Exception Definitions ***********************************/ -class DB_EXCEPTION : public std::exception +class DB_EXCEPTION : public tools::exception { private: std::string m; diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index 964c610cd..4c5e5fd02 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -198,7 +198,7 @@ int main(int argc, char* argv[]) else { LOG_ERROR("Attempted to use non-existent database type: " << db_type); - throw std::runtime_error("Attempting to use non-existent database type"); + throw tools::runtime_error("Attempting to use non-existent database type"); } LOG_PRINT_L0("database: " << db_type); diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 1aaf2bddc..43f6af6d5 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -359,14 +359,14 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path, str1.assign(buffer1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) { - throw std::runtime_error("Error in deserialization of chunk size"); + throw tools::runtime_error("Error in deserialization of chunk size"); } LOG_PRINT_L3("chunk_size: " << chunk_size); if (chunk_size > BUFFER_SIZE) { LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE); - throw std::runtime_error("Aborting: chunk size exceeds buffer size"); + throw tools::runtime_error("Aborting: chunk size exceeds buffer size"); } if (chunk_size > 100000) { @@ -406,7 +406,7 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path, str1.assign(buffer_block, chunk_size); bootstrap::block_package bp; if (! ::serialization::parse_binary(str1, bp)) - throw std::runtime_error("Error in deserialization of chunk"); + throw tools::runtime_error("Error in deserialization of chunk"); int display_interval = 1000; int progress_interval = 10; diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp index da3b44593..247709f57 100644 --- a/src/blockchain_utilities/bootstrap_file.cpp +++ b/src/blockchain_utilities/bootstrap_file.cpp @@ -117,7 +117,7 @@ bool BootstrapFile::initialize_file() std::string blob; if (! ::serialization::dump_binary(file_magic, blob)) { - throw std::runtime_error("Error in serialization of file magic"); + throw tools::runtime_error("Error in serialization of file magic"); } *m_raw_data_file << blob; @@ -143,7 +143,7 @@ bool BootstrapFile::initialize_file() if (! ::serialization::dump_binary(bd_size, blob)) { - throw std::runtime_error("Error in serialization of bootstrap::file_info size"); + throw tools::runtime_error("Error in serialization of bootstrap::file_info size"); } *output_stream_header << blob; *output_stream_header << bd; @@ -154,7 +154,7 @@ bool BootstrapFile::initialize_file() if (! ::serialization::dump_binary(bd_size, blob)) { - throw std::runtime_error("Error in serialization of bootstrap::blocks_info size"); + throw tools::runtime_error("Error in serialization of bootstrap::blocks_info size"); } *output_stream_header << blob; *output_stream_header << bd; @@ -181,7 +181,7 @@ void BootstrapFile::flush_chunk() std::string blob; if (! ::serialization::dump_binary(chunk_size, blob)) { - throw std::runtime_error("Error in serialization of chunk size"); + throw tools::runtime_error("Error in serialization of chunk size"); } *m_raw_data_file << blob; @@ -197,7 +197,7 @@ void BootstrapFile::flush_chunk() if (static_cast(num_chars_written) != chunk_size) { LOG_PRINT_RED_L0("Error writing chunk: height: " << m_cur_height << " chunk_size: " << chunk_size << " num chars written: " << num_chars_written); - throw std::runtime_error("Error writing chunk"); + throw tools::runtime_error("Error writing chunk"); } m_buffer.clear(); @@ -221,7 +221,7 @@ void BootstrapFile::write_block(block& block) { if (tx_id == null_hash) { - throw std::runtime_error("Aborting: tx == null_hash"); + throw tools::runtime_error("Aborting: tx == null_hash"); } #if SOURCE_DB == DB_MEMORY const transaction* tx = m_blockchain_storage->get_tx(tx_id); @@ -233,14 +233,14 @@ void BootstrapFile::write_block(block& block) if(tx == NULL) { if (! m_tx_pool) - throw std::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled"); + throw tools::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled"); else { transaction tx; if(m_tx_pool->get_transaction(tx_id, tx)) txs.push_back(tx); else - throw std::runtime_error("Aborting: tx not found in pool"); + throw tools::runtime_error("Aborting: tx not found in pool"); } } else @@ -362,16 +362,16 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file) char buf1[2048]; import_file.read(buf1, sizeof(file_magic)); if (! import_file) - throw std::runtime_error("Error reading expected number of bytes"); + throw tools::runtime_error("Error reading expected number of bytes"); str1.assign(buf1, sizeof(file_magic)); if (! ::serialization::parse_binary(str1, file_magic)) - throw std::runtime_error("Error in deserialization of file_magic"); + throw tools::runtime_error("Error in deserialization of file_magic"); if (file_magic != blockchain_raw_magic) { LOG_PRINT_RED_L0("bootstrap file not recognized"); - throw std::runtime_error("Aborting"); + throw tools::runtime_error("Aborting"); } else LOG_PRINT_L0("bootstrap file recognized"); @@ -381,20 +381,20 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file) import_file.read(buf1, sizeof(buflen_file_info)); str1.assign(buf1, sizeof(buflen_file_info)); if (! import_file) - throw std::runtime_error("Error reading expected number of bytes"); + throw tools::runtime_error("Error reading expected number of bytes"); if (! ::serialization::parse_binary(str1, buflen_file_info)) - throw std::runtime_error("Error in deserialization of buflen_file_info"); + throw tools::runtime_error("Error in deserialization of buflen_file_info"); LOG_PRINT_L1("bootstrap::file_info size: " << buflen_file_info); if (buflen_file_info > sizeof(buf1)) - throw std::runtime_error("Error: bootstrap::file_info size exceeds buffer size"); + throw tools::runtime_error("Error: bootstrap::file_info size exceeds buffer size"); import_file.read(buf1, buflen_file_info); if (! import_file) - throw std::runtime_error("Error reading expected number of bytes"); + throw tools::runtime_error("Error reading expected number of bytes"); str1.assign(buf1, buflen_file_info); bootstrap::file_info bfi; if (! ::serialization::parse_binary(str1, bfi)) - throw std::runtime_error("Error in deserialization of bootstrap::file_info"); + throw tools::runtime_error("Error in deserialization of bootstrap::file_info"); LOG_PRINT_L0("bootstrap file v" << unsigned(bfi.major_version) << "." << unsigned(bfi.minor_version)); LOG_PRINT_L0("bootstrap magic size: " << sizeof(file_magic)); LOG_PRINT_L0("bootstrap header size: " << bfi.header_size); @@ -412,7 +412,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) if (!boost::filesystem::exists(raw_file_path, ec)) { LOG_PRINT_L0("bootstrap file not found: " << raw_file_path); - throw std::runtime_error("Aborting"); + throw tools::runtime_error("Aborting"); } std::ifstream import_file; import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in); @@ -421,7 +421,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) if (import_file.fail()) { LOG_PRINT_L0("import_file.open() fail"); - throw std::runtime_error("Aborting"); + throw tools::runtime_error("Aborting"); } uint64_t full_header_size; // 4 byte magic + length of header structures @@ -456,7 +456,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) str1.assign(buf1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) - throw std::runtime_error("Error in deserialization of chunk_size"); + throw tools::runtime_error("Error in deserialization of chunk_size"); LOG_PRINT_L3("chunk_size: " << chunk_size); if (chunk_size > BUFFER_SIZE) @@ -464,7 +464,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) std::cout << refresh_string; LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE << " height: " << h-1); - throw std::runtime_error("Aborting: chunk size exceeds buffer size"); + throw tools::runtime_error("Aborting: chunk size exceeds buffer size"); } if (chunk_size > 100000) { @@ -475,7 +475,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) else if (chunk_size <= 0) { std::cout << refresh_string; LOG_PRINT_L0("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1); - throw std::runtime_error("Aborting"); + throw tools::runtime_error("Aborting"); } // skip to next expected block size value import_file.seekg(chunk_size, std::ios_base::cur); @@ -483,7 +483,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) std::cout << refresh_string; LOG_PRINT_L0("ERROR: unexpected end of file: bytes read before error: " << import_file.gcount() << " of chunk_size " << chunk_size); - throw std::runtime_error("Aborting"); + throw tools::runtime_error("Aborting"); } bytes_read += chunk_size; diff --git a/src/blockchain_utilities/fake_core.h b/src/blockchain_utilities/fake_core.h index 2fb5031d3..3840a1c13 100644 --- a/src/blockchain_utilities/fake_core.h +++ b/src/blockchain_utilities/fake_core.h @@ -78,7 +78,7 @@ struct fake_core_db else { LOG_ERROR("Attempted to use non-existent database type: " << db_type); - throw std::runtime_error("Attempting to use non-existent database type"); + throw tools::runtime_error("Attempting to use non-existent database type"); } boost::filesystem::path folder(path); @@ -176,7 +176,7 @@ struct fake_core_memory { // TODO: // would need to refactor handle_block_to_main_chain() to have a direct add_block() method like Blockchain class - throw std::runtime_error("direct add_block() method not implemented for in-memory db"); + throw tools::runtime_error("direct add_block() method not implemented for in-memory db"); return 2; } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 2289704e5..5537900ae 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -31,6 +31,7 @@ set(common_sources command_line.cpp dns_utils.cpp util.cpp + exception.cpp i18n.cpp) set(common_headers) @@ -48,6 +49,7 @@ set(common_private_headers unordered_containers_boost_serialization.h util.h varint.h + exception.h i18n.h) bitmonero_private_headers(common @@ -60,6 +62,7 @@ target_link_libraries(common LINK_PRIVATE crypto ${UNBOUND_LIBRARY} + ${LIBUNWIND_LIBRARIES} ${Boost_DATE_TIME_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} diff --git a/src/common/exception.cpp b/src/common/exception.cpp new file mode 100644 index 000000000..f8954329f --- /dev/null +++ b/src/common/exception.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2016, 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 "common/exception.h" +#include "misc_log_ex.h" +#define UNW_LOCAL_ONLY +#include +#include + +namespace tools +{ + +void log_stack_trace(const char *msg) +{ +#ifdef HAVE_LIBUNWIND + unw_context_t ctx; + unw_cursor_t cur; + unw_word_t ip, off; + unsigned level; + char sym[512], *dsym; + int status; + + if (msg) + LOG_PRINT_L0(msg); + LOG_PRINT_L0("Unwinded call stack:"); + if (unw_getcontext(&ctx) < 0) { + LOG_PRINT_L0("Failed to create unwind context"); + return; + } + if (unw_init_local(&cur, &ctx) < 0) { + LOG_PRINT_L0("Failed to find the first unwind frame"); + return; + } + for (level = 1; level < 999; ++level) { // 999 for safety + int ret = unw_step(&cur); + if (ret < 0) { + LOG_PRINT_L0("Failed to find the next frame"); + return; + } + if (ret == 0) + break; + if (unw_get_reg(&cur, UNW_REG_IP, &ip) < 0) { + LOG_PRINT_L0(" " << std::setw(4) << level); + continue; + } + if (unw_get_proc_name(&cur, sym, sizeof(sym), &off) < 0) { + LOG_PRINT_L0(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip); + continue; + } + dsym = abi::__cxa_demangle(sym, NULL, NULL, &status); + LOG_PRINT_L0(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip << " " << (!status && dsym ? dsym : sym) << " + " << "0x" << off); + free(dsym); + } +#else +#warning libunwind disabled, no stack traces +#endif +} + +} // namespace tools diff --git a/src/common/exception.h b/src/common/exception.h new file mode 100644 index 000000000..93e0d4013 --- /dev/null +++ b/src/common/exception.h @@ -0,0 +1,53 @@ +// Copyright (c) 2016, 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. + +#ifndef MONERO_EXCEPTION_H +#define MONERO_EXCEPTION_H + +#include +#include + +namespace tools +{ + +void log_stack_trace(const char *msg); + +class exception: public std::exception { +public: + exception() { log_stack_trace(what()); } +}; + +class runtime_error: public std::runtime_error { +public: + explicit runtime_error(const std::string &s): std::runtime_error(s) { log_stack_trace(what()); } + explicit runtime_error(const char *s): std::runtime_error(s) { log_stack_trace(what()); } +}; + +} // namespace tools + +#endif diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index 878202cf1..e25f80116 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -41,6 +41,7 @@ #include "syncobj.h" #include "string_tools.h" +#include "common/exception.h" #include "tx_pool.h" #include "cryptonote_basic.h" #include "common/util.h" @@ -314,7 +315,7 @@ namespace cryptonote "m_invalid_blocks: " << m_invalid_blocks.size() << ENDL << "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); - throw std::runtime_error("Blockchain data corruption"); + throw tools::runtime_error("Blockchain data corruption"); } } } diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp index 41f2321d5..41246e8d8 100644 --- a/src/cryptonote_core/checkpoints_create.cpp +++ b/src/cryptonote_core/checkpoints_create.cpp @@ -28,6 +28,7 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include "common/exception.h" #include "checkpoints_create.h" #include "common/dns_utils.h" #include "include_base_utils.h" diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 6f0fe88a4..907f9d803 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -161,7 +161,7 @@ namespace cryptonote cryptonote::checkpoints checkpoints; if (!cryptonote::create_checkpoints(checkpoints)) { - throw std::runtime_error("Failed to initialize checkpoints"); + throw tools::runtime_error("Failed to initialize checkpoints"); } set_checkpoints(std::move(checkpoints)); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 32f0b2ad4..186c1c93b 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -36,6 +36,7 @@ #include #include +#include #include "p2p/net_node_common.h" #include "cryptonote_protocol/cryptonote_protocol_handler_common.h" #include "storages/portable_storage_template_helper.h" diff --git a/src/cryptonote_core/miner.cpp b/src/cryptonote_core/miner.cpp index bad3f30bd..7bc126cd8 100644 --- a/src/cryptonote_core/miner.cpp +++ b/src/cryptonote_core/miner.cpp @@ -34,6 +34,7 @@ #include #include #include +#include "common/exception.h" #include "misc_language.h" #include "include_base_utils.h" #include "cryptonote_basic_impl.h" diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 1c92958c9..2112b5082 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -38,6 +38,7 @@ #include #include +#include "common/exception.h" #include "storages/levin_abstract_invoke2.h" #include "warnings.h" #include "cryptonote_protocol_defs.h" diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 0b42257e7..c48b836e9 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -26,6 +26,7 @@ // 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 "common/exception.h" #include "cryptonote_core/cryptonote_basic_impl.h" #include "daemon/command_parser_executor.h" diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 206de9d4a..7e5139636 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -26,6 +26,7 @@ // 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 "common/exception.h" #include "cryptonote_config.h" #include "version.h" #include "daemon/command_server.h" diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index e79823d08..d44538358 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -110,7 +110,7 @@ bool t_daemon::run(bool interactive) { if (nullptr == mp_internals) { - throw std::runtime_error{"Can't run stopped daemon"}; + throw tools::runtime_error{"Can't run stopped daemon"}; } tools::signal_handler::install(std::bind(&daemonize::t_daemon::stop_p2p, this)); @@ -155,7 +155,7 @@ void t_daemon::stop() { if (nullptr == mp_internals) { - throw std::runtime_error{"Can't stop stopped daemon"}; + throw tools::runtime_error{"Can't stop stopped daemon"}; } mp_internals->p2p.stop(); mp_internals->rpc.stop(); @@ -166,7 +166,7 @@ void t_daemon::stop_p2p() { if (nullptr == mp_internals) { - throw std::runtime_error{"Can't send stop signal to a stopped daemon"}; + throw tools::runtime_error{"Can't send stop signal to a stopped daemon"}; } mp_internals->p2p.get().send_stop_signal(); } diff --git a/src/daemon/p2p.h b/src/daemon/p2p.h index 3858989ce..b74a5e72d 100644 --- a/src/daemon/p2p.h +++ b/src/daemon/p2p.h @@ -60,7 +60,7 @@ public: LOG_PRINT_L0("Initializing p2p server..."); if (!m_server.init(vm)) { - throw std::runtime_error("Failed to initialize p2p server."); + throw tools::runtime_error("Failed to initialize p2p server."); } LOG_PRINT_L0("P2p server initialized OK"); } diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h index 8e2add4a2..5f6c317b1 100644 --- a/src/daemon/protocol.h +++ b/src/daemon/protocol.h @@ -50,7 +50,7 @@ public: LOG_PRINT_L0("Initializing cryptonote protocol..."); if (!m_protocol.init(vm)) { - throw std::runtime_error("Failed to initialize cryptonote protocol."); + throw tools::runtime_error("Failed to initialize cryptonote protocol."); } LOG_PRINT_L0("Cryptonote protocol initialized OK"); } diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h index bfd2afd84..caeae9a3d 100644 --- a/src/daemon/rpc.h +++ b/src/daemon/rpc.h @@ -55,7 +55,7 @@ public: LOG_PRINT_L0("Initializing core rpc server..."); if (!m_server.init(vm)) { - throw std::runtime_error("Failed to initialize core rpc server."); + throw tools::runtime_error("Failed to initialize core rpc server."); } LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_server.get_binded_port(), LOG_LEVEL_0); } @@ -65,7 +65,7 @@ public: LOG_PRINT_L0("Starting core rpc server..."); if (!m_server.run(2, false)) { - throw std::runtime_error("Failed to start core rpc server."); + throw tools::runtime_error("Failed to start core rpc server."); } LOG_PRINT_L0("Core rpc server started ok"); } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index ffda7cde3..13cc5fadc 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -28,6 +28,7 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include "common/exception.h" #include "string_tools.h" #include "common/scoped_message_writer.h" #include "daemon/rpc_command_executor.h" @@ -88,7 +89,7 @@ t_rpc_command_executor::t_rpc_command_executor( { if (rpc_server == NULL) { - throw std::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null"); + throw tools::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null"); } } diff --git a/src/daemonizer/posix_fork.cpp b/src/daemonizer/posix_fork.cpp index c068912ec..84ff88869 100644 --- a/src/daemonizer/posix_fork.cpp +++ b/src/daemonizer/posix_fork.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#include "common/exception.h" #include "daemonizer/posix_fork.h" #include "misc_log_ex.h" @@ -20,7 +21,7 @@ namespace { void quit(std::string const & message) { LOG_ERROR(message); - throw std::runtime_error(message); + throw tools::runtime_error(message); } } diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp index ba956d90b..19db3f534 100644 --- a/src/miner/simpleminer.cpp +++ b/src/miner/simpleminer.cpp @@ -28,6 +28,7 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include "common/exception.h" #include "common/command_line.h" #include "misc_log_ex.h" #include "simpleminer.h" diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index ca0726c5f..d3ff0ca8e 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -33,6 +33,7 @@ #include #include #include +#include "common/exception.h" #include "../../contrib/otshell_utils/utils.hpp" namespace epee @@ -43,7 +44,7 @@ namespace net_utils boost::call_once(m_singleton, [] { _info_c("dbg/data","Creating singleton of data_logger"); - if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw std::runtime_error("data_logger singleton"); } + if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw tools::runtime_error("data_logger singleton"); } m_state = data_logger_state::state_during_init; m_obj.reset(new data_logger()); m_state = data_logger_state::state_ready_to_use; @@ -52,7 +53,7 @@ namespace net_utils if (m_state != data_logger_state::state_ready_to_use) { _erro ("trying to use not working data_logger"); - throw std::runtime_error("data_logger ctor state"); + throw tools::runtime_error("data_logger ctor state"); } return * m_obj; @@ -60,7 +61,7 @@ namespace net_utils data_logger::data_logger() { _note_c("dbg/data","Starting data logger (for graphs data)"); - if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw std::runtime_error("data_logger ctor state"); } + if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw tools::runtime_error("data_logger ctor state"); } boost::lock_guard lock(mMutex); // lock // prepare all the files for given data channels: diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 73b56f2b7..a6ef292ef 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -561,7 +561,7 @@ bool simple_wallet::set_variable(const std::vector &args) { if (args.empty()) { - fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, default-mixin, auto-refresh, refresh-type"); + fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, store-tx-info, default-mixin, auto-refresh, refresh-type"); return true; } else diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2afe08cb1..ef17a770b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -32,6 +32,7 @@ #include #include +#include "common/exception.h" #include "include_base_utils.h" using namespace epee; @@ -803,7 +804,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re // handle error from async fetching thread if (error) { - throw std::runtime_error("proxy exception in refresh thread"); + throw tools::runtime_error("proxy exception in refresh thread"); } } catch (const std::exception&) @@ -2012,7 +2013,7 @@ std::vector wallet2::create_transactions(std::vector ptx_vector; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f798f404d..0961ad981 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -35,6 +35,7 @@ #include #include +#include "common/exception.h" #include "include_base_utils.h" #include "cryptonote_core/account.h" #include "cryptonote_core/account_boost_serialization.h" diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 0644e3690..0cb253398 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -28,6 +28,7 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include "common/exception.h" #include "wallet2_api.h" #include "wallet2.h" #include "mnemonics/electrum-words.h" diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 0315fc8c8..22f4c0421 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -82,7 +82,7 @@ namespace tests bool on_idle(){return true;} bool find_blockchain_supplement(const std::list& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} - cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } + cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } bool get_test_drop_download() {return true;} bool get_test_drop_download_height() {return true;} bool prepare_handle_incoming_blocks(const std::list &blocks) { return true; } diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 4fdd0a600..b897d9237 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -58,7 +58,7 @@ void test_generator::get_block_chain(std::vector& blockchain, const auto it = m_blocks_info.find(curr); if (m_blocks_info.end() == it) { - throw std::runtime_error("block hash wasn't found"); + throw tools::runtime_error("block hash wasn't found"); } blockchain.push_back(it->second); @@ -82,7 +82,7 @@ uint64_t test_generator::get_already_generated_coins(const crypto::hash& blk_id) { auto it = m_blocks_info.find(blk_id); if (it == m_blocks_info.end()) - throw std::runtime_error("block hash wasn't found"); + throw tools::runtime_error("block hash wasn't found"); return it->second.already_generated_coins; } @@ -323,7 +323,7 @@ bool init_output_indices(map_output_idx_t& outs, std::mapsecond); } @@ -486,11 +486,11 @@ void fill_tx_sources_and_destinations(const std::vector& event destinations.clear(); if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix)) - throw std::runtime_error("couldn't fill transaction sources"); + throw tools::runtime_error("couldn't fill transaction sources"); tx_destination_entry de; if (!fill_tx_destination(de, to, amount)) - throw std::runtime_error("couldn't fill transaction destination"); + throw tools::runtime_error("couldn't fill transaction destination"); destinations.push_back(de); tx_destination_entry de_change; @@ -498,7 +498,7 @@ void fill_tx_sources_and_destinations(const std::vector& event if (0 < cache_back) { if (!fill_tx_destination(de_change, from, cache_back)) - throw std::runtime_error("couldn't fill transaction cache back destination"); + throw tools::runtime_error("couldn't fill transaction cache back destination"); destinations.push_back(de_change); } } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index d0d912cbb..d51d9d320 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -284,7 +284,7 @@ bool do_check_tx_verification_context(const cryptonote::tx_verification_context& { // Default block verification context check if (tvc.m_verifivation_failed) - throw std::runtime_error("Transaction verification failed"); + throw tools::runtime_error("Transaction verification failed"); return true; } //-------------------------------------------------------------------------- @@ -307,7 +307,7 @@ bool do_check_block_verification_context(const cryptonote::block_verification_co { // Default block verification context check if (bvc.m_verifivation_failed) - throw std::runtime_error("Block verification failed"); + throw tools::runtime_error("Block verification failed"); return true; } //-------------------------------------------------------------------------- @@ -621,7 +621,7 @@ inline bool do_replay_file(const std::string& filename) if (!tools::serialize_obj_to_file(events, filename)) \ { \ std::cout << concolor::magenta << "Failed to serialize data to file: " << filename << concolor::normal << std::endl; \ - throw std::runtime_error("Failed to serialize data to file"); \ + throw tools::runtime_error("Failed to serialize data to file"); \ } \ } diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index f72c906e5..41d5f1e26 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -156,7 +156,7 @@ namespace } } - throw std::runtime_error("invalid public key wasn't found"); + throw tools::runtime_error("invalid public key wasn't found"); return crypto::public_key(); } } diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp index 56089a4da..360261676 100644 --- a/tests/net_load_tests/clt.cpp +++ b/tests/net_load_tests/clt.cpp @@ -37,6 +37,7 @@ #include "gtest/gtest.h" +#include "common/exception.h" #include "include_base_utils.h" #include "misc_language.h" #include "misc_log_ex.h" diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp index d8d3eae2e..13b31215e 100644 --- a/tests/net_load_tests/srv.cpp +++ b/tests/net_load_tests/srv.cpp @@ -31,6 +31,7 @@ #include #include +#include "common/exception.h" #include "include_base_utils.h" #include "misc_log_ex.h" #include "storages/levin_abstract_invoke2.h" diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp index a5ce244d9..5d40e90cf 100644 --- a/tests/unit_tests/ban.cpp +++ b/tests/unit_tests/ban.cpp @@ -56,7 +56,7 @@ public: bool on_idle(){return true;} bool find_blockchain_supplement(const std::list& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} - cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); } + cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); } bool get_test_drop_download() const {return true;} bool get_test_drop_download_height() const {return true;} bool prepare_handle_incoming_blocks(const std::list &blocks) { return true; } diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp index 946db292d..b68ce77bb 100644 --- a/tests/unit_tests/epee_boosted_tcp_server.cpp +++ b/tests/unit_tests/epee_boosted_tcp_server.cpp @@ -104,7 +104,7 @@ TEST(boosted_tcp_server, worker_threads_are_exception_resistant) // 2 theads, but 4 exceptions ASSERT_TRUE(srv.run_server(2, false)); - ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::runtime_error("test 1"); })); + ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw tools::runtime_error("test 1"); })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::string("test 2"); })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw "test 3"; })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw 4; })); diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp index 3dc5db7d4..3bf1df7ed 100644 --- a/tests/unit_tests/mnemonics.cpp +++ b/tests/unit_tests/mnemonics.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gtest/gtest.h" +#include "common/exception.h" #include "mnemonics/electrum-words.h" #include "crypto/crypto.h" #include diff --git a/tests/unit_tests/test_protocol_pack.cpp b/tests/unit_tests/test_protocol_pack.cpp index a9a1a34a6..1ff70b4d9 100644 --- a/tests/unit_tests/test_protocol_pack.cpp +++ b/tests/unit_tests/test_protocol_pack.cpp @@ -30,6 +30,7 @@ #include "gtest/gtest.h" +#include "common/exception.h" #include "include_base_utils.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "storages/portable_storage_template_helper.h" -- cgit v1.2.3 From b52545706147b31c373dbdb001b3504dbb35ead7 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 19 Mar 2016 22:18:47 +0000 Subject: simplewallet: make --password-file work in RPC mode --- src/simplewallet/simplewallet.cpp | 96 ++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 73b56f2b7..ea1993c80 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -760,6 +760,54 @@ void simple_wallet::print_seed(std::string seed) std::cout << seed << std::endl; } +//---------------------------------------------------------------------------------------------------- +static bool get_password(const boost::program_options::variables_map& vm, bool allow_entry, tools::password_container &pwd_container) +{ + if (has_arg(vm, arg_password) && has_arg(vm, arg_password_file)) + { + fail_msg_writer() << tr("can't specify more than one of --password and --password-file"); + return false; + } + + if (command_line::has_arg(vm, arg_password)) + { + pwd_container.password(command_line::get_arg(vm, arg_password)); + return true; + } + + if (command_line::has_arg(vm, arg_password_file)) + { + std::string password; + bool r = epee::file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_password_file), + password); + if (!r) + { + fail_msg_writer() << tr("the password file specified could not be read"); + return false; + } + + // Remove line breaks the user might have inserted + password.erase(std::remove(password.begin() - 1, password.end(), '\n'), password.end()); + password.erase(std::remove(password.end() - 1, password.end(), '\r'), password.end()); + pwd_container.password(password.c_str()); + return true; + } + + if (allow_entry) + { + bool r = pwd_container.read_password(); + if (!r) + { + fail_msg_writer() << tr("failed to read wallet password"); + return false; + } + return true; + } + + fail_msg_writer() << tr("Wallet password not set."); + return false; +} + //---------------------------------------------------------------------------------------------------- bool simple_wallet::init(const boost::program_options::variables_map& vm) { @@ -795,42 +843,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (m_daemon_address.empty()) m_daemon_address = std::string("http://") + m_daemon_host + ":" + std::to_string(m_daemon_port); - if (has_arg(vm, arg_password) && has_arg(vm, arg_password_file)) - { - fail_msg_writer() << tr("can't specify more than one of --password and --password-file"); - return false; - } - tools::password_container pwd_container; - if (command_line::has_arg(vm, arg_password)) - { - pwd_container.password(command_line::get_arg(vm, arg_password)); - } - else if (command_line::has_arg(vm, arg_password_file)) - { - std::string password; - bool r = epee::file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_password_file), - password); - if (!r) - { - fail_msg_writer() << tr("the password file specified could not be read"); - return false; - } - - // Remove line breaks the user might have inserted - password.erase(std::remove(password.begin() - 1, password.end(), '\n'), password.end()); - password.erase(std::remove(password.end() - 1, password.end(), '\r'), password.end()); - pwd_container.password(password.c_str()); - } - else - { - bool r = pwd_container.read_password(); - if (!r) - { - fail_msg_writer() << tr("failed to read wallet password"); - return false; - } - } + if (!get_password(vm, true, pwd_container)) + return false; if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty()) { @@ -2675,16 +2690,13 @@ int main(int argc, char* argv[]) LOG_ERROR(sw::tr("Daemon address not set.")); return 1; } - if(!command_line::has_arg(vm, arg_password) ) - { - LOG_ERROR(sw::tr("Wallet password not set.")); - return 1; - } bool testnet = command_line::get_arg(vm, arg_testnet); bool restricted = command_line::get_arg(vm, arg_restricted); std::string wallet_file = command_line::get_arg(vm, arg_wallet_file); - std::string wallet_password = command_line::get_arg(vm, arg_password); + tools::password_container pwd_container; + if (!get_password(vm, false, pwd_container)) + return 1; std::string daemon_address = command_line::get_arg(vm, arg_daemon_address); std::string daemon_host = command_line::get_arg(vm, arg_daemon_host); int daemon_port = command_line::get_arg(vm, arg_daemon_port); @@ -2699,7 +2711,7 @@ int main(int argc, char* argv[]) try { LOG_PRINT_L0(sw::tr("Loading wallet...")); - wal.load(wallet_file, wallet_password); + wal.load(wallet_file, pwd_container.password()); wal.init(daemon_address); wal.refresh(); LOG_PRINT_GREEN(sw::tr("Loaded ok"), LOG_LEVEL_0); -- cgit v1.2.3 From d2aa427c78f3aa742fc812b73de63abb8602707b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 19 Mar 2016 23:58:30 +0000 Subject: rpc: fix print_tx in command line mode It was only filling the input in non rpc mode --- src/daemon/rpc_command_executor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index ffda7cde3..15ddc081f 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -558,6 +558,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { std::string fail_message = "Problem fetching transaction"; + req.txs_hashes.push_back(epee::string_tools::pod_to_hex(transaction_hash)); if (m_is_rpc) { if (!m_rpc_client->rpc_request(req, res, "/gettransactions", fail_message.c_str())) @@ -567,7 +568,6 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { } else { - req.txs_hashes.push_back(epee::string_tools::pod_to_hex(transaction_hash)); if (!m_rpc_server->on_get_transactions(req, res) || res.status != CORE_RPC_STATUS_OK) { tools::fail_msg_writer() << fail_message.c_str(); -- cgit v1.2.3 From 1c3ed4c9da57b1ed1f912c14370249a9d02a3ea6 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 20 Mar 2016 12:35:53 +0000 Subject: cryptonote_protocol: clarify height wording It's logging the blockchain height, not the top block height --- src/cryptonote_protocol/cryptonote_protocol_handler.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index f917f4c3f..9f0ea0e83 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -281,7 +281,7 @@ namespace cryptonote << " [" << std::abs(diff) << " blocks (" << diff / (24 * 60 * 60 / DIFFICULTY_TARGET_V1) << " days) " << (0 <= diff ? std::string("behind") : std::string("ahead")) << "] " << ENDL << "SYNCHRONIZATION started", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1)); - LOG_PRINT_L1("Remote top block height: " << hshd.current_height << ", id: " << hshd.top_id); + LOG_PRINT_L1("Remote blockchain height: " << hshd.current_height << ", id: " << hshd.top_id); context.m_state = cryptonote_connection_context::state_synchronizing; context.m_remote_blockchain_height = hshd.current_height; //let the socket to send response to handshake, but request callback, to let send request data after response -- cgit v1.2.3 From 79117d4275c53ecd472f810e710c74be597758d5 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 20 Mar 2016 18:06:04 +0000 Subject: db_lmdb: include the error codes from lmdb api in error logs --- src/blockchain_db/lmdb/db_lmdb.cpp | 87 ++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 4e30548fc..e928ab803 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -545,11 +545,12 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const { MDB_val_copy parent_key(blk.prev_id); MDB_val parent_h; - if (mdb_cursor_get(m_cur_block_heights, &parent_key, &parent_h, MDB_SET)) + int result = mdb_cursor_get(m_cur_block_heights, &parent_key, &parent_h, MDB_SET); + if (result) { LOG_PRINT_L3("m_height: " << m_height); LOG_PRINT_L3("parent_key: " << blk.prev_id); - throw0(DB_ERROR("Failed to get top block hash to check for new block's parent")); + throw0(DB_ERROR(lmdb_error("Failed to get top block hash to check for new block's parent: ", result).c_str())); } uint64_t parent_height = *(const uint64_t *)parent_h.mv_data; if (parent_height != m_height - 1) @@ -606,6 +607,8 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const void BlockchainLMDB::remove_block() { + int result; + LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -614,29 +617,29 @@ void BlockchainLMDB::remove_block() MDB_val_copy k(m_height - 1); MDB_val h; - if (mdb_get(*m_write_txn, m_block_hashes, &k, &h)) - throw1(BLOCK_DNE("Attempting to remove block that's not in the db")); + if ((result = mdb_get(*m_write_txn, m_block_hashes, &k, &h))) + throw1(BLOCK_DNE(lmdb_error("Attempting to remove block that's not in the db: ", result).c_str())); - if (mdb_del(*m_write_txn, m_blocks, &k, NULL)) - throw1(DB_ERROR("Failed to add removal of block to db transaction")); + if ((result = mdb_del(*m_write_txn, m_blocks, &k, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block to db transaction: ", result).c_str())); - if (mdb_del(*m_write_txn, m_block_sizes, &k, NULL)) - throw1(DB_ERROR("Failed to add removal of block size to db transaction")); + if ((result = mdb_del(*m_write_txn, m_block_sizes, &k, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block size to db transaction: ", result).c_str())); - if (mdb_del(*m_write_txn, m_block_diffs, &k, NULL)) - throw1(DB_ERROR("Failed to add removal of block cumulative difficulty to db transaction")); + if ((result = mdb_del(*m_write_txn, m_block_diffs, &k, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block cumulative difficulty to db transaction: ", result).c_str())); - if (mdb_del(*m_write_txn, m_block_coins, &k, NULL)) - throw1(DB_ERROR("Failed to add removal of block total generated coins to db transaction")); + if ((result = mdb_del(*m_write_txn, m_block_coins, &k, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block total generated coins to db transaction: ", result).c_str())); - if (mdb_del(*m_write_txn, m_block_timestamps, &k, NULL)) - throw1(DB_ERROR("Failed to add removal of block timestamp to db transaction")); + if ((result = mdb_del(*m_write_txn, m_block_timestamps, &k, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block timestamp to db transaction: ", result).c_str())); - if (mdb_del(*m_write_txn, m_block_heights, &h, NULL)) - throw1(DB_ERROR("Failed to add removal of block height by hash to db transaction")); + if ((result = mdb_del(*m_write_txn, m_block_heights, &h, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block height by hash to db transaction: ", result).c_str())); - if (mdb_del(*m_write_txn, m_block_hashes, &k, NULL)) - throw1(DB_ERROR("Failed to add removal of block hash to db transaction")); + if ((result = mdb_del(*m_write_txn, m_block_hashes, &k, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block hash to db transaction: ", result).c_str())); } void BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) @@ -674,6 +677,8 @@ void BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const tr void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) { + int result; + LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -682,16 +687,16 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const if (mdb_get(*m_write_txn, m_txs, &val_h, &unused)) throw1(TX_DNE("Attempting to remove transaction that isn't in the db")); - if (mdb_del(*m_write_txn, m_txs, &val_h, NULL)) - throw1(DB_ERROR("Failed to add removal of tx to db transaction")); - if (mdb_del(*m_write_txn, m_tx_unlocks, &val_h, NULL)) - throw1(DB_ERROR("Failed to add removal of tx unlock time to db transaction")); - if (mdb_del(*m_write_txn, m_tx_heights, &val_h, NULL)) - throw1(DB_ERROR("Failed to add removal of tx block height to db transaction")); + if ((result = mdb_del(*m_write_txn, m_txs, &val_h, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of tx to db transaction: ", result).c_str())); + if ((result = mdb_del(*m_write_txn, m_tx_unlocks, &val_h, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of tx unlock time to db transaction: ", result).c_str())); + if ((result = mdb_del(*m_write_txn, m_tx_heights, &val_h, NULL))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of tx block height to db transaction: ", result).c_str())); remove_tx_outputs(&val_h, tx); - auto result = mdb_del(*m_write_txn, m_tx_outputs, &val_h, NULL); + result = mdb_del(*m_write_txn, m_tx_outputs, &val_h, NULL); if (result == MDB_NOTFOUND) LOG_PRINT_L1("tx has no outputs to remove: " << tx_hash); else if (result) @@ -741,8 +746,8 @@ void BlockchainLMDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_ou MDB_val_copy data(od); //MDB_val_copy val_pubkey(boost::get(tx_output.target).key); - if (mdb_cursor_put(m_cur_output_keys, &k, &data, MDB_APPEND)) - throw0(DB_ERROR("Failed to add output pubkey to db transaction")); + if ((result = mdb_cursor_put(m_cur_output_keys, &k, &data, MDB_APPEND))) + throw0(DB_ERROR(lmdb_error("Failed to add output pubkey to db transaction: ", result).c_str())); } else { @@ -767,7 +772,7 @@ void BlockchainLMDB::remove_tx_outputs(const MDB_val *tx_hash, const transaction } else if (result) { - throw0(DB_ERROR("DB error attempting to get an output")); + throw0(DB_ERROR(lmdb_error("DB error attempting to get an output", result).c_str())); } else { @@ -879,9 +884,9 @@ void BlockchainLMDB::remove_amount_output_index(const uint64_t amount, const MDB { // found the amount output index // now delete it - result = mdb_cursor_del(m_cur_output_amounts, 0); + int result = mdb_cursor_del(m_cur_output_amounts, 0); if (result) - throw0(DB_ERROR(std::string("Error deleting amount output index ").append(boost::lexical_cast(amount_output_index)).c_str())); + throw0(DB_ERROR(lmdb_error(std::string("Error deleting amount output index ").append(boost::lexical_cast(amount_output_index).append(": ")).c_str(), result).c_str())); } else { @@ -996,6 +1001,8 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions) void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) { + int result; + LOG_PRINT_L3("BlockchainLMDB::" << __func__); if (m_open) @@ -1025,10 +1032,10 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) m_folder = filename; // set up lmdb environment - if (mdb_env_create(&m_env)) - throw0(DB_ERROR("Failed to create lmdb environment")); - if (mdb_env_set_maxdbs(m_env, 20)) - throw0(DB_ERROR("Failed to set max number of dbs")); + if ((result = mdb_env_create(&m_env))) + throw0(DB_ERROR(lmdb_error("Failed to create lmdb environment: ", result).c_str())); + if ((result = mdb_env_set_maxdbs(m_env, 20))) + throw0(DB_ERROR(lmdb_error("Failed to set max number of dbs: ", result).c_str())); size_t mapsize = DEFAULT_MAPSIZE; @@ -1104,14 +1111,14 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) // get and keep current height MDB_stat db_stats; - if (mdb_stat(txn, m_blocks, &db_stats)) - throw0(DB_ERROR("Failed to query m_blocks")); + if ((result = mdb_stat(txn, m_blocks, &db_stats))) + throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str())); LOG_PRINT_L2("Setting m_height to: " << db_stats.ms_entries); m_height = db_stats.ms_entries; // get and keep current number of outputs - if (mdb_stat(txn, m_output_indices, &db_stats)) - throw0(DB_ERROR("Failed to query m_output_indices")); + if ((result = mdb_stat(txn, m_output_indices, &db_stats))) + throw0(DB_ERROR(lmdb_error("Failed to query m_output_indices: ", result).c_str())); m_num_outputs = db_stats.ms_entries; bool compatible = true; @@ -1232,8 +1239,8 @@ void BlockchainLMDB::reset() check_open(); mdb_txn_safe txn; - if (mdb_txn_begin(m_env, NULL, 0, txn)) - throw0(DB_ERROR("Failed to create a transaction for the db")); + if (auto result = mdb_txn_begin(m_env, NULL, 0, txn)) + throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); mdb_drop(txn, m_blocks, 0); mdb_drop(txn, m_block_timestamps, 0); mdb_drop(txn, m_block_heights, 0); -- cgit v1.2.3 From f7301c3563e7ae19b8d7c65d8bc88f3c42eefc09 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 21 Mar 2016 10:12:12 +0000 Subject: Revert "Print stack trace upon exceptions" Ain't nobody got time for link/cmake skullduggery. This reverts commit fff238ec94ac6d45fc18c315d7bc590ddfaad63d. --- CMakeLists.txt | 12 ---- cmake/FindLibunwind.cmake | 25 ------- contrib/epee/include/misc_log_ex.h | 2 +- contrib/epee/include/net/abstract_tcp_server2.inl | 2 +- .../include/storages/portable_storage_from_bin.h | 4 +- src/blockchain_db/blockchain_db.h | 3 +- src/blockchain_utilities/blockchain_export.cpp | 2 +- src/blockchain_utilities/blockchain_import.cpp | 6 +- src/blockchain_utilities/bootstrap_file.cpp | 44 ++++++------ src/blockchain_utilities/fake_core.h | 4 +- src/common/CMakeLists.txt | 3 - src/common/exception.cpp | 84 ---------------------- src/common/exception.h | 53 -------------- src/cryptonote_core/blockchain_storage.h | 3 +- src/cryptonote_core/checkpoints_create.cpp | 1 - src/cryptonote_core/cryptonote_core.cpp | 2 +- src/cryptonote_core/cryptonote_core.h | 1 - src/cryptonote_core/miner.cpp | 1 - .../cryptonote_protocol_handler.h | 1 - src/daemon/command_parser_executor.cpp | 1 - src/daemon/command_server.cpp | 1 - src/daemon/daemon.cpp | 6 +- src/daemon/p2p.h | 2 +- src/daemon/protocol.h | 2 +- src/daemon/rpc.h | 4 +- src/daemon/rpc_command_executor.cpp | 3 +- src/daemonizer/posix_fork.cpp | 3 +- src/miner/simpleminer.cpp | 1 - src/p2p/data_logger.cpp | 7 +- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/wallet2.cpp | 5 +- src/wallet/wallet2.h | 1 - src/wallet/wallet2_api.cpp | 1 - tests/core_proxy/core_proxy.h | 2 +- tests/core_tests/chaingen.cpp | 12 ++-- tests/core_tests/chaingen.h | 6 +- tests/core_tests/tx_validation.cpp | 2 +- tests/net_load_tests/clt.cpp | 1 - tests/net_load_tests/srv.cpp | 1 - tests/unit_tests/ban.cpp | 2 +- tests/unit_tests/epee_boosted_tcp_server.cpp | 2 +- tests/unit_tests/mnemonics.cpp | 1 - tests/unit_tests/test_protocol_pack.cpp | 1 - 43 files changed, 63 insertions(+), 259 deletions(-) delete mode 100644 cmake/FindLibunwind.cmake delete mode 100644 src/common/exception.cpp delete mode 100644 src/common/exception.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index ea1d5d7e5..9674404bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,14 +243,6 @@ endif() add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}") -find_package(Libunwind) -if(LIBUNWIND_FOUND) - message(STATUS "Using libunwind to provide stack traces") - add_definitions("-DHAVE_LIBUNWIND") -else() - message(STATUS "Stack traces disabled") -endif() - if (UNIX AND NOT APPLE) # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail set(THREADS_PREFER_PTHREAD_FLAG ON) @@ -282,10 +274,6 @@ if (BERKELEY_DB) include_directories(${BDB_INCLUDE}) endif() -# Final setup for libunwind -include_directories(${LIBUNWIND_INCLUDE}) -link_directories(${LIBUNWIND_LIBRARY_DIRS}) - if(MSVC) add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake deleted file mode 100644 index 9946e7cdd..000000000 --- a/cmake/FindLibunwind.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# - Try to find libunwind -# Once done this will define -# -# LIBUNWIND_FOUND - system has libunwind -# LIBUNWIND_INCLUDE_DIR - the libunwind include directory -# LIBUNWIND_LIBRARIES - Link these to use libunwind -# LIBUNWIND_DEFINITIONS - Compiler switches required for using libunwind - -# Copyright (c) 2006, Alexander Dymo, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -find_path(LIBUNWIND_INCLUDE_DIR libunwind.h - /usr/include - /usr/local/include -) - -find_library(LIBUNWIND_LIBRARIES NAMES unwind ) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Libunwind "Could not find libunwind" LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES) -# show the LIBUNWIND_INCLUDE_DIR and LIBUNWIND_LIBRARIES variables only in the advanced view -mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES ) - diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 58d47c472..d1451ff12 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -1426,7 +1426,7 @@ POP_WARNINGS #define CATCH_ENTRY_L4(lacation, return_val) CATCH_ENTRY(lacation, return_val) -#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw tools::runtime_error(ss.str());} +#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());} #define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message);} diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 2f6e52a5b..1c854dfb7 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -777,7 +777,7 @@ POP_WARNINGS { m_thread_name_prefix = prefix_name; auto it = server_type_map.find(m_thread_name_prefix); - if (it==server_type_map.end()) throw tools::runtime_error("Unknown prefix/server type:" + std::string(prefix_name)); + if (it==server_type_map.end()) throw std::runtime_error("Unknown prefix/server type:" + std::string(prefix_name)); auto connection_type = it->second; // the value of type _info_c("net/RPClog", "Set server type to: " << connection_type << " from name: " << m_thread_name_prefix); _info_c("net/RPClog", "prefix_name = " << prefix_name); diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h index 4cb2003e0..bc2fb1463 100644 --- a/contrib/epee/include/storages/portable_storage_from_bin.h +++ b/contrib/epee/include/storages/portable_storage_from_bin.h @@ -84,9 +84,9 @@ namespace epee inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz) { if(!ptr) - throw tools::runtime_error("throwable_buffer_reader: ptr==nullptr"); + throw std::runtime_error("throwable_buffer_reader: ptr==nullptr"); if(!sz) - throw tools::runtime_error("throwable_buffer_reader: sz==0"); + throw std::runtime_error("throwable_buffer_reader: sz==0"); m_ptr = (uint8_t*)ptr; m_count = sz; m_recursion_count = 0; diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index b9db6d196..3396b8c20 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -33,7 +33,6 @@ #include #include #include -#include "common/exception.h" #include "crypto/hash.h" #include "cryptonote_core/cryptonote_basic.h" #include "cryptonote_core/difficulty.h" @@ -152,7 +151,7 @@ struct output_data_t /*********************************** * Exception Definitions ***********************************/ -class DB_EXCEPTION : public tools::exception +class DB_EXCEPTION : public std::exception { private: std::string m; diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index 4c5e5fd02..964c610cd 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -198,7 +198,7 @@ int main(int argc, char* argv[]) else { LOG_ERROR("Attempted to use non-existent database type: " << db_type); - throw tools::runtime_error("Attempting to use non-existent database type"); + throw std::runtime_error("Attempting to use non-existent database type"); } LOG_PRINT_L0("database: " << db_type); diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 43f6af6d5..1aaf2bddc 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -359,14 +359,14 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path, str1.assign(buffer1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) { - throw tools::runtime_error("Error in deserialization of chunk size"); + throw std::runtime_error("Error in deserialization of chunk size"); } LOG_PRINT_L3("chunk_size: " << chunk_size); if (chunk_size > BUFFER_SIZE) { LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE); - throw tools::runtime_error("Aborting: chunk size exceeds buffer size"); + throw std::runtime_error("Aborting: chunk size exceeds buffer size"); } if (chunk_size > 100000) { @@ -406,7 +406,7 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path, str1.assign(buffer_block, chunk_size); bootstrap::block_package bp; if (! ::serialization::parse_binary(str1, bp)) - throw tools::runtime_error("Error in deserialization of chunk"); + throw std::runtime_error("Error in deserialization of chunk"); int display_interval = 1000; int progress_interval = 10; diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp index 247709f57..da3b44593 100644 --- a/src/blockchain_utilities/bootstrap_file.cpp +++ b/src/blockchain_utilities/bootstrap_file.cpp @@ -117,7 +117,7 @@ bool BootstrapFile::initialize_file() std::string blob; if (! ::serialization::dump_binary(file_magic, blob)) { - throw tools::runtime_error("Error in serialization of file magic"); + throw std::runtime_error("Error in serialization of file magic"); } *m_raw_data_file << blob; @@ -143,7 +143,7 @@ bool BootstrapFile::initialize_file() if (! ::serialization::dump_binary(bd_size, blob)) { - throw tools::runtime_error("Error in serialization of bootstrap::file_info size"); + throw std::runtime_error("Error in serialization of bootstrap::file_info size"); } *output_stream_header << blob; *output_stream_header << bd; @@ -154,7 +154,7 @@ bool BootstrapFile::initialize_file() if (! ::serialization::dump_binary(bd_size, blob)) { - throw tools::runtime_error("Error in serialization of bootstrap::blocks_info size"); + throw std::runtime_error("Error in serialization of bootstrap::blocks_info size"); } *output_stream_header << blob; *output_stream_header << bd; @@ -181,7 +181,7 @@ void BootstrapFile::flush_chunk() std::string blob; if (! ::serialization::dump_binary(chunk_size, blob)) { - throw tools::runtime_error("Error in serialization of chunk size"); + throw std::runtime_error("Error in serialization of chunk size"); } *m_raw_data_file << blob; @@ -197,7 +197,7 @@ void BootstrapFile::flush_chunk() if (static_cast(num_chars_written) != chunk_size) { LOG_PRINT_RED_L0("Error writing chunk: height: " << m_cur_height << " chunk_size: " << chunk_size << " num chars written: " << num_chars_written); - throw tools::runtime_error("Error writing chunk"); + throw std::runtime_error("Error writing chunk"); } m_buffer.clear(); @@ -221,7 +221,7 @@ void BootstrapFile::write_block(block& block) { if (tx_id == null_hash) { - throw tools::runtime_error("Aborting: tx == null_hash"); + throw std::runtime_error("Aborting: tx == null_hash"); } #if SOURCE_DB == DB_MEMORY const transaction* tx = m_blockchain_storage->get_tx(tx_id); @@ -233,14 +233,14 @@ void BootstrapFile::write_block(block& block) if(tx == NULL) { if (! m_tx_pool) - throw tools::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled"); + throw std::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled"); else { transaction tx; if(m_tx_pool->get_transaction(tx_id, tx)) txs.push_back(tx); else - throw tools::runtime_error("Aborting: tx not found in pool"); + throw std::runtime_error("Aborting: tx not found in pool"); } } else @@ -362,16 +362,16 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file) char buf1[2048]; import_file.read(buf1, sizeof(file_magic)); if (! import_file) - throw tools::runtime_error("Error reading expected number of bytes"); + throw std::runtime_error("Error reading expected number of bytes"); str1.assign(buf1, sizeof(file_magic)); if (! ::serialization::parse_binary(str1, file_magic)) - throw tools::runtime_error("Error in deserialization of file_magic"); + throw std::runtime_error("Error in deserialization of file_magic"); if (file_magic != blockchain_raw_magic) { LOG_PRINT_RED_L0("bootstrap file not recognized"); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } else LOG_PRINT_L0("bootstrap file recognized"); @@ -381,20 +381,20 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file) import_file.read(buf1, sizeof(buflen_file_info)); str1.assign(buf1, sizeof(buflen_file_info)); if (! import_file) - throw tools::runtime_error("Error reading expected number of bytes"); + throw std::runtime_error("Error reading expected number of bytes"); if (! ::serialization::parse_binary(str1, buflen_file_info)) - throw tools::runtime_error("Error in deserialization of buflen_file_info"); + throw std::runtime_error("Error in deserialization of buflen_file_info"); LOG_PRINT_L1("bootstrap::file_info size: " << buflen_file_info); if (buflen_file_info > sizeof(buf1)) - throw tools::runtime_error("Error: bootstrap::file_info size exceeds buffer size"); + throw std::runtime_error("Error: bootstrap::file_info size exceeds buffer size"); import_file.read(buf1, buflen_file_info); if (! import_file) - throw tools::runtime_error("Error reading expected number of bytes"); + throw std::runtime_error("Error reading expected number of bytes"); str1.assign(buf1, buflen_file_info); bootstrap::file_info bfi; if (! ::serialization::parse_binary(str1, bfi)) - throw tools::runtime_error("Error in deserialization of bootstrap::file_info"); + throw std::runtime_error("Error in deserialization of bootstrap::file_info"); LOG_PRINT_L0("bootstrap file v" << unsigned(bfi.major_version) << "." << unsigned(bfi.minor_version)); LOG_PRINT_L0("bootstrap magic size: " << sizeof(file_magic)); LOG_PRINT_L0("bootstrap header size: " << bfi.header_size); @@ -412,7 +412,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) if (!boost::filesystem::exists(raw_file_path, ec)) { LOG_PRINT_L0("bootstrap file not found: " << raw_file_path); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } std::ifstream import_file; import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in); @@ -421,7 +421,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) if (import_file.fail()) { LOG_PRINT_L0("import_file.open() fail"); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } uint64_t full_header_size; // 4 byte magic + length of header structures @@ -456,7 +456,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) str1.assign(buf1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) - throw tools::runtime_error("Error in deserialization of chunk_size"); + throw std::runtime_error("Error in deserialization of chunk_size"); LOG_PRINT_L3("chunk_size: " << chunk_size); if (chunk_size > BUFFER_SIZE) @@ -464,7 +464,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) std::cout << refresh_string; LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE << " height: " << h-1); - throw tools::runtime_error("Aborting: chunk size exceeds buffer size"); + throw std::runtime_error("Aborting: chunk size exceeds buffer size"); } if (chunk_size > 100000) { @@ -475,7 +475,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) else if (chunk_size <= 0) { std::cout << refresh_string; LOG_PRINT_L0("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } // skip to next expected block size value import_file.seekg(chunk_size, std::ios_base::cur); @@ -483,7 +483,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) std::cout << refresh_string; LOG_PRINT_L0("ERROR: unexpected end of file: bytes read before error: " << import_file.gcount() << " of chunk_size " << chunk_size); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } bytes_read += chunk_size; diff --git a/src/blockchain_utilities/fake_core.h b/src/blockchain_utilities/fake_core.h index 3840a1c13..2fb5031d3 100644 --- a/src/blockchain_utilities/fake_core.h +++ b/src/blockchain_utilities/fake_core.h @@ -78,7 +78,7 @@ struct fake_core_db else { LOG_ERROR("Attempted to use non-existent database type: " << db_type); - throw tools::runtime_error("Attempting to use non-existent database type"); + throw std::runtime_error("Attempting to use non-existent database type"); } boost::filesystem::path folder(path); @@ -176,7 +176,7 @@ struct fake_core_memory { // TODO: // would need to refactor handle_block_to_main_chain() to have a direct add_block() method like Blockchain class - throw tools::runtime_error("direct add_block() method not implemented for in-memory db"); + throw std::runtime_error("direct add_block() method not implemented for in-memory db"); return 2; } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5537900ae..2289704e5 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -31,7 +31,6 @@ set(common_sources command_line.cpp dns_utils.cpp util.cpp - exception.cpp i18n.cpp) set(common_headers) @@ -49,7 +48,6 @@ set(common_private_headers unordered_containers_boost_serialization.h util.h varint.h - exception.h i18n.h) bitmonero_private_headers(common @@ -62,7 +60,6 @@ target_link_libraries(common LINK_PRIVATE crypto ${UNBOUND_LIBRARY} - ${LIBUNWIND_LIBRARIES} ${Boost_DATE_TIME_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} diff --git a/src/common/exception.cpp b/src/common/exception.cpp deleted file mode 100644 index f8954329f..000000000 --- a/src/common/exception.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2016, 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 "common/exception.h" -#include "misc_log_ex.h" -#define UNW_LOCAL_ONLY -#include -#include - -namespace tools -{ - -void log_stack_trace(const char *msg) -{ -#ifdef HAVE_LIBUNWIND - unw_context_t ctx; - unw_cursor_t cur; - unw_word_t ip, off; - unsigned level; - char sym[512], *dsym; - int status; - - if (msg) - LOG_PRINT_L0(msg); - LOG_PRINT_L0("Unwinded call stack:"); - if (unw_getcontext(&ctx) < 0) { - LOG_PRINT_L0("Failed to create unwind context"); - return; - } - if (unw_init_local(&cur, &ctx) < 0) { - LOG_PRINT_L0("Failed to find the first unwind frame"); - return; - } - for (level = 1; level < 999; ++level) { // 999 for safety - int ret = unw_step(&cur); - if (ret < 0) { - LOG_PRINT_L0("Failed to find the next frame"); - return; - } - if (ret == 0) - break; - if (unw_get_reg(&cur, UNW_REG_IP, &ip) < 0) { - LOG_PRINT_L0(" " << std::setw(4) << level); - continue; - } - if (unw_get_proc_name(&cur, sym, sizeof(sym), &off) < 0) { - LOG_PRINT_L0(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip); - continue; - } - dsym = abi::__cxa_demangle(sym, NULL, NULL, &status); - LOG_PRINT_L0(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip << " " << (!status && dsym ? dsym : sym) << " + " << "0x" << off); - free(dsym); - } -#else -#warning libunwind disabled, no stack traces -#endif -} - -} // namespace tools diff --git a/src/common/exception.h b/src/common/exception.h deleted file mode 100644 index 93e0d4013..000000000 --- a/src/common/exception.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2016, 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. - -#ifndef MONERO_EXCEPTION_H -#define MONERO_EXCEPTION_H - -#include -#include - -namespace tools -{ - -void log_stack_trace(const char *msg); - -class exception: public std::exception { -public: - exception() { log_stack_trace(what()); } -}; - -class runtime_error: public std::runtime_error { -public: - explicit runtime_error(const std::string &s): std::runtime_error(s) { log_stack_trace(what()); } - explicit runtime_error(const char *s): std::runtime_error(s) { log_stack_trace(what()); } -}; - -} // namespace tools - -#endif diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index e25f80116..878202cf1 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -41,7 +41,6 @@ #include "syncobj.h" #include "string_tools.h" -#include "common/exception.h" #include "tx_pool.h" #include "cryptonote_basic.h" #include "common/util.h" @@ -315,7 +314,7 @@ namespace cryptonote "m_invalid_blocks: " << m_invalid_blocks.size() << ENDL << "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); - throw tools::runtime_error("Blockchain data corruption"); + throw std::runtime_error("Blockchain data corruption"); } } } diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp index 41246e8d8..41f2321d5 100644 --- a/src/cryptonote_core/checkpoints_create.cpp +++ b/src/cryptonote_core/checkpoints_create.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "checkpoints_create.h" #include "common/dns_utils.h" #include "include_base_utils.h" diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 907f9d803..6f0fe88a4 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -161,7 +161,7 @@ namespace cryptonote cryptonote::checkpoints checkpoints; if (!cryptonote::create_checkpoints(checkpoints)) { - throw tools::runtime_error("Failed to initialize checkpoints"); + throw std::runtime_error("Failed to initialize checkpoints"); } set_checkpoints(std::move(checkpoints)); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 186c1c93b..32f0b2ad4 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -36,7 +36,6 @@ #include #include -#include #include "p2p/net_node_common.h" #include "cryptonote_protocol/cryptonote_protocol_handler_common.h" #include "storages/portable_storage_template_helper.h" diff --git a/src/cryptonote_core/miner.cpp b/src/cryptonote_core/miner.cpp index 7bc126cd8..bad3f30bd 100644 --- a/src/cryptonote_core/miner.cpp +++ b/src/cryptonote_core/miner.cpp @@ -34,7 +34,6 @@ #include #include #include -#include "common/exception.h" #include "misc_language.h" #include "include_base_utils.h" #include "cryptonote_basic_impl.h" diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 2112b5082..1c92958c9 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -38,7 +38,6 @@ #include #include -#include "common/exception.h" #include "storages/levin_abstract_invoke2.h" #include "warnings.h" #include "cryptonote_protocol_defs.h" diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index c48b836e9..0b42257e7 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -26,7 +26,6 @@ // 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 "common/exception.h" #include "cryptonote_core/cryptonote_basic_impl.h" #include "daemon/command_parser_executor.h" diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 7e5139636..206de9d4a 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -26,7 +26,6 @@ // 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 "common/exception.h" #include "cryptonote_config.h" #include "version.h" #include "daemon/command_server.h" diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index d44538358..e79823d08 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -110,7 +110,7 @@ bool t_daemon::run(bool interactive) { if (nullptr == mp_internals) { - throw tools::runtime_error{"Can't run stopped daemon"}; + throw std::runtime_error{"Can't run stopped daemon"}; } tools::signal_handler::install(std::bind(&daemonize::t_daemon::stop_p2p, this)); @@ -155,7 +155,7 @@ void t_daemon::stop() { if (nullptr == mp_internals) { - throw tools::runtime_error{"Can't stop stopped daemon"}; + throw std::runtime_error{"Can't stop stopped daemon"}; } mp_internals->p2p.stop(); mp_internals->rpc.stop(); @@ -166,7 +166,7 @@ void t_daemon::stop_p2p() { if (nullptr == mp_internals) { - throw tools::runtime_error{"Can't send stop signal to a stopped daemon"}; + throw std::runtime_error{"Can't send stop signal to a stopped daemon"}; } mp_internals->p2p.get().send_stop_signal(); } diff --git a/src/daemon/p2p.h b/src/daemon/p2p.h index b74a5e72d..3858989ce 100644 --- a/src/daemon/p2p.h +++ b/src/daemon/p2p.h @@ -60,7 +60,7 @@ public: LOG_PRINT_L0("Initializing p2p server..."); if (!m_server.init(vm)) { - throw tools::runtime_error("Failed to initialize p2p server."); + throw std::runtime_error("Failed to initialize p2p server."); } LOG_PRINT_L0("P2p server initialized OK"); } diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h index 5f6c317b1..8e2add4a2 100644 --- a/src/daemon/protocol.h +++ b/src/daemon/protocol.h @@ -50,7 +50,7 @@ public: LOG_PRINT_L0("Initializing cryptonote protocol..."); if (!m_protocol.init(vm)) { - throw tools::runtime_error("Failed to initialize cryptonote protocol."); + throw std::runtime_error("Failed to initialize cryptonote protocol."); } LOG_PRINT_L0("Cryptonote protocol initialized OK"); } diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h index caeae9a3d..bfd2afd84 100644 --- a/src/daemon/rpc.h +++ b/src/daemon/rpc.h @@ -55,7 +55,7 @@ public: LOG_PRINT_L0("Initializing core rpc server..."); if (!m_server.init(vm)) { - throw tools::runtime_error("Failed to initialize core rpc server."); + throw std::runtime_error("Failed to initialize core rpc server."); } LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_server.get_binded_port(), LOG_LEVEL_0); } @@ -65,7 +65,7 @@ public: LOG_PRINT_L0("Starting core rpc server..."); if (!m_server.run(2, false)) { - throw tools::runtime_error("Failed to start core rpc server."); + throw std::runtime_error("Failed to start core rpc server."); } LOG_PRINT_L0("Core rpc server started ok"); } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index b57c60948..15ddc081f 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "string_tools.h" #include "common/scoped_message_writer.h" #include "daemon/rpc_command_executor.h" @@ -89,7 +88,7 @@ t_rpc_command_executor::t_rpc_command_executor( { if (rpc_server == NULL) { - throw tools::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null"); + throw std::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null"); } } diff --git a/src/daemonizer/posix_fork.cpp b/src/daemonizer/posix_fork.cpp index 84ff88869..c068912ec 100644 --- a/src/daemonizer/posix_fork.cpp +++ b/src/daemonizer/posix_fork.cpp @@ -4,7 +4,6 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "common/exception.h" #include "daemonizer/posix_fork.h" #include "misc_log_ex.h" @@ -21,7 +20,7 @@ namespace { void quit(std::string const & message) { LOG_ERROR(message); - throw tools::runtime_error(message); + throw std::runtime_error(message); } } diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp index 19db3f534..ba956d90b 100644 --- a/src/miner/simpleminer.cpp +++ b/src/miner/simpleminer.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "common/command_line.h" #include "misc_log_ex.h" #include "simpleminer.h" diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index d3ff0ca8e..ca0726c5f 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -33,7 +33,6 @@ #include #include #include -#include "common/exception.h" #include "../../contrib/otshell_utils/utils.hpp" namespace epee @@ -44,7 +43,7 @@ namespace net_utils boost::call_once(m_singleton, [] { _info_c("dbg/data","Creating singleton of data_logger"); - if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw tools::runtime_error("data_logger singleton"); } + if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw std::runtime_error("data_logger singleton"); } m_state = data_logger_state::state_during_init; m_obj.reset(new data_logger()); m_state = data_logger_state::state_ready_to_use; @@ -53,7 +52,7 @@ namespace net_utils if (m_state != data_logger_state::state_ready_to_use) { _erro ("trying to use not working data_logger"); - throw tools::runtime_error("data_logger ctor state"); + throw std::runtime_error("data_logger ctor state"); } return * m_obj; @@ -61,7 +60,7 @@ namespace net_utils data_logger::data_logger() { _note_c("dbg/data","Starting data logger (for graphs data)"); - if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw tools::runtime_error("data_logger ctor state"); } + if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw std::runtime_error("data_logger ctor state"); } boost::lock_guard lock(mMutex); // lock // prepare all the files for given data channels: diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index eb12f52ed..ea1993c80 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -561,7 +561,7 @@ bool simple_wallet::set_variable(const std::vector &args) { if (args.empty()) { - fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, store-tx-info, default-mixin, auto-refresh, refresh-type"); + fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, default-mixin, auto-refresh, refresh-type"); return true; } else diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ef17a770b..2afe08cb1 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -32,7 +32,6 @@ #include #include -#include "common/exception.h" #include "include_base_utils.h" using namespace epee; @@ -804,7 +803,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re // handle error from async fetching thread if (error) { - throw tools::runtime_error("proxy exception in refresh thread"); + throw std::runtime_error("proxy exception in refresh thread"); } } catch (const std::exception&) @@ -2013,7 +2012,7 @@ std::vector wallet2::create_transactions(std::vector ptx_vector; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0961ad981..f798f404d 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -35,7 +35,6 @@ #include #include -#include "common/exception.h" #include "include_base_utils.h" #include "cryptonote_core/account.h" #include "cryptonote_core/account_boost_serialization.h" diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 0cb253398..0644e3690 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "wallet2_api.h" #include "wallet2.h" #include "mnemonics/electrum-words.h" diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 22f4c0421..0315fc8c8 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -82,7 +82,7 @@ namespace tests bool on_idle(){return true;} bool find_blockchain_supplement(const std::list& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} - cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } + cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } bool get_test_drop_download() {return true;} bool get_test_drop_download_height() {return true;} bool prepare_handle_incoming_blocks(const std::list &blocks) { return true; } diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index b897d9237..4fdd0a600 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -58,7 +58,7 @@ void test_generator::get_block_chain(std::vector& blockchain, const auto it = m_blocks_info.find(curr); if (m_blocks_info.end() == it) { - throw tools::runtime_error("block hash wasn't found"); + throw std::runtime_error("block hash wasn't found"); } blockchain.push_back(it->second); @@ -82,7 +82,7 @@ uint64_t test_generator::get_already_generated_coins(const crypto::hash& blk_id) { auto it = m_blocks_info.find(blk_id); if (it == m_blocks_info.end()) - throw tools::runtime_error("block hash wasn't found"); + throw std::runtime_error("block hash wasn't found"); return it->second.already_generated_coins; } @@ -323,7 +323,7 @@ bool init_output_indices(map_output_idx_t& outs, std::mapsecond); } @@ -486,11 +486,11 @@ void fill_tx_sources_and_destinations(const std::vector& event destinations.clear(); if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix)) - throw tools::runtime_error("couldn't fill transaction sources"); + throw std::runtime_error("couldn't fill transaction sources"); tx_destination_entry de; if (!fill_tx_destination(de, to, amount)) - throw tools::runtime_error("couldn't fill transaction destination"); + throw std::runtime_error("couldn't fill transaction destination"); destinations.push_back(de); tx_destination_entry de_change; @@ -498,7 +498,7 @@ void fill_tx_sources_and_destinations(const std::vector& event if (0 < cache_back) { if (!fill_tx_destination(de_change, from, cache_back)) - throw tools::runtime_error("couldn't fill transaction cache back destination"); + throw std::runtime_error("couldn't fill transaction cache back destination"); destinations.push_back(de_change); } } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index d51d9d320..d0d912cbb 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -284,7 +284,7 @@ bool do_check_tx_verification_context(const cryptonote::tx_verification_context& { // Default block verification context check if (tvc.m_verifivation_failed) - throw tools::runtime_error("Transaction verification failed"); + throw std::runtime_error("Transaction verification failed"); return true; } //-------------------------------------------------------------------------- @@ -307,7 +307,7 @@ bool do_check_block_verification_context(const cryptonote::block_verification_co { // Default block verification context check if (bvc.m_verifivation_failed) - throw tools::runtime_error("Block verification failed"); + throw std::runtime_error("Block verification failed"); return true; } //-------------------------------------------------------------------------- @@ -621,7 +621,7 @@ inline bool do_replay_file(const std::string& filename) if (!tools::serialize_obj_to_file(events, filename)) \ { \ std::cout << concolor::magenta << "Failed to serialize data to file: " << filename << concolor::normal << std::endl; \ - throw tools::runtime_error("Failed to serialize data to file"); \ + throw std::runtime_error("Failed to serialize data to file"); \ } \ } diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 41d5f1e26..f72c906e5 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -156,7 +156,7 @@ namespace } } - throw tools::runtime_error("invalid public key wasn't found"); + throw std::runtime_error("invalid public key wasn't found"); return crypto::public_key(); } } diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp index 360261676..56089a4da 100644 --- a/tests/net_load_tests/clt.cpp +++ b/tests/net_load_tests/clt.cpp @@ -37,7 +37,6 @@ #include "gtest/gtest.h" -#include "common/exception.h" #include "include_base_utils.h" #include "misc_language.h" #include "misc_log_ex.h" diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp index 13b31215e..d8d3eae2e 100644 --- a/tests/net_load_tests/srv.cpp +++ b/tests/net_load_tests/srv.cpp @@ -31,7 +31,6 @@ #include #include -#include "common/exception.h" #include "include_base_utils.h" #include "misc_log_ex.h" #include "storages/levin_abstract_invoke2.h" diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp index 5d40e90cf..a5ce244d9 100644 --- a/tests/unit_tests/ban.cpp +++ b/tests/unit_tests/ban.cpp @@ -56,7 +56,7 @@ public: bool on_idle(){return true;} bool find_blockchain_supplement(const std::list& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} - cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); } + cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); } bool get_test_drop_download() const {return true;} bool get_test_drop_download_height() const {return true;} bool prepare_handle_incoming_blocks(const std::list &blocks) { return true; } diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp index b68ce77bb..946db292d 100644 --- a/tests/unit_tests/epee_boosted_tcp_server.cpp +++ b/tests/unit_tests/epee_boosted_tcp_server.cpp @@ -104,7 +104,7 @@ TEST(boosted_tcp_server, worker_threads_are_exception_resistant) // 2 theads, but 4 exceptions ASSERT_TRUE(srv.run_server(2, false)); - ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw tools::runtime_error("test 1"); })); + ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::runtime_error("test 1"); })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::string("test 2"); })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw "test 3"; })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw 4; })); diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp index 3bf1df7ed..3dc5db7d4 100644 --- a/tests/unit_tests/mnemonics.cpp +++ b/tests/unit_tests/mnemonics.cpp @@ -27,7 +27,6 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gtest/gtest.h" -#include "common/exception.h" #include "mnemonics/electrum-words.h" #include "crypto/crypto.h" #include diff --git a/tests/unit_tests/test_protocol_pack.cpp b/tests/unit_tests/test_protocol_pack.cpp index 1ff70b4d9..a9a1a34a6 100644 --- a/tests/unit_tests/test_protocol_pack.cpp +++ b/tests/unit_tests/test_protocol_pack.cpp @@ -30,7 +30,6 @@ #include "gtest/gtest.h" -#include "common/exception.h" #include "include_base_utils.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "storages/portable_storage_template_helper.h" -- cgit v1.2.3 From eda51a0dc36946af9528ee82216d73330587e145 Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Mon, 21 Mar 2016 12:53:49 +0200 Subject: set fork date for September, add hyc's GPG key, remove aabramov's --- src/cryptonote_core/blockchain.cpp | 3 +++ utils/gpg_keys/aabramov.asc | 31 --------------------------- utils/gpg_keys/hyc.asc | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 31 deletions(-) delete mode 100644 utils/gpg_keys/aabramov.asc create mode 100644 utils/gpg_keys/hyc.asc (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 8b7f298ee..cec4feece 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -81,6 +81,9 @@ static const struct { // version 2 starts from block 1009827, which is on or around the 20th of March, 2016. Fork time finalised on 2015-09-20. No fork voting occurs for the v2 fork. { 2, 1009827, 0, 1442763710 }, + + // version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21. + { 3, 1009827, 0, 1442763710 }, }; static const uint64_t mainnet_hard_fork_version_1_till = 1009826; diff --git a/utils/gpg_keys/aabramov.asc b/utils/gpg_keys/aabramov.asc deleted file mode 100644 index 1626f95b2..000000000 --- a/utils/gpg_keys/aabramov.asc +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 - -mQENBFQwICMBCACyHKYHaSEdNyE8kqYm+V37IsX5xxqMTkOCuVmaWt8i8FP2aPDz -TgsITQ8tHoJubL0wh/y6Z/KQY8cSWT/JU39gP64I1XdGVgaPErF3kZ7n2jh+K5HY -vBWrFvw4Xj2XvHaJZW6rVVX5dc4rxqnnOjfKTPI6/tQhT16dwbMuCyZOyMfStAF9 -q+14I9M2MAbMlgNO0el0aR3GMVjoDeaWBk/qWxTaHjyOBAVyryoFpwIl7Gmwkk1d -+jv4542LjJOiiwBEDcWUmNvlsRk5sXMcXImJSpaCN1Ta9Eyu2NBIK/qAbuC6YgLe -nn/0DaA7TOpeIMU/WNq/Dpbathst+fMJNK6BABEBAAG0JkFsZXhhbmRlciBBYnJh -bW92IDxhYWJyYW1vdkBnbWFpbC5jb20+iQE+BBMBAgAoBQJUMCAjAhsDBQkDwmcA -BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA/57nKbsMV+F/+B/9f7C1iiEFD -18Af48WLJXZaJJTqxMeWzztWhZ2LS27rFOGJcj50UeON7aVu8LWU8gvyPJct6wJA -T1hvPWc6TTsbYp8KHP/nUfUWWV+np0qVSj91eGHp7NjAxXYe4NnWt1JUtINxvNll -BKY2l0MHHHKwuWxky6zug48CToB8Y0RBDUgFM0pmnCzmySs6OAJbLmnnvesTDFZk -m6wycq4/SrbVByTZHVqBmZNnypMQxbqXTti9ltpXWqO89RpQQ+QBQQlrNy9QRHJq -VW9Qn5eL4O4IdmXpHqln1ppSu2il+pqQCGc5O9xFxqG6YRHljQEngBfgKLxOsqa1 -OGJHu1pLyUYRuQENBFQwICMBCACmQ+1DRgm9AMNo4iDur47obDzUTQ/1g2ah1+AT -IYNhhltBD3jURsRZ6lMeancxU2/6hyUzCon5ETKfnF0+ujqldSDuo+XY9CDgmXLC -s3wPAKZvyjScwMFTyW1hGfyT9SFwYVDaXOeW+VrJ97Xh5FWHx8LU7eieYIl8tOUY -YWEeIps/y5zBkk7bB4LVNVc3AlKPS4vb/py5szA5fMg8ix/ggvpq8be4BnImP3a1 -yrl+W9HUtcTs8jBnFLMoZYaUklZ9LR7yfnjhhtKqW833UB07qYQY//dJGy4kVnit -M5LX9VKa+wnWsgP+w5jElPX0bweV6+V/yFRhjLLwV7dv/MJnABEBAAGJASUEGAEC -AA8FAlQwICMCGwwFCQPCZwAACgkQP+e5ym7DFfgrvAf/bnQD5iR/HiNsH0HQE96G -Wsrr9VW/ucnm06pd1D/r7ogYcVWuNIglx3QdvFla4uZDvYR0PhyjNrOyPzUgLWp/ -fjQw9buyI3BawAScbPuN06zHLUIvDQpaPq2+uBRq7sCcdsox6sMiUH6x5QcD3lbR -nh6aAGwSkTabW5a/GVZTIHSicGbhXUaIIh3w+sQZ/y5xTVjgVi4I4XdrxOZoo5RN -nF5oyn74n5p9euxJMWgvC/tz/bD7VKYWJHRnuyeumLTPudLjPFFQpTX+I+gMJ5FT -Vs7byaOlrZbQxzXd4G0uBnCvJ1FH3cL6Ddqlsz/l2WzddMknMbVMn7+fSVMdpbIm -hw== -=7XDh ------END PGP PUBLIC KEY BLOCK----- diff --git a/utils/gpg_keys/hyc.asc b/utils/gpg_keys/hyc.asc new file mode 100644 index 000000000..4d174e989 --- /dev/null +++ b/utils/gpg_keys/hyc.asc @@ -0,0 +1,44 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQGiBERuNuERBACY9KGBcxSvy6D9Sxk51L59/7ACWQf/Mk2B5jWCxcadEZHokKf4 +mYBBH963B1v04S8QKsm1avt4amS3dEEfxJ920RWtg5XkVCW0HfErsZ58XobIcPLD +pd7u3btGHObQfJ5fzyRuIaWpBg59gGJAw13Rz/ILuDpXHBP0ppI9OOq6nwCgnG+I +B56YTz9oGLiVXFsa8LItTI0D/jBTd5UWQ+BYCU8HdHq+fRm6l/N921yrFO4hF1jU +4Mi6t9srHkQVW5ro9cxVhAWKCbVum5ogylcfH1WK//R2HkSdKJXNVxZdBieGD/tL +YYSJj3qU7UA9ZTH5QGUkNqcHH7bV+o+5oZdhIhpcMuG1TFudGkQcnTWW0X69S6bR +uBa1A/9Zg6Hk2uL0ytbHtASWKZHr80f1hhe6catT314nqJNU5rufYHHHCvQJVDPs +NWkj4OfkBE5xG1VxMPulvMTJIKm1FdXK+1B9OfcXUk/+zyCiYLGbrAjuUlHDmVDH +P1YQEn+a8S8QowXl+tAL62lO3mDCiPny6ohuIJiTfLLPrE1+bLQaSG93YXJkIENo +dSA8aHljQHN5bWFzLmNvbT6IRgQQEQIABgUCRukakgAKCRCZSHtC+KtbW2rTAJ9/ +j5IiB0Fvq7gAs2Zf/eqc4wqLzwCeLicSAHhaXSRrKd7ZEFTnAFW/qWSIRgQQEQIA +BgUCSDbdawAKCRBsEnep072iJdceAJ44GfpthT4ZPN8XEob5pn8qsFPKIgCfbcNI +wsWoHybiovYiHBZTpW50/QqIRgQQEQIABgUCSDbe8wAKCRBDbTC1hOUd3UFUAKCn +CAhM4Hpe2QNGZM8lYewn2bVRogCeKs5eOlG4vqzYsH1ro1evBsKFXLyIZAQTEQIA +JAUCRG424QIbAwUJEswDAAYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRD9KnC0SrEb +p72rAJ44Keweij6d4EFjROG6PdF8J64vYACfZ99qH7+wzvBxaMuAIAw558lBaY2I +XgQTEQIAHgIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAUCVpAQGAAKCRD9KnC0SrEb +p+3XAJwNjg2sFjNTwzf5LaTT/wl2sWwqbgCgiX9jv1OS+pzJHH4OpjTt5+lHuUO5 +AQ0ERG424RAEAIrOpREkyhB6FTmYo+Tw3r1/pfO0gHC1FcuTrL0lsRVOYwiwVwmk +gVME4gvHRNqnT1gG/RMQm6kKGz07RvzVaRrrT7B/nOG9kbVMzRQIqBbk1o+u7TFr +EYSvXF9xfl3Sq2/UYqIURCW9ZIOF6JLGcF0qGrhheg9eDq97tAfZDwvXAAMFA/4u +38QVNe0Izqc9FTGkO6VijsfXvsn3tCKqm7v/vkJa8Rpu3dumChwMtiGwkzLCJMpC +TbnL0dW4hChHjT/DOWKV84WZwP6vmuMlhNFFrsRh9wqi6LjBNdhVHHfjx2JU0R4L +kID4FSiU20TH4Z/Vm+JSC1E272kw3xfacga4e3DpN4hPBBgRAgAPBQJEbjbhAhsM +BQkSzAMAAAoJEP0qcLRKsRun3wAAn1BnosO00oGZ0sVX5N+m8haWI6YeAJ9HV/RG +L4t04ykgAnU8LLAOaNCWV7kCDQRWkBA0EAgAmQ81PiXqJmk475469zKLWyxjrvG/ +utPTzE4jgah7Ib3I591J6cGmpoOWeM9bdaLc2DGxWqpjcZd/6dFo4CyIFLMPXsgv +JH0iwh5gUt/YBUHkz3kVpN+UqoE+5d+6LVoJQrio/lHAUpFBtpnrx2BeolWRmG6m +uTQwOkyNXUbFgSIwpKuN1rqe2U4KuvFEBTX1QCCzGIOEYtbmtBdGtg/FLwt/+pIF +QHY4tQe/bykX+XLYyLCChoq5Kkq+KZv0Ebafg3vm+xUMwbeqQwUNFLPjIFpHeeKi +nQk8BPNvFjf+MmZ/y/tbsA/156WfMldHsXOV/nD6JWk2HPv8/BL7Fz4bvwADBQf+ +M+6GDIWUpZFfix7eDBZhtyNbehQ6sqSGu97LljKZXb0SxOM5jTkAguuVmjOM8bi4 +cVs9LJt1nFD+PmNRLuju4tda4xk61fvueqv1T0c59fFak5STejzrpWhDeEJZmJMw +EwSv4e0OTFsKlmWJSvfoOavPhbw+Tuhgza1WFLjedqo+RQnCQmXMNlcblD6otgSV +X1uadZBWODmHX/nBmgyDzSILZsy3mJkspAIx/bH95oTMaGQAkVH++WLLGUmjr6tb +uru3e8+mCUvpEptaaBcIq8minoVvfkIZKUgISKf4Yize1PoEuCQbnETcfekZyY94 +m/RwmduzBwMXzMikPOyRwYhPBBgRAgAPBQJWkBA0AhsMBQkSzAMAAAoJEP0qcLRK +sRunqSUAnRenNWORvzTRRy0qmF5xVFlDIUGpAJ4pUZgkE7YRyjSzdhxcaRBOjAQa +GQ== +=sUzZ +-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file -- cgit v1.2.3 From 23d1538fe70d76817f6f6e07908e93bfd232d30c Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Mon, 21 Mar 2016 13:09:35 +0200 Subject: also update the timestamp for the hard fork --- src/cryptonote_core/blockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index cec4feece..5a7c9ba5a 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -83,7 +83,7 @@ static const struct { { 2, 1009827, 0, 1442763710 }, // version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21. - { 3, 1009827, 0, 1442763710 }, + { 3, 1009827, 0, 1458558528 }, }; static const uint64_t mainnet_hard_fork_version_1_till = 1009826; -- cgit v1.2.3 From a1c38299b3d8a1826bf4f2b31853c195bff2619d Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Mon, 21 Mar 2016 13:19:49 +0200 Subject: also maybe do the block height this time, you know, just so that it actually works. --- src/cryptonote_core/blockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 5a7c9ba5a..00bae3741 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -83,7 +83,7 @@ static const struct { { 2, 1009827, 0, 1442763710 }, // version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21. - { 3, 1009827, 0, 1458558528 }, + { 3, 1141317, 0, 1458558528 }, }; static const uint64_t mainnet_hard_fork_version_1_till = 1009826; -- cgit v1.2.3 From 8438aeb7403b5a1b4cb0efdd1cbeb03be23d67ea Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Mon, 21 Mar 2016 23:10:48 +0200 Subject: update version number --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/version.h.in b/src/version.h.in index 073129810..a0832db91 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define MONERO_VERSION_TAG "@VERSIONTAG@" -#define MONERO_VERSION "0.9.2.0" +#define MONERO_VERSION "0.9.3.0" #define MONERO_RELEASE_NAME "Hydrogen Helix" #define MONERO_VERSION_FULL MONERO_VERSION "-" MONERO_VERSION_TAG -- cgit v1.2.3 From cc4b19c32ede3c377597ff8cb9e7e6a86a9cdfa2 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 22 Mar 2016 15:37:16 +0000 Subject: blockchain: fix partial block reward detection --- src/cryptonote_core/blockchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 00bae3741..131f56a4d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -984,9 +984,9 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl // to show the amount of coins that were actually generated, the remainder will be pushed back for later // emission. This modifies the emission curve very slightly. CHECK_AND_ASSERT_MES(money_in_use - fee <= base_reward, false, "base reward calculation bug"); - base_reward = money_in_use - fee; if(base_reward + fee != money_in_use) partial_block_reward = true; + base_reward = money_in_use - fee; } return true; } -- cgit v1.2.3 From 3a484497bc3b363aabbb0170c4334bb5176b4769 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Thu, 24 Sep 2015 11:00:46 -0400 Subject: Updated documentation for blockchain.* All functions are now documented in doxygen format. Comments have been updated to reflect the current state of the code. Many areas for improvement in clarity and design have been noted, as well as cruft to be removed. These changes are not reflected in this commit both to allow time for comment and to keep commits organized by purpose. --- src/cryptonote_core/blockchain.cpp | 40 +- src/cryptonote_core/blockchain.h | 899 ++++++++++++++++++++++++++++++++++++- 2 files changed, 925 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 00bae3741..a55a435b3 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -352,6 +352,7 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const cryptonote::te // we only need 1 m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service)); + //TODO: move this block into separate functions? #if defined(PER_BLOCK_CHECKPOINT) if (!fakechain) load_compiled_in_block_hashes(); @@ -840,7 +841,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list blocks, starting at -// and return by reference . +// get the block sizes of the last blocks, and return by reference . void Blockchain::get_last_n_blocks_sizes(std::vector& sz, size_t count) const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -1408,6 +1408,10 @@ bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::list missed_tx_ids; std::list txs; + + // FIXME: s/rsp.missed_ids/missed_tx_id/ ? Seems like rsp.missed_ids + // is for missed blocks, not missed transactions as well. get_transactions(bl.tx_hashes, txs, missed_tx_ids); if (missed_tx_ids.size() != 0) @@ -1668,6 +1675,8 @@ uint64_t Blockchain::block_difficulty(uint64_t i) const return 0; } //------------------------------------------------------------------ +//TODO: return type should be void, throw on exception +// alternatively, return true only if no blocks missed template bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const { @@ -1692,6 +1701,8 @@ bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container return true; } //------------------------------------------------------------------ +//TODO: return type should be void, throw on exception +// alternatively, return true only if no transactions missed template bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const { @@ -1708,7 +1719,6 @@ bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container { missed_txs.push_back(tx_hash); } - //FIXME: is this the correct way to handle this? catch (const std::exception& e) { return false; @@ -1965,6 +1975,11 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vectorheight() < m_blocks_hash_check.size() && kept_by_block) { TIME_MEASURE_START(a); @@ -2038,6 +2054,10 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const } //------------------------------------------------------------------ // This function validates transaction inputs and their keys. +// FIXME: consider moving functionality specific to one input into +// check_tx_input() rather than here, and use this function simply +// to iterate the inputs as necessary (splitting the task +// using threads, etc.) bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height) { LOG_PRINT_L3("Blockchain::" << __func__); @@ -2320,7 +2340,7 @@ bool Blockchain::check_tx_input(const txin_to_key& txin, const crypto::hash& tx_ output_keys.clear(); - //check ring signature + // collect output keys outputs_visitor vi(output_keys, *this); if (!scan_outputkeys_for_indexes(txin, vi, tx_prefix_hash, pmax_related_block_height)) { @@ -2617,6 +2637,11 @@ leave: txs.push_back(tx); TIME_MEASURE_START(dd); + // FIXME: the storage should not be responsible for validation. + // If it does any, it is merely a sanity check. + // Validation is the purview of the Blockchain class + // - TW + // // ND: this is not needed, db->add_block() checks for duplicate k_images and fails accordingly. // if (!check_for_double_spend(tx, keys)) // { @@ -2797,6 +2822,8 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc return handle_block_to_main_chain(bl, id, bvc); } //------------------------------------------------------------------ +//TODO: Refactor, consider returning a failure height and letting +// caller decide course of action. void Blockchain::check_against_checkpoints(const checkpoints& points, bool enforce) { const auto& pts = points.get_points(); @@ -2878,6 +2905,8 @@ void Blockchain::block_longhash_worker(const uint64_t height, const std::vector< TIME_MEASURE_START(t); slow_hash_allocate_state(); + //FIXME: height should be changing here, as get_block_longhash expects + // the height of the block passed to it for (const auto & block : blocks) { crypto::hash id = get_block_hash(block); @@ -2933,6 +2962,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) } //------------------------------------------------------------------ +//FIXME: unused parameter txs void Blockchain::output_scan_worker(const uint64_t amount, const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const { try diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index ab2c8f9e8..98a58c540 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -60,11 +60,14 @@ namespace cryptonote class tx_memory_pool; struct test_options; + /** Declares ways in which the BlockchainDB backend should be told to sync + * + */ enum blockchain_db_sync_mode { - db_sync, - db_async, - db_nosync + db_sync, //!< handle syncing calls instead of the backing db, synchronously + db_async, //!< handle syncing calls instead of the backing db, asynchronously + db_nosync //!< Leave syncing up to the backing db (safest, but slowest because of disk I/O) }; /************************************************************************/ @@ -73,6 +76,9 @@ namespace cryptonote class Blockchain { public: + /** + * @brief Now-defunct (TODO: remove) struct from in-memory blockchain + */ struct transaction_chain_entry { transaction tx; @@ -81,127 +87,700 @@ namespace cryptonote std::vector m_global_output_indexes; }; + /** + * @brief container for passing a block and metadata about it on the blockchain + */ struct block_extended_info { - block bl; - uint64_t height; - size_t block_cumulative_size; - difficulty_type cumulative_difficulty; - uint64_t already_generated_coins; + block bl; //!< the block + uint64_t height; //!< the height of the block in the blockchain + size_t block_cumulative_size; //!< the size (in bytes) 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 }; + /** + * @brief Blockchain constructor + * + * @param tx_pool a reference to the transaction pool to be kept by the Blockchain + */ Blockchain(tx_memory_pool& tx_pool); + /** + * @brief Initialize the Blockchain state + * + * @param db a pointer to the backing store to use for the blockchain + * @param testnet true if on testnet, else false + * @param test_options test parameters + * + * @return true on success, false if any initialization steps fail + */ bool init(BlockchainDB* db, const bool testnet = false, const cryptonote::test_options *test_options = NULL); + + /** + * @brief Initialize the Blockchain state + * + * @param db a pointer to the backing store to use for the blockchain + * @param hf a structure containing hardfork information + * @param testnet true if on testnet, else false + * + * @return true on success, false if any initialization steps fail + */ bool init(BlockchainDB* db, HardFork*& hf, const bool testnet = false); + + /** + * @brief Uninitializes the blockchain state + * + * Saves to disk any state that needs to be maintained + * + * @return true on success, false if any uninitialization steps fail + */ bool deinit(); + /** + * @brief assign a set of blockchain checkpoint hashes + * + * @param chk_pts the set of checkpoints to assign + */ void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; } - //bool push_new_block(); + /** + * @brief get blocks and transactions from blocks based on start height and count + * + * @param start_offset the height on the blockchain to start at + * @param count the number of blocks to get, if there are as many after start_offset + * @param blocks return-by-reference container to put result blocks in + * @param txs return-by-reference container to put result transactions in + * + * @return false if start_offset > blockchain height, else true + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const; + + /** + * @brief get blocks from blocks based on start height and count + * + * @param start_offset the height on the blockchain to start at + * @param count the number of blocks to get, if there are as many after start_offset + * @param blocks return-by-reference container to put result blocks in + * + * @return false if start_offset > blockchain height, else true + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const; + + /** + * @brief compiles a list of all blocks stored as alternative chains + * + * @param blocks return-by-reference container to put result blocks in + * + * @return true + */ bool get_alternative_blocks(std::list& blocks) const; + + /** + * @brief returns the number of alternative blocks stored + * + * @return the number of alternative blocks stored + */ size_t get_alternative_blocks_count() const; + + /** + * @brief gets a block's hash given a height + * + * @param height the height of the block + * + * @return the hash of the block at the requested height, or a zeroed hash if there is no such block + */ crypto::hash get_block_id_by_height(uint64_t height) const; + + /** + * @brief gets the block with a given hash + * + * @param h the hash to look for + * @param blk return-by-reference variable to put result block in + * + * @return true if the block was found, else false + */ bool get_block_by_hash(const crypto::hash &h, block &blk) const; + + /** + * @brief get all block hashes (main chain, alt chains, and invalid blocks) + * + * @param main return-by-reference container to put result main chain blocks' hashes in + * @param alt return-by-reference container to put result alt chain blocks' hashes in + * @param invalid return-by-reference container to put result invalid blocks' hashes in + */ void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) const; + + /** + * @brief performs some preprocessing on a group of incoming blocks to speed up verification + * + * @param blocks a list of incoming blocks + * + * @return false on erroneous blocks, else true + */ bool prepare_handle_incoming_blocks(const std::list &blocks); + + /** + * @brief incoming blocks post-processing, cleanup, and disk sync + * + * @param force_sync if true, and Blockchain is handling syncing to disk, always sync + * + * @return true + */ bool cleanup_handle_incoming_blocks(bool force_sync = false); + /** + * @brief search the blockchain for a transaction by hash + * + * @param id the hash to search for + * + * @return true if the tx exists, else false + */ bool have_tx(const crypto::hash &id) const; + + /** + * @brief check if any key image in a transaction has already been spent + * + * @param tx the transaction to check + * + * @return true if any key image is already spent in the blockchain, else false + */ bool have_tx_keyimges_as_spent(const transaction &tx) const; + + /** + * @brief check if a key image is already spent on the blockchain + * + * Whenever a transaction output is used as an input for another transaction + * (a true input, not just one of a mixing set), a key image is generated + * and stored in the transaction in order to prevent double spending. If + * this key image is seen again, the transaction using it is rejected. + * + * @param key_im the key image to search for + * + * @return true if the key image is already spent in the blockchain, else false + */ bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const; + /** + * @brief get the current height of the blockchain + * + * @return the height + */ uint64_t get_current_blockchain_height() const; + + /** + * @brief get the hash of the most recent block on the blockchain + * + * @return the hash + */ crypto::hash get_tail_id() const; + + /** + * @brief get the height and hash of the most recent block on the blockchain + * + * @param height return-by-reference variable to store the height in + * + * @return the hash + */ crypto::hash get_tail_id(uint64_t& height) const; + + /** + * @brief returns the difficulty target the next block to be added must meet + * + * @return the target + */ difficulty_type get_difficulty_for_next_block(); + + /** + * @brief adds a block to the blockchain + * + * Adds a new block to the blockchain. If the block's parent is not the + * current top of the blockchain, the block may be added to an alternate + * chain. If the block does not belong, is already in the blockchain + * or an alternate chain, or is invalid, return false. + * + * @param bl_ the block to be added + * @param bvc metadata about the block addition's success/failure + * + * @return true on successful addition to the blockchain, else false + */ bool add_new_block(const block& bl_, block_verification_context& bvc); + + /** + * @brief clears the blockchain and starts a new one + * + * @param b the first block in the new chain (the genesis block) + * + * @return true on success, else false + */ bool reset_and_set_genesis_block(const block& b); + + /** + * @brief creates a new block to mine against + * + * @param b return-by-reference block to be filled in + * @param miner_address address new coins for the block will go to + * @param di return-by-reference tells the miner what the difficulty target is + * @param height return-by-reference tells the miner what height it's mining against + * @param ex_nonce extra data to be added to the miner transaction's extra + * + * @return true if block template filled in successfully, else false + */ bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce); + + /** + * @brief checks if a block is known about with a given hash + * + * This function checks the main chain, alternate chains, and invalid blocks + * for a block with the given hash + * + * @param id the hash to search for + * + * @return true if the block is known, else false + */ bool have_block(const crypto::hash& id) const; + + /** + * @brief gets the total number of transactions on the main chain + * + * @return the number of transactions on the main chain + */ size_t get_total_transactions() const; + + /** + * @brief gets the hashes for a subset of the blockchain + * + * puts into list a list of hashes representing certain blocks + * from the blockchain in reverse chronological order + * + * the blocks chosen, at the time of this writing, are: + * the most recent 11 + * powers of 2 less recent from there, so 13, 17, 25, etc... + * + * @param ids return-by-reference list to put the resulting hashes in + * + * @return true + */ bool get_short_chain_history(std::list& ids) const; + + /** + * @brief get recent block hashes for a foreign chain + * + * Find the split point between us and foreign blockchain and return + * (by reference) the most recent common block hash along with up to + * BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes. + * + * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) + * @param resp return-by-reference the split height and subsequent blocks' hashes + * + * @return true if a block found in common, else false + */ bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const; + + /** + * @brief find the most recent common point between ours and a foreign chain + * + * This function takes a list of block hashes from another node + * on the network to find where the split point is between us and them. + * This is used to see what to send another node that needs to sync. + * + * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) + * @param starter_offset return-by-reference the most recent common block's height + * + * @return true if a block found in common, else false + */ bool find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset) const; + + /** + * @brief get recent blocks for a foreign chain + * + * This function gets recent blocks relative to a foreign chain, starting either at + * a requested height or whatever height is the most recent ours and the foreign + * chain have in common. + * + * @param req_start_block if non-zero, specifies a start point (otherwise find most recent commonality) + * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) + * @param blocks return-by-reference the blocks and their transactions + * @param total_height return-by-reference our current blockchain height + * @param start_height return-by-reference the height of the first block returned + * @param max_count the max number of blocks to get + * + * @return true if a block found in common or req_start_block specified, else false + */ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const; + + /** + * @brief retrieves a set of blocks and their transactions, and possibly other transactions + * + * the request object encapsulates a list of block hashes and a (possibly empty) list of + * transaction hashes. for each block hash, the block is fetched along with all of that + * block's transactions. Any transactions requested separately are fetched afterwards. + * + * @param arg the request + * @param rsp return-by-reference the response to fill in + * + * @return true unless any blocks or transactions are missing + */ bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp); + + //FIXME: function declared, but never defined or used. Candidate for removal. bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res); + + /** + * @brief gets random outputs to mix with + * + * This function takes an RPC request for outputs to mix with + * and creates an RPC response with the resultant output indices. + * + * Outputs to mix with are randomly selected from the utxo set + * for each output amount in the request. + * + * @param req the output amounts and number of mixins to select + * @param res return-by-reference the resultant output indices + * + * @return true + */ bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const; + + /** + * @brief gets the global indices for outputs from a given transaction + * + * This function gets the global indices for all outputs belonging + * to a specific transaction. + * + * @param tx_id the hash of the transaction to fetch indices for + * @param indexs return-by-reference the global indices for the transaction's outputs + * + * @return false if the transaction does not exist, or if no indices are found, otherwise true + */ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; + + /** + * @brief stores the blockchain + * + * If Blockchain is handling storing of the blockchain (rather than BlockchainDB), + * this initiates a blockchain save. + * + * @return true unless saving the blockchain fails + */ bool store_blockchain(); + /** + * @brief validates a transaction's inputs + * + * validates a transaction's inputs as correctly used and not previously + * spent. also returns the hash and height of the most recent block + * which contains an output that was used as an input to the transaction. + * + * @param tx the transaction to validate + * @param pmax_used_block_height return-by-reference block height of most recent input + * @param max_used_block_id return-by-reference block hash of most recent input + * @param kept_by_block whether or not the transaction is from a previously-verified block + * + * @return false if any input is invalid, otherwise true + */ bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, bool kept_by_block = false); + + /** + * @brief check that a transaction's outputs conform to current standards + * + * This function checks, for example at the time of this writing, that + * each output is of the form a * 10^b (phrased differently, that if + * written out would have only one non-zero digit in base 10). + * + * @param tx the transaction to check the outputs of + * + * @return false if any outputs do not conform, otherwise true + */ bool check_tx_outputs(const transaction& tx); + + /** + * @brief gets the blocksize limit based on recent blocks + * + * @return the limit + */ uint64_t get_current_cumulative_blocksize_limit() const; + + /** + * @brief checks if the blockchain is currently being stored + * + * Note: this should be meaningless in cases where Blockchain is not + * directly managing saving the blockchain to disk. + * + * @return true if Blockchain is having the chain stored currently, else false + */ bool is_storing_blockchain()const{return m_is_blockchain_storing;} + + /** + * @brief gets the difficulty of the block with a given height + * + * @param i the height + * + * @return the difficulty + */ uint64_t block_difficulty(uint64_t i) const; + /** + * @brief gets blocks based on a list of block hashes + * + * @tparam t_ids_container a standard-iterable container + * @tparam t_blocks_container a standard-iterable container + * @tparam t_missed_container a standard-iterable container + * @param block_ids a container of block hashes for which to get the corresponding blocks + * @param blocks return-by-reference a container to store result blocks in + * @param missed_bs return-by-reference a container to store missed blocks in + * + * @return false if an unexpected exception occurs, else true + */ template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const; + /** + * @brief gets transactions based on a list of transaction hashes + * + * @tparam t_ids_container a standard-iterable container + * @tparam t_tx_container a standard-iterable container + * @tparam t_missed_container a standard-iterable container + * @param txs_ids a container of hashes for which to get the corresponding transactions + * @param txs return-by-reference a container to store result transactions in + * @param missed_txs return-by-reference a container to store missed transactions in + * + * @return false if an unexpected exception occurs, else true + */ template bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const; + //debug functions + + /** + * @brief prints data about a snippet of the blockchain + * + * if start_index is greater than the blockchain height, do nothing + * + * @param start_index height on chain to start at + * @param end_index height on chain to end at + */ void print_blockchain(uint64_t start_index, uint64_t end_index) const; + + /** + * @brief prints every block's hash + * + * WARNING: This function will absolutely crush a terminal in prints, so + * it is recommended to redirect this output to a log file (or null sink + * if a log file is already set up, as should be the default) + */ void print_blockchain_index() const; + + /** + * @brief currently does nothing, candidate for removal + * + * @param file + */ void print_blockchain_outs(const std::string& file) const; + /** + * @brief check the blockchain against a set of checkpoints + * + * If a block fails a checkpoint and enforce is enabled, the blockchain + * will be rolled back to two blocks prior to that block. If enforce + * is disabled, as is currently the default case with DNS-based checkpoints, + * an error will be printed to the user but no other action will be taken. + * + * @param points the checkpoints to check against + * @param enforce whether or not to take action on failure + */ void check_against_checkpoints(const checkpoints& points, bool enforce); + + /** + * @brief configure whether or not to enforce DNS-based checkpoints + * + * @param enforce the new enforcement setting + */ void set_enforce_dns_checkpoints(bool enforce); + + /** + * @brief loads new checkpoints from a file and optionally from DNS + * + * @param file_path the path of the file to look for and load checkpoints from + * @param check_dns whether or not to check for new DNS-based checkpoints + * + * @return false if any enforced checkpoint type fails to load, otherwise true + */ bool update_checkpoints(const std::string& file_path, bool check_dns); + // user options, must be called before calling init() + + //FIXME: parameter names don't match function definition in .cpp file + /** + * @brief sets various performance options + * + * @param block_threads max number of threads when preparing blocks for addition + * @param blocks_per_sync number of blocks to cache before syncing to database + * @param sync_mode the ::blockchain_db_sync_mode to use + * @param fast_sync sync using built-in block hashes as trusted + */ void set_user_options(uint64_t block_threads, uint64_t blocks_per_sync, blockchain_db_sync_mode sync_mode, bool fast_sync); + /** + * @brief set whether or not to show/print time statistics + * + * @param stats the new time stats setting + */ void set_show_time_stats(bool stats) { m_show_time_stats = stats; } + /** + * @brief gets the hardfork voting state object + * + * @return the HardFork object + */ HardFork::State get_hard_fork_state() const; + + /** + * @brief gets the current hardfork version in use/voted for + * + * @return the version + */ uint8_t get_current_hard_fork_version() const { return m_hardfork->get_current_version(); } + + /** + * @brief returns the newest hardfork version known to the blockchain + * + * @return the version + */ uint8_t get_ideal_hard_fork_version() const { return m_hardfork->get_ideal_version(); } + + /** + * @brief returns the newest hardfork version voted to be enabled + * as of a certain height + * + * @param height the height for which to check version info + * + * @return the version + */ uint8_t get_ideal_hard_fork_version(uint64_t height) const { return m_hardfork->get_ideal_version(height); } + /** + * @brief get information about hardfork voting for a version + * + * @param version the version in question + * @param window the size of the voting window + * @param votes the number of votes to enable + * @param threshold the number of votes required to enable + * @param earliest_height the earliest height at which is allowed + * @param voting which version this node is voting for/using + * + * @return whether the version queried is enabled + */ bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const; + /** + * @brief remove transactions from the transaction pool (if present) + * + * @param txids a list of hashes of transactions to be removed + * + * @return false if any removals fail, otherwise true + */ bool flush_txes_from_pool(const std::list &txids); + /** + * @brief perform a check on all key images in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any key image fails the check, otherwise true + */ bool for_all_key_images(std::function) const; + + /** + * @brief perform a check on all blocks in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any block fails the check, otherwise true + */ bool for_all_blocks(std::function) const; + + /** + * @brief perform a check on all transactions in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any transaction fails the check, otherwise true + */ bool for_all_transactions(std::function) const; + + /** + * @brief perform a check on all outputs in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any output fails the check, otherwise true + */ bool for_all_outputs(std::function) const; + /** + * @brief get a reference to the BlockchainDB in use by Blockchain + * + * @return a reference to the BlockchainDB instance + */ BlockchainDB& get_db() { return *m_db; } + /** + * @brief get a number of outputs of a specific amount + * + * @param amount the amount + * @param offsets the indices (indexed to the amount) of the outputs + * @param outputs return-by-reference the outputs collected + * @param txs unused, candidate for removal + */ void output_scan_worker(const uint64_t amount,const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const; + /** + * @brief computes the "short" and "long" hashes for a set of blocks + * + * @param height the height of the first block + * @param blocks the blocks to be hashed + * @param map return-by-reference the hashes for each block + */ void block_longhash_worker(const uint64_t height, const std::vector &blocks, std::unordered_map &map) const; private: + + // TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage typedef std::unordered_map blocks_by_id_index; + typedef std::unordered_map transactions_container; + typedef std::unordered_set key_images_container; + typedef std::vector blocks_container; + typedef std::unordered_map blocks_ext_by_hash; + typedef std::unordered_map blocks_by_hash; + typedef std::map>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction + BlockchainDB* m_db; tx_memory_pool& m_tx_pool; + 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_sz_limit; + // metadata containers std::unordered_map>> m_scan_table; std::unordered_map> m_check_tx_inputs_table; std::unordered_map m_blocks_longhash_table; @@ -243,39 +822,341 @@ namespace cryptonote bool m_testnet; + /** + * @brief collects the keys for all outputs being "spent" as an input + * + * This function makes sure that each "input" in an input (mixins) exists + * and collects the public key for each from the transaction it was included in + * via the visitor passed to it. + * + * If pmax_related_block_height is not NULL, its value is set to the height + * of the most recent block which contains an output used in the input set + * + * @tparam visitor_t a class encapsulating tx is unlocked and collect tx key + * @param tx_in_to_key a transaction input instance + * @param vis an instance of the visitor to use + * @param tx_prefix_hash the hash of the associated transaction_prefix + * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set + * + * @return false if any keys are not found or any inputs are not unlocked, otherwise true + */ template inline bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t &vis, const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height = NULL) const; + + /** + * @brief collect output public keys of a transaction input set + * + * This function locates all outputs associated with a given input set (mixins) + * and validates that they exist and are usable + * (unlocked, unspent is checked elsewhere). + * + * If pmax_related_block_height is not NULL, its value is set to the height + * of the most recent block which contains an output used in the input set + * + * @param txin the transaction input + * @param tx_prefix_hash the transaction prefix hash, for caching organization + * @param sig the input signature + * @param output_keys return-by-reference the public keys of the outputs in the input set + * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set + * + * @return false if any output is not yet unlocked, or is missing, otherwise true + */ bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); + + /** + * @brief validate a transaction's inputs and their keys + * + * This function validates transaction inputs and their keys. Previously + * it also performed double spend checking, but that has been moved to its + * own function. + * + * If pmax_related_block_height is not NULL, its value is set to the height + * of the most recent block which contains an output used in any input set + * + * Currently this function calls ring signature validation for each + * transaction. + * + * @param tx the transaction to validate + * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set + * + * @return false if any validation step fails, otherwise true + */ bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL); + /** + * @brief performs a blockchain reorganization according to the longest chain rule + * + * This function aggregates all the actions necessary to switch to a + * newly-longer chain. If any step in the reorganization process fails, + * the blockchain is reverted to its previous state. + * + * @param alt_chain the chain to switch to + * @param discard_disconnected_chain whether or not to keep the old chain as an alternate + * + * @return false if the reorganization fails, otherwise true + */ bool switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain); + + /** + * @brief removes the most recent block from the blockchain + * + * @return the block removed + */ block pop_block_from_blockchain(); + /** + * @brief validate and add a new block to the end of the blockchain + * + * This function is merely a convenience wrapper around the other + * of the same name. This one passes the block's hash to the other + * as well as the block and verification context. + * + * @param bl the block to be added + * @param bvc metadata concerning the block's validity + * + * @return true if the block was added successfully, otherwise false + */ bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc); + + /** + * @brief validate and add a new block to the end of the blockchain + * + * When a block is given to Blockchain to be added to the blockchain, it + * is passed here if it is determined to belong at the end of the current + * chain. + * + * @param bl the block to be added + * @param id the hash of the block + * @param bvc metadata concerning the block's validity + * + * @return true if the block was added successfully, otherwise false + */ bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc); + + /** + * @brief validate and add a new block to an alternate blockchain + * + * If a block to be added does not belong to the main chain, but there + * is an alternate chain to which it should be added, that is handled + * here. + * + * @param b the block to be added + * @param id the hash of the block + * @param bvc metadata concerning the block's validity + * + * @return true if the block was added successfully, otherwise false + */ bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc); + + /** + * @brief gets the difficulty requirement for a new block on an alternate chain + * + * @param alt_chain the chain to be added to + * @param bei the block being added (and metadata, see ::block_extended_info) + * + * @return the difficulty requirement + */ difficulty_type get_next_difficulty_for_alternative_chain(const std::list& alt_chain, block_extended_info& bei) const; + + /** + * @brief sanity checks a miner transaction before validating an entire block + * + * This function merely checks basic things like the structure of the miner + * transaction, the unlock time, and that the amount doesn't overflow. + * + * @param b the block containing the miner transaction + * @param height the height at which the block will be added + * + * @return false if anything is found wrong with the miner transaction, otherwise true + */ bool prevalidate_miner_transaction(const block& b, uint64_t height); + + /** + * @brief validates a miner (coinbase) transaction + * + * This function makes sure that the miner calculated his reward correctly + * and that his miner transaction totals reward + fee. + * + * @param b the block containing the miner transaction to be validated + * @param cumulative_block_size the block's size + * @param fee the total fees collected in the block + * @param base_reward return-by-reference the new block's generated coins + * @param already_generated_coins the amount of currency generated prior to this block + * @param partial_block_reward return-by-reference true if miner accepted only partial reward + * + * @return false if anything is found wrong with the miner transaction, otherwise true + */ bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward); + + //FIXME: function declared but neither defined nor used, candidate for removal bool validate_transaction(const block& b, uint64_t height, const transaction& tx); + + /** + * @brief reverts the blockchain to its previous state following a failed switch + * + * If Blockchain fails to switch to an alternate chain when it means + * to do so, this function reverts the blockchain to how it was before + * the attempted switch. + * + * @param original_chain the chain to switch back to + * @param rollback_height the height to revert to before appending the original chain + * + * @return false if something goes wrong with reverting (very bad), otherwise true + */ bool rollback_blockchain_switching(std::list& original_chain, uint64_t rollback_height); + + //FIXME: function declared but neither defined nor used, candidate for removal, + // remnant from old blockchain_storage implementation bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height); + + //FIXME: function declared but neither defined nor used, candidate for removal, + // remnant from old blockchain_storage implementation bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); + + //FIXME: function declared but neither defined nor used, candidate for removal, + // remnant from old blockchain_storage implementation bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); + + /** + * @brief gets recent block sizes for median calculation + * + * get the block sizes of the last blocks, and return by reference . + * + * @param sz return-by-reference the list of sizes + * @param count the number of blocks to get sizes for + */ void get_last_n_blocks_sizes(std::vector& sz, size_t count) const; + + /** + * @brief adds the given output to the requested set of random outputs + * + * @param result_outs return-by-reference the set the output is to be added to + * @param amount the output amount + * @param i the output index (indexed to amount) + */ void add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i) const; + + /** + * @brief checks if a transaction is unlocked (its outputs spendable) + * + * This function checks to see if a transaction is unlocked. + * unlock_time is either a block index or a unix time. + * + * @param unlock_time the unlock parameter (height or time) + * + * @return true if spendable, otherwise false + */ bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; + + /** + * @brief stores an invalid block in a separate container + * + * Storing invalid blocks allows quick dismissal of the same block + * if it is seen again. + * + * @param bl the invalid block + * @param h the block's hash + * + * @return false if the block cannot be stored for some reason, otherwise true + */ bool add_block_as_invalid(const block& bl, const crypto::hash& h); + + /** + * @brief stores an invalid block in a separate container + * + * Storing invalid blocks allows quick dismissal of the same block + * if it is seen again. + * + * @param bei the invalid block (see ::block_extended_info) + * @param h the block's hash + * + * @return false if the block cannot be stored for some reason, otherwise true + */ bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); + + /** + * @brief checks a block's timestamp + * + * This function grabs the timestamps from the most recent blocks, + * where n = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. If there are not those many + * blocks in the blockchain, the timestap is assumed to be valid. If there + * are, this function returns: + * true if the block's timestamp is not less than the timestamp of the + * median of the selected blocks + * false otherwise + * + * @param b the block to be checked + * + * @return true if the block's timestamp is valid, otherwise false + */ bool check_block_timestamp(const block& b) const; + + /** + * @brief checks a block's timestamp + * + * If the block is not more recent than the median of the recent + * timestamps passed here, it is considered invalid. + * + * @param timestamps a list of the most recent timestamps to check against + * @param b the block to be checked + * + * @return true if the block's timestamp is valid, otherwise false + */ bool check_block_timestamp(std::vector& timestamps, const block& b) const; + + /** + * @brief get the "adjusted time" + * + * Currently this simply returns the current time according to the + * user's machine. + * + * @return the current time + */ uint64_t get_adjusted_time() const; + + /** + * @brief finish an alternate chain's timestamp window from the main chain + * + * for an alternate chain, get the timestamps from the main chain to complete + * the needed number of timestamps for the BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. + * + * @param start_height the alternate chain's attachment height to the main chain + * @param timestamps return-by-value the timestamps set to be populated + * + * @return true unless start_height is greater than the current blockchain height + */ bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); + + /** + * @brief calculate the block size limit for the next block to be added + * + * @return true + */ bool update_next_cumulative_size_limit(); void return_tx_to_pool(const std::vector &txs); + /** + * @brief make sure a transaction isn't attempting a double-spend + * + * @param tx the transaction to check + * @param keys_this_block a cumulative list of spent keys for the current block + * + * @return false if a double spend was detected, otherwise true + */ bool check_for_double_spend(const transaction& tx, key_images_container& keys_this_block) const; + + //FIXME: function declared but neither defined nor used, candidate for removal, void get_timestamp_and_difficulty(uint64_t ×tamp, difficulty_type &difficulty, const int offset) const; + + /** + * @brief validates a transaction input's ring signature + * + * @param tx_prefix_hash the transaction prefix' hash + * @param key_image the key image generated from the true input + * @param pubkeys the public keys for each input in the ring signature + * @param sig the signature generated for each input in the ring signature + * @param result false if the ring signature is invalid, otherwise true + */ void check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector &pubkeys, const std::vector &sig, uint64_t &result); -- cgit v1.2.3 From 89c24ac2be8b00474cd3f0973ee458a6e80f76f3 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 7 Oct 2015 22:25:06 -0400 Subject: Remove unnecessary or defunct code --- src/cryptonote_core/blockchain.cpp | 1 - src/cryptonote_core/blockchain.h | 21 --------------------- 2 files changed, 22 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index a55a435b3..2be4f6aee 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -352,7 +352,6 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const cryptonote::te // we only need 1 m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service)); - //TODO: move this block into separate functions? #if defined(PER_BLOCK_CHECKPOINT) if (!fakechain) load_compiled_in_block_hashes(); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 98a58c540..94def1aa9 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -423,9 +423,6 @@ namespace cryptonote */ bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp); - //FIXME: function declared, but never defined or used. Candidate for removal. - bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res); - /** * @brief gets random outputs to mix with * @@ -988,9 +985,6 @@ namespace cryptonote */ bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward); - //FIXME: function declared but neither defined nor used, candidate for removal - bool validate_transaction(const block& b, uint64_t height, const transaction& tx); - /** * @brief reverts the blockchain to its previous state following a failed switch * @@ -1005,18 +999,6 @@ namespace cryptonote */ bool rollback_blockchain_switching(std::list& original_chain, uint64_t rollback_height); - //FIXME: function declared but neither defined nor used, candidate for removal, - // remnant from old blockchain_storage implementation - bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height); - - //FIXME: function declared but neither defined nor used, candidate for removal, - // remnant from old blockchain_storage implementation - bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); - - //FIXME: function declared but neither defined nor used, candidate for removal, - // remnant from old blockchain_storage implementation - bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); - /** * @brief gets recent block sizes for median calculation * @@ -1145,9 +1127,6 @@ namespace cryptonote */ bool check_for_double_spend(const transaction& tx, key_images_container& keys_this_block) const; - //FIXME: function declared but neither defined nor used, candidate for removal, - void get_timestamp_and_difficulty(uint64_t ×tamp, difficulty_type &difficulty, const int offset) const; - /** * @brief validates a transaction input's ring signature * -- cgit v1.2.3 From 1b0c98e7e9951fbeff8b713dd80b040e628059ff Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 7 Oct 2015 22:28:31 -0400 Subject: doxygen documentation for checkpoints.{h,cpp} All functions in src/cryptonote_core/checkpoints.h are now documented in doxygen style. checkpoints.cpp has been reviewed, one function has been marked for discussion on correctness. --- src/cryptonote_core/checkpoints.cpp | 5 +- src/cryptonote_core/checkpoints.h | 100 +++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index 24d066dae..42f1163f3 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -84,10 +84,7 @@ namespace cryptonote return check_block(height, h, ignored); } //--------------------------------------------------------------------------- - // this basically says if the blockchain is smaller than the first - // checkpoint then alternate blocks are allowed. Alternatively, if the - // last checkpoint *before* the end of the current chain is also before - // the block to be added, then this is fine. + //FIXME: is this the desired behavior? bool checkpoints::is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const { if (0 == block_height) diff --git a/src/cryptonote_core/checkpoints.h b/src/cryptonote_core/checkpoints.h index 00a53ec24..56d57db43 100644 --- a/src/cryptonote_core/checkpoints.h +++ b/src/cryptonote_core/checkpoints.h @@ -36,19 +36,115 @@ namespace cryptonote { + /** + * @brief A container for blockchain checkpoints + * + * A checkpoint is a pre-defined hash for the block at a given height. + * Some of these are compiled-in, while others can be loaded at runtime + * either from a json file or via DNS from a checkpoint-hosting server. + */ class checkpoints { public: + + /** + * @brief default constructor + */ checkpoints(); + + /** + * @brief adds a checkpoint to the container + * + * @param height the height of the block the checkpoint is for + * @param hash_str the hash of the block, as a string + * + * @return false if parsing the hash fails, or if the height is a duplicate + * AND the existing checkpoint hash does not match the new one, + * otherwise returns true + */ bool add_checkpoint(uint64_t height, const std::string& hash_str); + + /** + * @brief checks if there is a checkpoint in the future + * + * This function checks if the height passed is lower than the highest + * checkpoint. + * + * @param height the height to check against + * + * @return false if no checkpoints, otherwise returns whether or not + * the height passed is lower than the highest checkpoint. + */ bool is_in_checkpoint_zone(uint64_t height) const; - bool check_block(uint64_t height, const crypto::hash& h) const; + + /** + * @brief checks if the given height and hash agree with the checkpoints + * + * This function checks if the given height and hash exist in the + * checkpoints container. If so, it returns whether or not the passed + * parameters match the stored values. + * + * @param height the height to be checked + * @param h the hash to be checked + * @param is_a_checkpoint return-by-reference if there is a checkpoint at the given height + * + * @return true if there is no checkpoint at the given height, + * true if the passed parameters match the stored checkpoint, + * false otherwise + */ bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const; + + /** + * @overload + */ + bool check_block(uint64_t height, const crypto::hash& h) const; + + /** + * @brief checks if alternate chain blocks should be kept for a given height + * + * this basically says if the blockchain is smaller than the first + * checkpoint then alternate blocks are allowed. Alternatively, if the + * last checkpoint *before* the end of the current chain is also before + * the block to be added, then this is fine. + * + * @param blockchain_height the current blockchain height + * @param block_height the height of the block to be added as alternate + * + * @return true if alternate blocks are allowed given the parameters, + * otherwise false + */ bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const; + + /** + * @brief gets the highest checkpoint height + * + * @return the height of the highest checkpoint + */ uint64_t get_max_height() const; + + /** + * @brief gets the checkpoints container + * + * @return a const reference to the checkpoints container + */ const std::map& get_points() const; + + /** + * @brief checks if our checkpoints container conflicts with another + * + * A conflict refers to a case where both checkpoint sets have a checkpoint + * for a specific height but their hashes for that height do not match. + * + * @param other the other checkpoints instance to check against + * + * @return false if any conflict is found, otherwise true + */ bool check_for_conflicts(const checkpoints& other) const; + + private: - std::map m_points; + + std::map m_points; //!< the checkpoints container + }; } -- cgit v1.2.3 From 540a76c5c29aa0742c00af4391ce718e7ec69c97 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 7 Oct 2015 22:28:37 -0400 Subject: Move checkpoint functions into checkpoints class The functions in src/cryptonote_core/checkpoints_create.{h,cpp} should be member functions of the checkpoints class, if nothing else for the sake of keeping their documentation together. This commit covers moving those functions to be member functions of the checkpoints class as well as documenting those functions. --- src/cryptonote_core/CMakeLists.txt | 2 - src/cryptonote_core/blockchain.cpp | 10 +- src/cryptonote_core/blockchain_storage.cpp | 8 +- src/cryptonote_core/checkpoints.cpp | 246 ++++++++++++++++++++++++- src/cryptonote_core/checkpoints.h | 87 +++++++-- src/cryptonote_core/checkpoints_create.cpp | 280 ----------------------------- src/cryptonote_core/checkpoints_create.h | 48 ----- src/cryptonote_core/cryptonote_core.cpp | 4 +- src/daemon/core.h | 1 - 9 files changed, 327 insertions(+), 359 deletions(-) delete mode 100644 src/cryptonote_core/checkpoints_create.cpp delete mode 100644 src/cryptonote_core/checkpoints_create.h (limited to 'src') diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 88eea1d7e..205356797 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -31,7 +31,6 @@ set(cryptonote_core_sources blockchain_storage.cpp blockchain.cpp checkpoints.cpp - checkpoints_create.cpp cryptonote_basic_impl.cpp cryptonote_core.cpp cryptonote_format_utils.cpp @@ -49,7 +48,6 @@ set(cryptonote_core_private_headers blockchain_storage_boost_serialization.h blockchain.h checkpoints.h - checkpoints_create.h connection_context.h cryptonote_basic.h cryptonote_basic_impl.h diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 2be4f6aee..dec7b8e29 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -49,7 +49,7 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/checkpoints.h" #include "cryptonote_core/cryptonote_core.h" #if defined(PER_BLOCK_CHECKPOINT) #include "blocks/blocks.h" @@ -2860,16 +2860,16 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor // with an existing checkpoint. bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns) { - if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) + if (!m_checkpoints.load_checkpoints_from_json(file_path)) { - return false; + return false; } // if we're checking both dns and json, load checkpoints from dns. // if we're not hard-enforcing dns checkpoints, handle accordingly if (m_enforce_dns_checkpoints && check_dns) { - if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) + if (!m_checkpoints.load_checkpoints_from_dns()) { return false; } @@ -2877,7 +2877,7 @@ bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns else if (check_dns) { checkpoints dns_points; - cryptonote::load_checkpoints_from_dns(dns_points); + dns_points.load_checkpoints_from_dns(); if (m_checkpoints.check_for_conflicts(dns_points)) { check_against_checkpoints(dns_points, false); diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index e1b89f887..a829b7cbe 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -48,7 +48,7 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/checkpoints.h" //#include "serialization/json_archive.h" #include "../../contrib/otshell_utils/utils.hpp" #include "../../src/p2p/data_logger.hpp" @@ -1854,7 +1854,7 @@ void blockchain_storage::check_against_checkpoints(const checkpoints& points, bo // with an existing checkpoint. bool blockchain_storage::update_checkpoints(const std::string& file_path, bool check_dns) { - if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) + if (!m_checkpoints.load_checkpoints_from_json(file_path)) { return false; } @@ -1863,7 +1863,7 @@ bool blockchain_storage::update_checkpoints(const std::string& file_path, bool c // if we're not hard-enforcing dns checkpoints, handle accordingly if (m_enforce_dns_checkpoints && check_dns) { - if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) + if (!m_checkpoints.load_checkpoints_from_dns()) { return false; } @@ -1871,7 +1871,7 @@ bool blockchain_storage::update_checkpoints(const std::string& file_path, bool c else if (check_dns) { checkpoints dns_points; - cryptonote::load_checkpoints_from_dns(dns_points, m_testnet); + dns_points.load_checkpoints_from_dns(m_testnet); if (m_checkpoints.check_for_conflicts(dns_points)) { check_against_checkpoints(dns_points, false); diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index 42f1163f3..c038a4802 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -1,21 +1,21 @@ // Copyright (c) 2014-2016, 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 @@ -25,14 +25,44 @@ // 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. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include "include_base_utils.h" + using namespace epee; #include "checkpoints.h" +#include "common/dns_utils.h" +#include "include_base_utils.h" +#include +#include + +namespace +{ + bool dns_records_match(const std::vector& a, const std::vector& b) + { + if (a.size() != b.size()) return false; + + for (const auto& record_in_a : a) + { + bool ok = false; + for (const auto& record_in_b : b) + { + if (record_in_a == record_in_b) + { + ok = true; + break; + } + } + if (!ok) return false; + } + + return true; + } +} // anonymous namespace + namespace cryptonote { //--------------------------------------------------------------------------- @@ -125,4 +155,206 @@ namespace cryptonote } return true; } + + bool checkpoints::init_default_checkpoints() + { + ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); + ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); + ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); + ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876"); + ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2"); + ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); + ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); + ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); + ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3"); + ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"); + ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); + ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); + ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); + ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553"); + ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61"); + ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf"); + ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131"); + ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8"); + ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d"); + ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831"); + ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02"); + ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5"); + ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd"); + ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60"); + ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337"); + ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f"); + + return true; + } + + bool checkpoints::load_checkpoints_from_json(const std::string json_hashfile_fullpath) + { + boost::system::error_code errcode; + if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode))) + { + LOG_PRINT_L1("Blockchain checkpoints file not found"); + return true; + } + + LOG_PRINT_L1("Adding checkpoints from blockchain hashfile"); + + uint64_t prev_max_height = get_max_height(); + LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height); + t_hash_json hashes; + epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath); + for (std::vector::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); ) + { + uint64_t height; + height = it->height; + if (height <= prev_max_height) { + LOG_PRINT_L1("ignoring checkpoint height " << height); + } else { + std::string blockhash = it->hash; + LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash); + ADD_CHECKPOINT(height, blockhash); + } + ++it; + } + + return true; + } + + bool checkpoints::load_checkpoints_from_dns(bool testnet) + { + // All four MoneroPulse domains have DNSSEC on and valid + static const std::vector dns_urls = { "checkpoints.moneropulse.se" + , "checkpoints.moneropulse.org" + , "checkpoints.moneropulse.net" + , "checkpoints.moneropulse.co" + }; + + static const std::vector testnet_dns_urls = { "testpoints.moneropulse.se" + , "testpoints.moneropulse.org" + , "testpoints.moneropulse.net" + , "testpoints.moneropulse.co" + }; + + std::vector > records; + records.resize(dns_urls.size()); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, dns_urls.size() - 1); + size_t first_index = dis(gen); + + bool avail, valid; + size_t cur_index = first_index; + do + { + std::string url; + if (testnet) + { + url = testnet_dns_urls[cur_index]; + } + else + { + url = dns_urls[cur_index]; + } + + records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid); + if (!avail) + { + records[cur_index].clear(); + LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); + } + if (!valid) + { + records[cur_index].clear(); + LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); + } + + cur_index++; + if (cur_index == dns_urls.size()) + { + cur_index = 0; + } + records[cur_index].clear(); + } while (cur_index != first_index); + + size_t num_valid_records = 0; + + for( const auto& record_set : records) + { + if (record_set.size() != 0) + { + num_valid_records++; + } + } + + if (num_valid_records < 2) + { + LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received"); + return true; + } + + int good_records_index = -1; + for (size_t i = 0; i < records.size() - 1; ++i) + { + if (records[i].size() == 0) continue; + + for (size_t j = i + 1; j < records.size(); ++j) + { + if (dns_records_match(records[i], records[j])) + { + good_records_index = i; + break; + } + } + if (good_records_index >= 0) break; + } + + if (good_records_index < 0) + { + LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched"); + return true; + } + + for (auto& record : records[good_records_index]) + { + auto pos = record.find(":"); + if (pos != std::string::npos) + { + uint64_t height; + crypto::hash hash; + + // parse the first part as uint64_t, + // if this fails move on to the next record + std::stringstream ss(record.substr(0, pos)); + if (!(ss >> height)) + { + continue; + } + + // parse the second part as crypto::hash, + // if this fails move on to the next record + std::string hashStr = record.substr(pos + 1); + if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash)) + { + continue; + } + + ADD_CHECKPOINT(height, hashStr); + } + } + return true; + } + + bool checkpoints::load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet, bool dns) + { + bool result; + + result = load_checkpoints_from_json(json_hashfile_fullpath); + if (dns) + { + result &= load_checkpoints_from_dns(testnet); + } + + return result; + } } diff --git a/src/cryptonote_core/checkpoints.h b/src/cryptonote_core/checkpoints.h index 56d57db43..71727753e 100644 --- a/src/cryptonote_core/checkpoints.h +++ b/src/cryptonote_core/checkpoints.h @@ -1,21 +1,21 @@ // Copyright (c) 2014-2016, 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 @@ -25,13 +25,18 @@ // 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. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once #include #include #include "cryptonote_basic_impl.h" +#include "misc_log_ex.h" +#include "storages/portable_storage_template_helper.h" // epee json include + +#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false); +#define JSON_HASH_FILE_NAME "checkpoints.json" namespace cryptonote @@ -88,8 +93,8 @@ namespace cryptonote * @param h the hash to be checked * @param is_a_checkpoint return-by-reference if there is a checkpoint at the given height * - * @return true if there is no checkpoint at the given height, - * true if the passed parameters match the stored checkpoint, + * @return true if there is no checkpoint at the given height, + * true if the passed parameters match the stored checkpoint, * false otherwise */ bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const; @@ -110,7 +115,7 @@ namespace cryptonote * @param blockchain_height the current blockchain height * @param block_height the height of the block to be added as alternate * - * @return true if alternate blocks are allowed given the parameters, + * @return true if alternate blocks are allowed given the parameters, * otherwise false */ bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const; @@ -141,9 +146,71 @@ namespace cryptonote */ bool check_for_conflicts(const checkpoints& other) const; + /** + * @brief loads the default main chain checkpoints + * + * @return true unless adding a checkpoint fails + */ + bool init_default_checkpoints(); + + /** + * @brief load new checkpoints + * + * Loads new checkpoints from the specified json file, as well as + * (optionally) from DNS. + * + * @param json_hashfile_fullpath path to the json checkpoints file + * @param testnet whether to load testnet checkpoints or mainnet + * @param dns whether or not to load DNS checkpoints + * + * @return true if loading successful and no conflicts + */ + bool load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet=false, bool dns=true); + + /** + * @brief load new checkpoints from json + * + * @param json_hashfile_fullpath path to the json checkpoints file + * + * @return true if loading successful and no conflicts + */ + bool load_checkpoints_from_json(const std::string json_hashfile_fullpath); + + /** + * @brief load new checkpoints from DNS + * + * @param testnet whether to load testnet checkpoints or mainnet + * + * @return true if loading successful and no conflicts + */ + bool load_checkpoints_from_dns(bool testnet = false); private: + + /** + * @brief struct for loading a checkpoint from json + */ + struct t_hashline + { + uint64_t height; //!< the height of the checkpoint + std::string hash; //!< the hash for the checkpoint + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(hash) + END_KV_SERIALIZE_MAP() + }; + + /** + * @brief struct for loading many checkpoints from json + */ + struct t_hash_json { + std::vector hashlines; //!< the checkpoint lines from the file + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hashlines) + END_KV_SERIALIZE_MAP() + }; + std::map m_points; //!< the checkpoints container }; diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp deleted file mode 100644 index 41f2321d5..000000000 --- a/src/cryptonote_core/checkpoints_create.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (c) 2014-2016, 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. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#include "checkpoints_create.h" -#include "common/dns_utils.h" -#include "include_base_utils.h" -#include -#include -#include "storages/portable_storage_template_helper.h" // epee json include - -namespace -{ - bool dns_records_match(const std::vector& a, const std::vector& b) - { - if (a.size() != b.size()) return false; - - for (const auto& record_in_a : a) - { - bool ok = false; - for (const auto& record_in_b : b) - { - if (record_in_a == record_in_b) - { - ok = true; - break; - } - } - if (!ok) return false; - } - - return true; - } -} // anonymous namespace - -namespace cryptonote -{ - -struct t_hashline -{ - uint64_t height; - std::string hash; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(height) - KV_SERIALIZE(hash) - END_KV_SERIALIZE_MAP() -}; - -struct t_hash_json { - std::vector hashlines; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(hashlines) - END_KV_SERIALIZE_MAP() -}; - -bool create_checkpoints(cryptonote::checkpoints& checkpoints) -{ - ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); - ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); - ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); - ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876"); - ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2"); - ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); - ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); - ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); - ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3"); - ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"); - ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); - ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); - ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); - ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553"); - ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61"); - ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf"); - ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131"); - ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8"); - ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d"); - ADD_CHECKPOINT(300000, "0c1cd46df6ccff90ec4ab493281f2583c344cd62216c427628990fe9db1bb8b6"); - ADD_CHECKPOINT(400000, "1b2b0e7a30e59691491529a3d506d1ba3d6052d0f6b52198b7330b28a6f1b6ac"); - ADD_CHECKPOINT(450000, "4d098b511ca97723e81737c448343cfd4e6dadb3d8a0e757c6e4d595e6e48357"); - ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831"); - ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02"); - ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5"); - ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd"); - ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60"); - ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337"); - ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f"); - - return true; -} - -bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath) -{ - boost::system::error_code errcode; - if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode))) - { - LOG_PRINT_L1("Blockchain checkpoints file not found"); - return true; - } - - LOG_PRINT_L1("Adding checkpoints from blockchain hashfile"); - - uint64_t prev_max_height = checkpoints.get_max_height(); - LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height); - t_hash_json hashes; - epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath); - for (std::vector::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); ) - { - uint64_t height; - height = it->height; - if (height <= prev_max_height) { - LOG_PRINT_L1("ignoring checkpoint height " << height); - } else { - std::string blockhash = it->hash; - LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash); - ADD_CHECKPOINT(height, blockhash); - } - ++it; - } - - return true; -} - -bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet) -{ - // All four MoneroPulse domains have DNSSEC on and valid - static const std::vector dns_urls = { "checkpoints.moneropulse.se" - , "checkpoints.moneropulse.org" - , "checkpoints.moneropulse.net" - , "checkpoints.moneropulse.co" - }; - - static const std::vector testnet_dns_urls = { "testpoints.moneropulse.se" - , "testpoints.moneropulse.org" - , "testpoints.moneropulse.net" - , "testpoints.moneropulse.co" - }; - - std::vector > records; - records.resize(dns_urls.size()); - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(0, dns_urls.size() - 1); - size_t first_index = dis(gen); - - bool avail, valid; - size_t cur_index = first_index; - do - { - std::string url; - if (testnet) - { - url = testnet_dns_urls[cur_index]; - } - else - { - url = dns_urls[cur_index]; - } - - records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid); - if (!avail) - { - records[cur_index].clear(); - LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); - } - if (!valid) - { - records[cur_index].clear(); - LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); - } - - cur_index++; - if (cur_index == dns_urls.size()) - { - cur_index = 0; - } - records[cur_index].clear(); - } while (cur_index != first_index); - - size_t num_valid_records = 0; - - for( const auto& record_set : records) - { - if (record_set.size() != 0) - { - num_valid_records++; - } - } - - if (num_valid_records < 2) - { - LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received"); - return true; - } - - int good_records_index = -1; - for (size_t i = 0; i < records.size() - 1; ++i) - { - if (records[i].size() == 0) continue; - - for (size_t j = i + 1; j < records.size(); ++j) - { - if (dns_records_match(records[i], records[j])) - { - good_records_index = i; - break; - } - } - if (good_records_index >= 0) break; - } - - if (good_records_index < 0) - { - LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched"); - return true; - } - - for (auto& record : records[good_records_index]) - { - auto pos = record.find(":"); - if (pos != std::string::npos) - { - uint64_t height; - crypto::hash hash; - - // parse the first part as uint64_t, - // if this fails move on to the next record - std::stringstream ss(record.substr(0, pos)); - if (!(ss >> height)) - { - continue; - } - - // parse the second part as crypto::hash, - // if this fails move on to the next record - std::string hashStr = record.substr(pos + 1); - if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash)) - { - continue; - } - - ADD_CHECKPOINT(height, hashStr); - } - } - return true; -} - -bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath) -{ - // TODO: replace hard-coded url with const string or #define - return (load_checkpoints_from_json(checkpoints, json_hashfile_fullpath) && load_checkpoints_from_dns(checkpoints)); -} - -} // namespace cryptonote diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h deleted file mode 100644 index 83830f8a2..000000000 --- a/src/cryptonote_core/checkpoints_create.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2014-2016, 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. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#pragma once - -#include "checkpoints.h" -#include "misc_log_ex.h" - -#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false); -#define JSON_HASH_FILE_NAME "checkpoints.json" - -namespace cryptonote -{ - - bool create_checkpoints(cryptonote::checkpoints& checkpoints); - - bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath); - bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet = false); - bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath); - -} // namespace cryptonote diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 6f0fe88a4..91e969170 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -42,7 +42,7 @@ using namespace epee; #include "cryptonote_format_utils.h" #include "misc_language.h" #include -#include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/checkpoints.h" #include "blockchain_db/blockchain_db.h" #include "blockchain_db/lmdb/db_lmdb.h" #if defined(BERKELEY_DB) @@ -159,7 +159,7 @@ namespace cryptonote if (!m_testnet && !m_fakechain) { cryptonote::checkpoints checkpoints; - if (!cryptonote::create_checkpoints(checkpoints)) + if (!checkpoints.init_default_checkpoints()) { throw std::runtime_error("Failed to initialize checkpoints"); } diff --git a/src/daemon/core.h b/src/daemon/core.h index 2208ef25a..2b7f0d177 100644 --- a/src/daemon/core.h +++ b/src/daemon/core.h @@ -28,7 +28,6 @@ #pragma once -#include "cryptonote_core/checkpoints_create.h" #include "cryptonote_core/cryptonote_core.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "misc_log_ex.h" -- cgit v1.2.3 From 8ac329df0294f16efbc48a2785eda165878d3511 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 7 Oct 2015 22:28:43 -0400 Subject: doxygen documentation for difficulty functions --- src/cryptonote_core/difficulty.cpp | 6 ++++-- src/cryptonote_core/difficulty.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp index 236e84481..54da77392 100644 --- a/src/cryptonote_core/difficulty.cpp +++ b/src/cryptonote_core/difficulty.cpp @@ -116,8 +116,8 @@ namespace cryptonote { return !carry; } - difficulty_type next_difficulty(vector timestamps, vector cumulative_difficulties, size_t target_seconds) { - //cutoff DIFFICULTY_LAG + difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { + if(timestamps.size() > DIFFICULTY_WINDOW) { timestamps.resize(DIFFICULTY_WINDOW); @@ -151,6 +151,8 @@ namespace cryptonote { assert(total_work > 0); uint64_t low, high; mul(total_work, target_seconds, low, high); + // blockchain errors "difficulty overhead" if this function returns zero. + // TODO: consider throwing an exception instead if (high != 0 || low + time_span - 1 < low) { return 0; } diff --git a/src/cryptonote_core/difficulty.h b/src/cryptonote_core/difficulty.h index d49c2f3b8..910f97035 100644 --- a/src/cryptonote_core/difficulty.h +++ b/src/cryptonote_core/difficulty.h @@ -39,6 +39,18 @@ namespace cryptonote { typedef std::uint64_t difficulty_type; + /** + * @brief checks if a hash fits the given difficulty + * + * The hash passes if (hash * difficulty) < 2^192. + * Phrased differently, if (hash * difficulty) fits without overflow into + * the least significant 192 bits of the 256 bit multiplication result. + * + * @param hash the hash to check + * @param difficulty the difficulty to check against + * + * @return true if valid, else false + */ bool check_hash(const crypto::hash &hash, difficulty_type difficulty); difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); } -- cgit v1.2.3 From 50dba6d30110336047cc45e5bbf9b8e59639277c Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 7 Oct 2015 22:28:51 -0400 Subject: cryptonote::core doxygen documentation --- src/cryptonote_core/cryptonote_core.cpp | 2 +- src/cryptonote_core/cryptonote_core.h | 641 ++++++++++++++++++++++++++++++-- 2 files changed, 617 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 91e969170..eb9718958 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -415,7 +415,7 @@ namespace cryptonote CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints."); r = m_miner.init(vm, m_testnet); - CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); + CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance"); return load_state_data(); } diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 32f0b2ad4..cee9bba3d 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -63,157 +63,748 @@ namespace cryptonote /************************************************************************/ /* */ /************************************************************************/ + + /** + * @brief handles core cryptonote functionality + * + * This class coordinates cryptonote functionality including, but not + * limited to, communication among the Blockchain, the transaction pool, + * any miners, and the network. + */ class core: public i_miner_handler { public: + + /** + * @brief constructor + * + * sets member variables into a usable state + * + * @param pprotocol pre-constructed protocol object to store and use + */ core(i_cryptonote_protocol* pprotocol); + + /** + * @copydoc Blockchain::handle_get_objects + * + * @note see Blockchain::handle_get_objects() + * @param context connection context associated with the request + */ bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote_connection_context& context); + + /** + * @brief calls various idle routines + * + * @note see miner::on_idle and tx_memory_pool::on_idle + * + * @return true + */ bool on_idle(); + + /** + * @brief handles an incoming transaction + * + * Parses an incoming transaction and, if nothing is obviously wrong, + * passes it along to the transaction pool + * + * @param tx_blob the tx to handle + * @param tvc metadata about the transaction's validity + * @param keeped_by_block if the transaction has been in a block + * @param relayed whether or not the transaction was relayed to us + * + * @return true if the transaction made it to the transaction pool, otherwise false + */ bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed); + + /** + * @brief handles an incoming block + * + * periodic update to checkpoints is triggered here + * Attempts to add the block to the Blockchain and, on success, + * optionally updates the miner's block template. + * + * @param block_blob the block to be added + * @param bvc return-by-reference metadata context about the block's validity + * @param update_miner_blocktemplate whether or not to update the miner's block template + * + * @return false if loading new checkpoints fails, or the block is not + * added, otherwise true + */ bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true); + + /** + * @copydoc Blockchain::prepare_handle_incoming_blocks + * + * @note see Blockchain::prepare_handle_incoming_blocks + */ bool prepare_handle_incoming_blocks(const std::list &blocks); - bool cleanup_handle_incoming_blocks(bool force_sync = false); + /** + * @copydoc Blockchain::cleanup_handle_incoming_blocks + * + * @note see Blockchain::cleanup_handle_incoming_blocks + */ + bool cleanup_handle_incoming_blocks(bool force_sync = false); + + /** + * @brief check the size of a block against the current maximum + * + * @param block_blob the block to check + * + * @return whether or not the block is too big + */ bool check_incoming_block_size(const blobdata& block_blob) const; + + /** + * @brief get the cryptonote protocol instance + * + * @return the instance + */ i_cryptonote_protocol* get_protocol(){return m_pprotocol;} //-------------------- i_miner_handler ----------------------- + + /** + * @brief stores and relays a block found by a miner + * + * Updates the miner's target block, attempts to store the found + * block in Blockchain, and -- on success -- relays that block to + * the network. + * + * @param b the block found + * + * @return true if the block was added to the main chain, otherwise false + */ virtual bool handle_block_found( block& b); + + /** + * @copydoc Blockchain::create_block_template + * + * @note see Blockchain::create_block_template + */ virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce); + /** + * @brief gets the miner instance + * + * @return a reference to the miner instance + */ miner& get_miner(){return m_miner;} + + /** + * @brief gets the miner instance (const) + * + * @return a const reference to the miner instance + */ const miner& get_miner()const{return m_miner;} + + /** + * @brief adds command line options to the given options set + * + * As of now, there are no command line options specific to core, + * so this function simply returns. + * + * @param desc return-by-reference the command line options set to add to + */ static void init_options(boost::program_options::options_description& desc); + + /** + * @brief initializes the core as needed + * + * This function initializes the transaction pool, the Blockchain, and + * a miner instance with parameters given on the command line (or defaults) + * + * @param vm command line parameters + * @param test_options configuration options for testing + * + * @return false if one of the init steps fails, otherwise true + */ bool init(const boost::program_options::variables_map& vm, const test_options *test_options = NULL); + + /** + * @copydoc Blockchain::reset_and_set_genesis_block + * + * @note see Blockchain::reset_and_set_genesis_block + */ bool set_genesis_block(const block& b); + + /** + * @brief performs safe shutdown steps for core and core components + * + * Uninitializes the miner instance, transaction pool, and Blockchain + * + * if m_fast_exit is set, the call to Blockchain::deinit() is not made. + * + * @return true + */ bool deinit(); + + /** + * @brief sets fast exit flag + * + * @note see deinit() + */ static void set_fast_exit(); + + /** + * @brief gets the current state of the fast exit flag + * + * @return the fast exit flag + * + * @note see deinit() + */ static bool get_fast_exit(); + + /** + * @brief sets to drop blocks downloaded (for testing) + */ void test_drop_download(); + + /** + * @brief sets to drop blocks downloaded below a certain height + * + * @param height height below which to drop blocks + */ void test_drop_download_height(uint64_t height); + + /** + * @brief gets whether or not to drop blocks (for testing) + * + * @return whether or not to drop blocks + */ bool get_test_drop_download() const; + + /** + * @brief gets whether or not to drop blocks + * + * If the current blockchain height <= our block drop threshold + * and test drop blocks is set, return true + * + * @return see above + */ bool get_test_drop_download_height() const; + + /** + * @copydoc Blockchain::get_current_blockchain_height + * + * @note see Blockchain::get_current_blockchain_height() + */ uint64_t get_current_blockchain_height() const; bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const; + + /** + * @brief get the hash and height of the most recent block + * + * @param height return-by-reference height of the block + * @param top_id return-by-reference hash of the block + * + * @return true + */ + bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) const; + + /** + * @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list&, std::list&) const + * + * @note see Blockchain::get_blocks(uint64_t, size_t, std::list&, std::list&) const + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const; + + /** + * @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list&) const + * + * @note see Blockchain::get_blocks(uint64_t, size_t, std::list&) const + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const; + + /** + * @copydoc Blockchain::get_blocks(const t_ids_container&, t_blocks_container&, t_missed_container&) const + * + * @note see Blockchain::get_blocks(const t_ids_container&, t_blocks_container&, t_missed_container&) const + */ template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const { return m_blockchain_storage.get_blocks(block_ids, blocks, missed_bs); } + + /** + * @copydoc Blockchain::get_block_id_by_height + * + * @note see Blockchain::get_block_id_by_height + */ crypto::hash get_block_id_by_height(uint64_t height) const; + + /** + * @copydoc Blockchain::get_transactions + * + * @note see Blockchain::get_transactions + */ bool get_transactions(const std::vector& txs_ids, std::list& txs, std::list& missed_txs) const; + + /** + * @copydoc Blockchain::get_block_by_hash + * + * @note see Blockchain::get_block_by_hash + */ bool get_block_by_hash(const crypto::hash &h, block &blk) const; //void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid); + /** + * @copydoc Blockchain::get_alternative_blocks + * + * @note see Blockchain::get_alternative_blocks(std::list&) const + */ bool get_alternative_blocks(std::list& blocks) const; + + /** + * @copydoc Blockchain::get_alternative_blocks_count + * + * @note see Blockchain::get_alternative_blocks_count() const + */ size_t get_alternative_blocks_count() const; + /** + * @brief set the pointer to the cryptonote protocol object to use + * + * @param pprotocol the pointer to set ours as + */ void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol); + + /** + * @copydoc Blockchain::set_checkpoints + * + * @note see Blockchain::set_checkpoints() + */ void set_checkpoints(checkpoints&& chk_pts); + + /** + * @brief set the file path to read from when loading checkpoints + * + * @param path the path to set ours as + */ void set_checkpoints_file_path(const std::string& path); + + /** + * @brief set whether or not we enforce DNS checkpoints + * + * @param enforce_dns enforce DNS checkpoints or not + */ void set_enforce_dns_checkpoints(bool enforce_dns); + /** + * @copydoc tx_memory_pool::get_transactions + * + * @note see tx_memory_pool::get_transactions + */ bool get_pool_transactions(std::list& txs) const; + + /** + * @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info + * + * @note see tx_memory_pool::get_pool_transactions_and_spent_keys_info + */ bool get_pool_transactions_and_spent_keys_info(std::vector& tx_infos, std::vector& key_image_infos) const; + + /** + * @copydoc tx_memory_pool::get_transactions_count + * + * @note see tx_memory_pool::get_transactions_count + */ size_t get_pool_transactions_count() const; + + /** + * @copydoc Blockchain::get_total_transactions + * + * @note see Blockchain::get_total_transactions + */ size_t get_blockchain_total_transactions() const; //bool get_outs(uint64_t amount, std::list& pkeys); + + /** + * @copydoc Blockchain::have_block + * + * @note see Blockchain::have_block + */ bool have_block(const crypto::hash& id) const; + + /** + * @copydoc Blockchain::get_short_chain_history + * + * @note see Blockchain::get_short_chain_history + */ bool get_short_chain_history(std::list& ids) const; + + /** + * @copydoc Blockchain::find_blockchain_supplement(const std::list&, NOTIFY_RESPONSE_CHAIN_ENTRY::request&) const + * + * @note see Blockchain::find_blockchain_supplement(const std::list&, NOTIFY_RESPONSE_CHAIN_ENTRY::request&) const + */ bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const; + + /** + * @copydoc Blockchain::find_blockchain_supplement(const uint64_t, const std::list&, std::list > >&, uint64_t&, uint64_t&, size_t) const + * + * @note see Blockchain::find_blockchain_supplement(const uint64_t, const std::list&, std::list > >&, uint64_t&, uint64_t&, size_t) const + */ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const; + + /** + * @brief gets some stats about the daemon + * + * @param st_inf return-by-reference container for the stats requested + * + * @return true + */ bool get_stat_info(core_stat_info& st_inf) const; //bool get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count); + + /** + * @copydoc Blockchain::get_tx_outputs_gindexs + * + * @note see Blockchain::get_tx_outputs_gindexs + */ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; + + /** + * @copydoc Blockchain::get_tail_id + * + * @note see Blockchain::get_tail_id + */ crypto::hash get_tail_id() const; + + /** + * @copydoc Blockchain::get_random_outs_for_amounts + * + * @note see Blockchain::get_random_outs_for_amounts + */ bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const; + + + /** + * @copydoc miner::pause + * + * @note see miner::pause + */ void pause_mine(); + + /** + * @copydoc miner::resume + * + * @note see miner::resume + */ void resume_mine(); + #if BLOCKCHAIN_DB == DB_LMDB + /** + * @brief gets the Blockchain instance + * + * @return a reference to the Blockchain instance + */ Blockchain& get_blockchain_storage(){return m_blockchain_storage;} + + /** + * @brief gets the Blockchain instance (const) + * + * @return a const reference to the Blockchain instance + */ const Blockchain& get_blockchain_storage()const{return m_blockchain_storage;} #else blockchain_storage& get_blockchain_storage(){return m_blockchain_storage;} const blockchain_storage& get_blockchain_storage()const{return m_blockchain_storage;} #endif - //debug functions + + /** + * @copydoc Blockchain::print_blockchain + * + * @note see Blockchain::print_blockchain + */ void print_blockchain(uint64_t start_index, uint64_t end_index) const; + + /** + * @copydoc Blockchain::print_blockchain_index + * + * @note see Blockchain::print_blockchain_index + */ void print_blockchain_index() const; + + /** + * @copydoc tx_memory_pool::print_pool + * + * @note see tx_memory_pool::print_pool + */ std::string print_pool(bool short_format) const; + + /** + * @copydoc Blockchain::print_blockchain_outs + * + * @note see Blockchain::print_blockchain_outs + */ void print_blockchain_outs(const std::string& file); + + /** + * @copydoc miner::on_synchronized + * + * @note see miner::on_synchronized + */ void on_synchronized(); + /** + * @brief sets the target blockchain height + * + * @param target_blockchain_height the height to set + */ void set_target_blockchain_height(uint64_t target_blockchain_height); + + /** + * @brief gets the target blockchain height + * + * @param target_blockchain_height the target height + */ uint64_t get_target_blockchain_height() const; + /** + * @brief tells the Blockchain to update its checkpoints + * + * This function will check if enough time has passed since the last + * time checkpoints were updated and tell the Blockchain to update + * its checkpoints if it is time. If updating checkpoints fails, + * the daemon is told to shut down. + * + * @note see Blockchain::update_checkpoints() + */ bool update_checkpoints(); + /** + * @brief tells the daemon to wind down operations and stop running + * + * Currently this function raises SIGTERM, allowing the installed signal + * handlers to do the actual stopping. + */ + void graceful_exit(); + + /** + * @brief stops the daemon running + * + * @note see graceful_exit() + */ void stop(); + /** + * @copydoc Blockchain::have_tx_keyimg_as_spent + * + * @note see Blockchain::have_tx_keyimg_as_spent + */ bool is_key_image_spent(const crypto::key_image& key_im) const; + + /** + * @brief check if multiple key images are spent + * + * plural version of is_key_image_spent() + * + * @param key_im list of key images to check + * @param spent return-by-reference result for each image checked + * + * @return true + */ bool are_key_images_spent(const std::vector& key_im, std::vector &spent) const; private: + + /** + * @copydoc add_new_tx(const transaction&, tx_verification_context&, bool) + * + * @param tx_hash the transaction's hash + * @param tx_prefix_hash the transaction prefix' hash + * @param blob_size the size of the transaction + * @param relayed whether or not the transaction was relayed to us + * + */ bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed); + + /** + * @brief add a new transaction to the transaction pool + * + * Adds a new transaction to the transaction pool. + * + * @param tx the transaction to add + * @param tvc return-by-reference metadata about the transaction's verification process + * @param keeped_by_block whether or not the transaction has been in a block + * @param relayed whether or not the transaction was relayed to us + * + * @return true if the transaction is already in the transaction pool, + * is already in a block on the Blockchain, or is successfully added + * to the transaction pool + */ bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed); + + /** + * @copydoc Blockchain::add_new_block + * + * @note see Blockchain::add_new_block + */ bool add_new_block(const block& b, block_verification_context& bvc); + + /** + * @brief load any core state stored on disk + * + * currently does nothing, but may have state to load in the future. + * + * @return true + */ bool load_state_data(); + + /** + * @copydoc parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const + * + * @note see parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const + */ bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob) const; + /** + * @brief check a transaction's syntax + * + * For now this does nothing, but it may check something about the tx + * in the future. + * + * @param tx the transaction to check + * + * @return true + */ bool check_tx_syntax(const transaction& tx) const; //check correct values, amounts and all lightweight checks not related with database + + /** + * @brief validates some simple properties of a transaction + * + * Currently checks: tx has inputs, + * tx inputs all of supported type(s), + * tx outputs valid (type, key, amount), + * input and output total amounts don't overflow, + * output amount <= input amount, + * tx not too large, + * each input has a different key image. + * + * @param tx the transaction to check + * @param keeped_by_block if the transaction has been in a block + * + * @return true if all the checks pass, otherwise false + */ bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const; //check if tx already in memory pool or in main blockchain bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector& sig) const; bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; + /** + * @copydoc miner::on_block_chain_update + * + * @note see miner::on_block_chain_update + * + * @return true + */ bool update_miner_block_template(); + + /** + * @brief act on a set of command line options given + * + * @param vm the command line options + * + * @return true + */ bool handle_command_line(const boost::program_options::variables_map& vm); bool on_update_blocktemplate_interval(); + + /** + * @brief verify that each input key image in a transaction is unique + * + * @param tx the transaction to check + * + * @return false if any key image is repeated, otherwise true + */ bool check_tx_inputs_keyimages_diff(const transaction& tx) const; - void graceful_exit(); + + /** + * @brief checks HardFork status and prints messages about it + * + * Checks the status of HardFork and logs/prints if an update to + * the daemon is necessary. + * + * @note see Blockchain::get_hard_fork_state and HardFork::State + * + * @return true + */ bool check_fork_time(); + + /** + * @brief attempts to relay any transactions in the mempool which need it + * + * @return true + */ bool relay_txpool_transactions(); + + /** + * @brief locks a file in the BlockchainDB directory + * + * @param path the directory in which to place the file + * + * @return true if lock acquired successfully, otherwise false + */ bool lock_db_directory(const boost::filesystem::path &path); + + /** + * @brief unlocks the db directory + * + * @note see lock_db_directory() + * + * @return true + */ bool unlock_db_directory(); - static std::atomic m_fast_exit; - bool m_test_drop_download = true; - uint64_t m_test_drop_download_height = 0; + static std::atomic m_fast_exit; //!< whether or not to deinit Blockchain on exit + + bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing) - tx_memory_pool m_mempool; + uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so + + tx_memory_pool m_mempool; //!< transaction pool instance #if BLOCKCHAIN_DB == DB_LMDB - Blockchain m_blockchain_storage; + Blockchain m_blockchain_storage; //!< Blockchain instance #else blockchain_storage m_blockchain_storage; #endif - i_cryptonote_protocol* m_pprotocol; - epee::critical_section m_incoming_tx_lock; + + i_cryptonote_protocol* m_pprotocol; //!< cryptonote protocol instance + + epee::critical_section m_incoming_tx_lock; //!< incoming transaction lock + //m_miner and m_miner_addres are probably temporary here - miner m_miner; - account_public_address m_miner_address; - std::string m_config_folder; - cryptonote_protocol_stub m_protocol_stub; - epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; - epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; + 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 + + cryptonote_protocol_stub m_protocol_stub; //!< cryptonote protocol stub instance + + epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled + epee::math_helper::once_a_time_seconds<60*60*2, false> m_fork_moaner; //!< interval for checking HardFork status epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions + friend class tx_validate_inputs; - std::atomic m_starter_message_showed; + std::atomic m_starter_message_showed; //!< has the "daemon will sync now" message been shown? + + uint64_t m_target_blockchain_height; //!< blockchain height target + + bool m_testnet; //!< are we on testnet? - uint64_t m_target_blockchain_height; + bool m_fakechain; //!< are we using a fake chain (for testing purposes)? - bool m_testnet; - bool m_fakechain; - std::string m_checkpoints_path; - time_t m_last_dns_checkpoints_update; - time_t m_last_json_checkpoints_update; + std::string m_checkpoints_path; //!< path to json checkpoints file + time_t m_last_dns_checkpoints_update; //!< time when dns checkpoints were last updated + time_t m_last_json_checkpoints_update; //!< time when json checkpoints were last updated - std::atomic_flag m_checkpoints_updating; + std::atomic_flag m_checkpoints_updating; //!< set if checkpoints are currently updating to avoid multiple threads attempting to update at once - boost::interprocess::file_lock db_lock; + boost::interprocess::file_lock db_lock; //!< a lock object for a file lock in the db directory }; } -- cgit v1.2.3 From c835215ea9756bf374b4cc7a8e7a95699b00de1d Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 7 Oct 2015 22:28:54 -0400 Subject: remove defunct code from cryptonote::core --- src/cryptonote_core/cryptonote_core.cpp | 13 ------------- src/cryptonote_core/cryptonote_core.h | 9 --------- 2 files changed, 22 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index eb9718958..c31be5acf 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -634,11 +634,6 @@ namespace cryptonote return m_blockchain_storage.get_total_transactions(); } //----------------------------------------------------------------------------------------------- - //bool core::get_outs(uint64_t amount, std::list& pkeys) - //{ - // return m_blockchain_storage.get_outs(amount, pkeys); - //} - //----------------------------------------------------------------------------------------------- bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed) { if(m_mempool.have_tx(tx_hash)) @@ -770,10 +765,6 @@ namespace cryptonote { m_miner.on_synchronized(); } - //bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count) - //{ - // return m_blockchain_storage.get_backward_blocks_sizes(from_height, sizes, count); - //} //----------------------------------------------------------------------------------------------- bool core::add_new_block(const block& b, block_verification_context& bvc) { @@ -894,10 +885,6 @@ namespace cryptonote return m_blockchain_storage.get_block_by_hash(h, blk); } //----------------------------------------------------------------------------------------------- - //void core::get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) { - // m_blockchain_storage.get_all_known_block_ids(main, alt, invalid); - //} - //----------------------------------------------------------------------------------------------- std::string core::print_pool(bool short_format) const { return m_mempool.print_pool(short_format); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index cee9bba3d..30384209f 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -291,7 +291,6 @@ namespace cryptonote * @note see Blockchain::get_current_blockchain_height() */ uint64_t get_current_blockchain_height() const; - bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const; /** * @brief get the hash and height of the most recent block @@ -348,7 +347,6 @@ namespace cryptonote * @note see Blockchain::get_block_by_hash */ bool get_block_by_hash(const crypto::hash &h, block &blk) const; - //void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid); /** * @copydoc Blockchain::get_alternative_blocks @@ -419,7 +417,6 @@ namespace cryptonote * @note see Blockchain::get_total_transactions */ size_t get_blockchain_total_transactions() const; - //bool get_outs(uint64_t amount, std::list& pkeys); /** * @copydoc Blockchain::have_block @@ -457,7 +454,6 @@ namespace cryptonote * @return true */ bool get_stat_info(core_stat_info& st_inf) const; - //bool get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count); /** * @copydoc Blockchain::get_tx_outputs_gindexs @@ -672,7 +668,6 @@ namespace cryptonote * @return true */ bool check_tx_syntax(const transaction& tx) const; - //check correct values, amounts and all lightweight checks not related with database /** * @brief validates some simple properties of a transaction @@ -691,10 +686,7 @@ namespace cryptonote * @return true if all the checks pass, otherwise false */ bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const; - //check if tx already in memory pool or in main blockchain - bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector& sig) const; - bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; /** * @copydoc miner::on_block_chain_update * @@ -712,7 +704,6 @@ namespace cryptonote * @return true */ bool handle_command_line(const boost::program_options::variables_map& vm); - bool on_update_blocktemplate_interval(); /** * @brief verify that each input key image in a transaction is unique -- cgit v1.2.3 From bfd4a28c4100cf94f6e8bb6f038e0bd1b6c41059 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 1 Dec 2015 17:38:22 -0500 Subject: Update BlockchainDB documentation BlockchainDB is now Doxygen-compliant and its documentation is up-to-date with recent changes. --- src/blockchain_db/blockchain_db.h | 1092 +++++++++++++++++++++++++++++++------ 1 file changed, 937 insertions(+), 155 deletions(-) (limited to 'src') diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 3396b8c20..3e0ca141e 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -38,18 +38,20 @@ #include "cryptonote_core/difficulty.h" #include "cryptonote_core/hardfork.h" -/* DB Driver Interface +/** \file + * Cryptonote Blockchain Database Interface * * The DB interface is a store for the canonical block chain. * It serves as a persistent storage for the blockchain. * - * For the sake of efficiency, the reference implementation will also + * For the sake of efficiency, a concrete implementation may also * store some blockchain data outside of the blocks, such as spent * transfer key images, unspent transaction outputs, etc. * + * Examples are as follows: + * * Transactions are duplicated so that we don't have to fetch a whole block - * in order to fetch a transaction from that block. If this is deemed - * unnecessary later, this can change. + * in order to fetch a transaction from that block. * * Spent key images are duplicated outside of the blocks so it is quick * to verify an output hasn't already been spent @@ -57,100 +59,34 @@ * Unspent transaction outputs are duplicated to quickly gather random * outputs to use for mixins * - * IMPORTANT: - * A concrete implementation of this interface should populate these - * duplicated members! It is possible to have a partial implementation - * of this interface call to private members of the interface to be added - * later that will then populate as needed. - * - * General: - * open() - * is_open() - * close() - * sync() - * reset() - * - * Lock and unlock provided for reorg externally, and for block - * additions internally, this way threaded reads are completely fine - * unless the blockchain is changing. - * bool lock() - * unlock() - * - * vector get_filenames() - * - * Blocks: - * bool block_exists(hash) - * height add_block(block, block_size, cumulative_difficulty, coins_generated, transactions) - * block get_block(hash) - * height get_block_height(hash) - * header get_block_header(hash) - * block get_block_from_height(height) - * size_t get_block_size(height) - * difficulty get_block_cumulative_difficulty(height) - * uint64_t get_block_already_generated_coins(height) - * uint64_t get_block_timestamp(height) - * uint64_t get_top_block_timestamp() - * hash get_block_hash_from_height(height) - * blocks get_blocks_range(height1, height2) - * hashes get_hashes_range(height1, height2) - * hash top_block_hash() - * block get_top_block() - * height height() - * void pop_block(block&, tx_list&) - * - * Transactions: - * bool tx_exists(hash) - * uint64_t get_tx_unlock_time(hash) - * tx get_tx(hash) - * uint64_t get_tx_count() - * tx_list get_tx_list(hash_list) - * height get_tx_block_height(hash) - * - * Outputs: - * uint64_t get_num_outputs(amount) - * pub_key get_output_key(amount, index) - * hash,index get_output_tx_and_index_from_global(index) - * hash,index get_output_tx_and_index(amount, index) - * vec get_tx_output_indices(tx_hash) - * - * - * Spent Output Key Images: - * bool has_key_image(key_image) - * - * Exceptions: - * DB_ERROR -- generic - * DB_OPEN_FAILURE - * DB_CREATE_FAILURE - * DB_SYNC_FAILURE - * BLOCK_DNE - * BLOCK_PARENT_DNE - * BLOCK_EXISTS - * BLOCK_INVALID -- considering making this multiple errors - * TX_DNE - * TX_EXISTS - * OUTPUT_DNE - * OUTPUT_EXISTS - * KEY_IMAGE_EXISTS */ namespace cryptonote { -// typedef for convenience +/** a pair of , typedef for convenience */ typedef std::pair tx_out_index; #pragma pack(push, 1) + +/** + * @brief a struct containing output metadata + */ struct output_data_t { - crypto::public_key pubkey; - uint64_t unlock_time; - uint64_t height; + crypto::public_key pubkey; //!< the output's public key (for spend verification) + uint64_t unlock_time; //!< the output's unlock time (or height) + uint64_t height; //!< the height of the block which created the output }; #pragma pack(pop) /*********************************** * Exception Definitions ***********************************/ + +/** + * @brief A base class for BlockchainDB exceptions + */ class DB_EXCEPTION : public std::exception { private: @@ -168,6 +104,9 @@ class DB_EXCEPTION : public std::exception } }; +/** + * @brief A generic BlockchainDB exception + */ class DB_ERROR : public DB_EXCEPTION { public: @@ -175,7 +114,9 @@ class DB_ERROR : public DB_EXCEPTION DB_ERROR(const char* s) : DB_EXCEPTION(s) { } }; -// For distinguishing errors trying to set up a DB txn from other errors +/** + * @brief thrown when there is an error starting a DB transaction + */ class DB_ERROR_TXN_START : public DB_EXCEPTION { public: @@ -183,6 +124,9 @@ class DB_ERROR_TXN_START : public DB_EXCEPTION DB_ERROR_TXN_START(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when opening the BlockchainDB fails + */ class DB_OPEN_FAILURE : public DB_EXCEPTION { public: @@ -190,6 +134,9 @@ class DB_OPEN_FAILURE : public DB_EXCEPTION DB_OPEN_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when creating the BlockchainDB fails + */ class DB_CREATE_FAILURE : public DB_EXCEPTION { public: @@ -197,6 +144,9 @@ class DB_CREATE_FAILURE : public DB_EXCEPTION DB_CREATE_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when synchronizing the BlockchainDB to disk fails + */ class DB_SYNC_FAILURE : public DB_EXCEPTION { public: @@ -204,6 +154,9 @@ class DB_SYNC_FAILURE : public DB_EXCEPTION DB_SYNC_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a requested block does not exist + */ class BLOCK_DNE : public DB_EXCEPTION { public: @@ -211,6 +164,9 @@ class BLOCK_DNE : public DB_EXCEPTION BLOCK_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a block's parent does not exist (and it needed to) + */ class BLOCK_PARENT_DNE : public DB_EXCEPTION { public: @@ -218,6 +174,9 @@ class BLOCK_PARENT_DNE : public DB_EXCEPTION BLOCK_PARENT_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a block exists, but shouldn't, namely when adding a block + */ class BLOCK_EXISTS : public DB_EXCEPTION { public: @@ -225,6 +184,9 @@ class BLOCK_EXISTS : public DB_EXCEPTION BLOCK_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when something is wrong with the block to be added + */ class BLOCK_INVALID : public DB_EXCEPTION { public: @@ -232,6 +194,9 @@ class BLOCK_INVALID : public DB_EXCEPTION BLOCK_INVALID(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a requested transaction does not exist + */ class TX_DNE : public DB_EXCEPTION { public: @@ -239,6 +204,9 @@ class TX_DNE : public DB_EXCEPTION TX_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a transaction exists, but shouldn't, namely when adding a block + */ class TX_EXISTS : public DB_EXCEPTION { public: @@ -246,6 +214,9 @@ class TX_EXISTS : public DB_EXCEPTION TX_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a requested output does not exist + */ class OUTPUT_DNE : public DB_EXCEPTION { public: @@ -253,6 +224,9 @@ class OUTPUT_DNE : public DB_EXCEPTION OUTPUT_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when an output exists, but shouldn't, namely when adding a block + */ class OUTPUT_EXISTS : public DB_EXCEPTION { public: @@ -260,6 +234,9 @@ class OUTPUT_EXISTS : public DB_EXCEPTION OUTPUT_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a spent key image exists, but shouldn't, namely when adding a block + */ class KEY_IMAGE_EXISTS : public DB_EXCEPTION { public: @@ -272,6 +249,18 @@ class KEY_IMAGE_EXISTS : public DB_EXCEPTION ***********************************/ +/** + * @brief The BlockchainDB backing store interface declaration/contract + * + * This class provides a uniform interface for using BlockchainDB to store + * a blockchain. Any implementation of this class will also implement all + * functions exposed here, so one can use this class without knowing what + * implementation is being used. Refer to each pure virtual function's + * documentation here when implementing a BlockchainDB subclass. + * + * A subclass which encounters an issue should report that issue by throwing + * a DB_EXCEPTION which adequately conveys the issue. + */ class BlockchainDB { private: @@ -279,7 +268,22 @@ private: * private virtual members *********************************************************************/ - // tells the subclass to add the block and metadata to storage + /** + * @brief add the block and metadata to the db + * + * The subclass implementing this will add the specified block and + * block metadata to its backing store. This does not include its + * transactions, those are added in a separate step. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk the block to be added + * @param block_size the size of the block (transactions and all) + * @param cumulative_difficulty the accumulated difficulty after this block + * @param coins_generated the number of coins generated total after this block + * @param blk_hash the hash of the block + */ virtual void add_block( const block& blk , const size_t& block_size , const difficulty_type& cumulative_difficulty @@ -287,84 +291,274 @@ private: , const crypto::hash& blk_hash ) = 0; - // tells the subclass to remove data about the top block + /** + * @brief remove data about the top block + * + * The subclass implementing this will remove the block data from the top + * block in the chain. The data to be removed is that which was added in + * BlockchainDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash) + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void remove_block() = 0; - // tells the subclass to store the transaction and its metadata + /** + * @brief store the transaction and its metadata + * + * The subclass implementing this will add the specified transaction data + * to its backing store. This includes only the transaction blob itself + * and the other data passed here, not the separate outputs of the + * transaction. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk_hash the hash of the block containing the transaction + * @param tx the transaction to be added + * @param tx_hash the hash of the transaction + */ virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0; - // tells the subclass to remove data about a transaction + /** + * @brief remove data about a transaction + * + * The subclass implementing this will remove the transaction data + * for the passed transaction. The data to be removed was added in + * add_transaction_data(). Additionally, current subclasses have behavior + * which requires the transaction itself as a parameter here. Future + * implementations should note that this parameter is subject to be removed + * at a later time. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_hash the hash of the transaction to be removed + * @param tx the transaction + */ virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0; - // tells the subclass to store an output + /** + * @brief store an output + * + * The subclass implementing this will add the output data passed to its + * backing store in a suitable manner. In addition, the subclass is responsible + * for keeping track of the global output count in some manner, so that + * outputs may be indexed by the order in which they were created. In the + * future, this tracking (of the number, at least) should be moved to + * this class, as it is necessary and the same among all BlockchainDB. + * + * This data should be stored in such a manner that the only thing needed to + * reverse the process is the tx_out. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_hash hash of the transaction the output was created by + * @param tx_output the output + * @param local_index index of the output in its transaction + * @param unlock_time unlock time/height of the output + */ virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) = 0; - // tells the subclass to remove an output + /** + * @brief remove an output + * + * The subclass implementing this will remove all output data it stored + * in add_output(). + * + * In addition, the subclass is responsible for correctly decrementing + * its global output counter (this may be automatic for some, such as using + * a database backend "count" feature). + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_output the output to be removed + */ virtual void remove_output(const tx_out& tx_output) = 0; - // tells the subclass to store a spent key + /** + * @brief store a spent key + * + * The subclass implementing this will store the spent key image. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param k_image the spent key image to store + */ virtual void add_spent_key(const crypto::key_image& k_image) = 0; - // tells the subclass to remove a spent key + /** + * @brief remove a spent key + * + * The subclass implementing this will remove the key image. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param k_image the spent key image to remove + */ virtual void remove_spent_key(const crypto::key_image& k_image) = 0; /********************************************************************* * private concrete members *********************************************************************/ - // private version of pop_block, for undoing if an add_block goes tits up + /** + * @brief private version of pop_block, for undoing if an add_block fails + * + * This function simply calls pop_block(block& blk, std::vector& txs) + * with dummy parameters, as the returns-by-reference can be discarded. + */ void pop_block(); - // helper function for add_transactions, to add each individual tx + /** + * @brief helper function for add_transactions, to add each individual transaction + * + * This function is called by add_transactions() for each transaction to be + * added. + * + * @param blk_hash hash of the block which has the transaction + * @param tx the transaction to add + * @param tx_hash_ptr the hash of the transaction, if already calculated + */ void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL); // helper function to remove transaction from blockchain + /** + * @brief helper function to remove transaction from the blockchain + * + * This function encapsulates aspects of removing a transaction. + * + * @param tx_hash the hash of the transaction to be removed + */ void remove_transaction(const crypto::hash& tx_hash); - uint64_t num_calls = 0; - uint64_t time_blk_hash = 0; - uint64_t time_add_block1 = 0; - uint64_t time_add_transaction = 0; + uint64_t num_calls = 0; //!< a performance metric + uint64_t time_blk_hash = 0; //!< a performance metric + uint64_t time_add_block1 = 0; //!< a performance metric + uint64_t time_add_transaction = 0; //!< a performance metric protected: - mutable uint64_t time_tx_exists = 0; - uint64_t time_commit1 = 0; - bool m_auto_remove_logs = true; + mutable uint64_t time_tx_exists = 0; //!< a performance metric + uint64_t time_commit1 = 0; //!< a performance metric + bool m_auto_remove_logs = true; //!< whether or not to automatically remove old logs HardFork* m_hardfork; public: - // virtual dtor + /** + * @brief An empty destructor. + */ virtual ~BlockchainDB() { }; - // reset profiling stats + /** + * @brief reset profiling stats + */ void reset_stats(); - // show profiling stats + /** + * @brief show profiling stats + * + * This function prints current performance/profiling data to whichever + * log file(s) are set up (possibly including stdout or stderr) + */ void show_stats(); - // open the db at location , or create it if there isn't one. + /** + * @brief open a db, or create it if necessary. + * + * This function opens an existing database or creates it if it + * does not exist. + * + * The subclass implementing this will handle all file opening/creation, + * and is responsible for maintaining its state. + * + * The parameter may not refer to a file name, necessarily, but + * could be an IP:PORT for a database which needs it, and so on. Calling it + * is convenient and should be descriptive enough, however. + * + * For now, db_flags are + * specific to the subclass being instantiated. This is subject to change, + * and the db_flags parameter may be deprecated. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param filename a string referring to the BlockchainDB to open + * @param db_flags flags relevant to how to open/use the BlockchainDB + */ virtual void open(const std::string& filename, const int db_flags = 0) = 0; - // returns true of the db is open/ready, else false + /** + * @brief Gets the current open/ready state of the BlockchainDB + * + * @return true if open/ready, otherwise false + */ bool is_open() const; - // close and sync the db + /** + * @brief close the BlockchainDB + * + * At minimum, this call ensures that further use of the BlockchainDB + * instance will not have effect. In any case where it is necessary + * to do so, a subclass implementing this will sync with disk. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void close() = 0; - // sync the db + /** + * @brief sync the BlockchainDB with disk + * + * This function should write any changes to whatever permanent backing + * store the subclass uses. Example: a BlockchainDB instance which + * keeps the whole blockchain in RAM won't need to regularly access a + * disk, but should write out its state when this is called. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void sync() = 0; - // reset the db -- USE WITH CARE + /** + * @brief Remove everything from the BlockchainDB + * + * This function should completely remove all data from a BlockchainDB. + * + * Use with caution! + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void reset() = 0; - // get all files used by this db (if any) + /** + * @brief get all files used by the BlockchainDB (if any) + * + * This function is largely for ease of automation, namely for unit tests. + * + * The subclass implementation should return all filenames it uses. + * + * @return a list of filenames + */ virtual std::vector get_filenames() const = 0; // return the name of the folder the db's file(s) should reside in + /** + * @brief gets the name of the folder the BlockchainDB's file(s) should be in + * + * The subclass implementation should return the name of the folder in which + * it stores files, or an empty string if there is none. + * + * @return the name of the folder with the BlockchainDB's files, if any. + */ virtual std::string get_db_name() const = 0; @@ -372,13 +566,86 @@ public: // RAII-friendly and multi-read one-write friendly locking mechanism // // acquire db lock + /** + * @brief acquires the BlockchainDB lock + * + * This function is a stub until such a time as locking is implemented at + * this level. + * + * The subclass implementation should return true unless implementing a + * locking scheme of some sort, in which case it should return true upon + * acquisition of the lock and block until then. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @return true, unless at a future time false makes sense (timeout, etc) + */ virtual bool lock() = 0; // release db lock + /** + * @brief This function releases the BlockchainDB lock + * + * The subclass, should it have implemented lock(), will release any lock + * held by the calling thread. In the case of recursive locking, it should + * release one instance of a lock. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void unlock() = 0; + /** + * @brief tells the BlockchainDB to start a new "batch" of blocks + * + * If the subclass implements a batching method of caching blocks in RAM to + * be added to a backing store in groups, it should start a batch which will + * end either when has been added or batch_stop() has + * been called. In either case, it should end the batch and write to its + * backing store. + * + * If a batch is already in-progress, this function should throw a DB_ERROR. + * This exception may change in the future if it is deemed necessary to + * have a more granular exception type for this scenario. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param batch_num_blocks number of blocks to batch together + */ virtual void batch_start(uint64_t batch_num_blocks=0) = 0; + + /** + * @brief ends a batch transaction + * + * If the subclass implements batching, this function should store the + * batch it is currently on and mark it finished. + * + * 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_stop() = 0; + + /** + * @brief sets whether or not to batch transactions + * + * If the subclass implements batching, this function tells it to begin + * batching automatically. + * + * If the subclass implements batching and has a batch in-progress, a + * parameter of false should disable batching and call batch_stop() to + * store the current batch. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param bool batch whether or not to use batch transactions. + */ virtual void set_batch_transactions(bool) = 0; virtual void block_txn_start(bool readonly=false) = 0; @@ -388,8 +655,26 @@ public: virtual void set_hard_fork(HardFork* hf); // adds a block with the given metadata to the top of the blockchain, returns the new height - // NOTE: subclass implementations of this (or the functions it calls) need - // to handle undoing any partially-added blocks in the event of a failure. + /** + * @brief handles the addition of a new block to BlockchainDB + * + * This function organizes block addition and calls various functions as + * necessary. + * + * NOTE: subclass implementations of this (or the functions it calls) need + * to handle undoing any partially-added blocks in the event of a failure. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk the block to be added + * @param block_size the size of the block (transactions and all) + * @param cumulative_difficulty the accumulated difficulty after this block + * @param coins_generated the number of coins generated total after this block + * @param txs the transactions in the block + * + * @return the height of the chain post-addition + */ virtual uint64_t add_block( const block& blk , const size_t& block_size , const difficulty_type& cumulative_difficulty @@ -397,142 +682,639 @@ public: , const std::vector& txs ); - // return true if a block with hash exists in the blockchain + /** + * @brief checks if a block exists + * + * @param h the hash of the requested block + * + * @return true of the block exists, otherwise false + */ virtual bool block_exists(const crypto::hash& h) const = 0; - // return block with hash + /** + * @brief fetches the block with the given hash + * + * The subclass should return the requested block. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the block requested + */ virtual block get_block(const crypto::hash& h) const = 0; - // return the height of the block with hash on the blockchain, - // throw if it doesn't exist + /** + * @brief gets the height of the block with a given hash + * + * The subclass should return the requested height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the height + */ virtual uint64_t get_block_height(const crypto::hash& h) const = 0; - // return header for block with hash + /** + * @brief fetch a block header + * + * The subclass should return the block header from the block with + * the given hash. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the block header + */ virtual block_header get_block_header(const crypto::hash& h) const = 0; - // return block at height + /** + * @brief fetch a block by height + * + * The subclass should return the block at the given height. + * + * If the block does not exist, that is to say if the blockchain is not + * that high, then the subclass should throw BLOCK_DNE + * + * @param height the height to look for + * + * @return the block + */ virtual block get_block_from_height(const uint64_t& height) const = 0; - // return timestamp of block at height + /** + * @brief fetch a block's timestamp + * + * The subclass should return the timestamp of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the timestamp + */ virtual uint64_t get_block_timestamp(const uint64_t& height) const = 0; - // return timestamp of most recent block + /** + * @brief fetch the top block's timestamp + * + * The subclass should return the timestamp of the most recent block. + * + * @return the top block's timestamp + */ virtual uint64_t get_top_block_timestamp() const = 0; - // return block size of block at height + /** + * @brief fetch a block's size + * + * The subclass should return the size of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the size + */ virtual size_t get_block_size(const uint64_t& height) const = 0; - // return cumulative difficulty up to and including block at height + /** + * @brief fetch a block's cumulative difficulty + * + * The subclass should return the cumulative difficulty of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the cumulative difficulty + */ virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const = 0; - // return difficulty of block at height + /** + * @brief fetch a block's difficulty + * + * The subclass should return the difficulty of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the difficulty + */ virtual difficulty_type get_block_difficulty(const uint64_t& height) const = 0; - // return number of coins generated up to and including block at height + /** + * @brief fetch a block's already generated coins + * + * The subclass should return the total coins generated as of the block + * with the given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the already generated coins + */ virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const = 0; - // return hash of block at height + /** + * @brief fetch a block's hash + * + * The subclass should return hash of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the hash + */ virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const = 0; - // return vector of blocks in range of height (inclusively) + /** + * @brief fetch a list of blocks + * + * The subclass should return a vector of blocks with heights starting at + * h1 and ending at h2, inclusively. + * + * If the height range requested goes past the end of the blockchain, + * the subclass should throw BLOCK_DNE. (current implementations simply + * don't catch this exception as thrown by methods called within) + * + * @param h1 the start height + * @param h2 the end height + * + * @return a vector of blocks + */ virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const = 0; - // return vector of block hashes in range of height (inclusively) + /** + * @brief fetch a list of block hashes + * + * The subclass should return a vector of block hashes from blocks with + * heights starting at h1 and ending at h2, inclusively. + * + * If the height range requested goes past the end of the blockchain, + * the subclass should throw BLOCK_DNE. (current implementations simply + * don't catch this exception as thrown by methods called within) + * + * @param h1 the start height + * @param h2 the end height + * + * @return a vector of block hashes + */ virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const = 0; - // return the hash of the top block on the chain + /** + * @brief fetch the top block's hash + * + * The subclass should return the hash of the most recent block + * + * @return the top block's hash + */ virtual crypto::hash top_block_hash() const = 0; - // return the block at the top of the blockchain + /** + * @brief fetch the top block + * + * The subclass should return most recent block + * + * @return the top block + */ virtual block get_top_block() const = 0; - // return the height of the chain + /** + * @brief fetch the current blockchain height + * + * The subclass should return the current blockchain height + * + * @return the current blockchain height + */ virtual uint64_t height() const = 0; - // pops the top block off the blockchain. - // Returns by reference the popped block and its associated transactions - // - // IMPORTANT: - // When a block is popped, the transactions associated with it need to be - // removed, as well as outputs and spent key images associated with - // those transactions. + + /** + * + * + * @brief pops the top block off the blockchain + * + * The subclass should remove the most recent block from the blockchain, + * along with all transactions, outputs, and other metadata created as + * a result of its addition to the blockchain. Most of this is handled + * by the concrete members of the base class provided the subclass correctly + * implements remove_* functions. + * + * The subclass should return by reference the popped block and + * its associated transactions + * + * @param blk return-by-reference the block which was popped + * @param txs return-by-reference the transactions from the popped block + */ virtual void pop_block(block& blk, std::vector& txs); - // return true if a transaction with hash exists + /** + * @brief check if a transaction with a given hash exists + * + * The subclass should check if a transaction is stored which has the + * given hash and return true if so, false otherwise. + * + * @param h the hash to check against + * + * @return true if the transaction exists, otherwise false + */ virtual bool tx_exists(const crypto::hash& h) const = 0; // return unlock time of tx with hash + /** + * @brief fetch a transaction's unlock time/height + * + * The subclass should return the stored unlock time for the transaction + * with the given hash. + * + * If no such transaction exists, the subclass should throw TX_DNE. + * + * @param h the hash of the requested transaction + * + * @return the unlock time/height + */ virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const = 0; // return tx with hash // throw if no such tx exists + /** + * @brief fetches the transaction with the given hash + * + * The subclass should return the transaction stored which has the given + * hash. + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * @param h the hash to look for + * + * @return the transaction with the given hash + */ virtual transaction get_tx(const crypto::hash& h) const = 0; - // returns the total number of transactions in all blocks + /** + * @brief fetches the total number of transactions ever + * + * The subclass should return a count of all the transactions from + * all blocks. + * + * @return the number of transactions in the blockchain + */ virtual uint64_t get_tx_count() const = 0; - // return list of tx with hashes . - // TODO: decide if a missing hash means return empty list - // or just skip that hash + /** + * @brief fetches a list of transactions based on their hashes + * + * The subclass should attempt to fetch each transaction referred to by + * the hashes passed. + * + * Currently, if any of the transactions is not in BlockchainDB, the call + * to get_tx in the implementation will throw TX_DNE. + * + * + * + * @param hlist a list of hashes + * + * @return the list of transactions + */ virtual std::vector get_tx_list(const std::vector& hlist) const = 0; // returns height of block that contains transaction with hash + /** + * @brief fetches the height of a transaction's block + * + * The subclass should attempt to return the height of the block containing + * the transaction with the given hash. + * + * If the transaction cannot be found, the subclass should throw TX_DNE. + * + * @param h the hash of the transaction + * + * @return the height of the transaction's block + */ virtual uint64_t get_tx_block_height(const crypto::hash& h) const = 0; // returns the total number of outputs of amount + /** + * @brief fetches the number of outputs of a given amount + * + * The subclass should return a count of outputs of the given amount, + * or zero if there are none. + * + * + * + * @param amount the output amount being looked up + * + * @return the number of outputs of the given amount + */ virtual uint64_t get_num_outputs(const uint64_t& amount) const = 0; - // return index of the first element (should be hidden, but isn't) + /** + * @brief return index of the first element (should be hidden, but isn't) + * + * @return the index + */ virtual uint64_t get_indexing_base() const { return 0; } - // return public key for output with global output amount and index + /** + * @brief get some of an output's data + * + * The subclass should return the public key, unlock time, and block height + * for the output with the given amount and index, collected in a struct. + * + * If the output cannot be found, the subclass should throw OUTPUT_DNE. + * + * If any of these parts cannot be found, but some are, the subclass + * should throw DB_ERROR with a message stating as much. + * + * @param amount the output amount + * @param index the output's index (indexed by amount) + * + * @return the requested output data + */ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0; + + /** + * @brief get some of an output's data + * + * The subclass should return the public key, unlock time, and block height + * for the output with the given global index, collected in a struct. + * + * If the output cannot be found, the subclass should throw OUTPUT_DNE. + * + * If any of these parts cannot be found, but some are, the subclass + * should throw DB_ERROR with a message stating as much. + * + * @param global_index the output's index (global) + * + * @return the requested output data + */ virtual output_data_t get_output_key(const uint64_t& global_index) const = 0; - // returns the tx hash associated with an output, referenced by global output index + /** + * @brief gets an output's tx hash and index + * + * The subclass should return the hash of the transaction which created the + * output with the global index given, as well as its index in that transaction. + * + * @param index an output's global index + * + * @return the tx hash and output index + */ virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const = 0; - // returns the transaction-local reference for the output with at - // return type is pair of tx hash and index + /** + * @brief gets an output's tx hash and index + * + * The subclass should return the hash of the transaction which created the + * output with the amount and index given, as well as its index in that + * transaction. + * + * @param amount an output amount + * @param index an output's amount-specific index + * + * @return the tx hash and output index + */ virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) = 0; + + /** + * @brief gets some outputs' tx hashes and indices + * + * This function is a mirror of + * get_output_tx_and_index(const uint64_t& amount, const uint64_t& index), + * but for a list of outputs rather than just one. + * + * @param amount an output amount + * @param offsets a list of amount-specific output indices + * @param indices return-by-reference a list of tx hashes and output indices (as pairs) + */ virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) = 0; - virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) = 0; + /** + * @brief gets outputs' data + * + * This function is a mirror of + * get_output_data(const uint64_t& amount, const uint64_t& index) + * but for a list of outputs rather than just one. + * + * @param amount an output amount + * @param offsets a list of amount-specific output indices + * @param outputs return-by-reference a list of outputs' metadata + */ + virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) = 0; + + /* + * FIXME: Need to check with git blame and ask what this does to + * document it + */ virtual bool can_thread_bulk_indices() const = 0; - // return a vector of indices corresponding to the global output index for - // each output in the transaction with hash + /** + * @brief gets output indices (global) for a transaction's outputs + * + * The subclass should fetch the global output indices for each output + * in the transaction with the given hash. + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * If an output cannot be found, the subclass should throw OUTPUT_DNE. + * + * @param h a transaction hash + * + * @return a list of global output indices + */ virtual std::vector get_tx_output_indices(const crypto::hash& h) const = 0; - // return a vector of indices corresponding to the amount output index for - // each output in the transaction with hash + + /** + * @brief gets output indices (amount-specific) for a transaction's outputs + * + * The subclass should fetch the amount-specific output indices for each + * output in the transaction with the given hash. + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * If an output cannot be found, the subclass should throw OUTPUT_DNE. + * + * @param h a transaction hash + * + * @return a list of amount-specific output indices + */ virtual std::vector get_tx_amount_output_indices(const crypto::hash& h) const = 0; - // returns true if key image is present in spent key images storage + /** + * @brief check if a key image is stored as spent + * + * @param img the key image to check for + * + * @return true if the image is present, otherwise false + */ virtual bool has_key_image(const crypto::key_image& img) const = 0; + /** + * @brief runs a function over all key images stored + * + * The subclass should run the passed function for each key image it has + * stored, passing the key image as its parameter. + * + * If any call to the function returns false, the subclass should return + * false. Otherwise, the subclass returns true. + * + * @param std::function fn the function to run + * + * @return false if the function returns false for any key image, otherwise true + */ virtual bool for_all_key_images(std::function) const = 0; + + /** + * @brief runs a function over all blocks stored + * + * The subclass should run the passed function for each block it has + * stored, passing (block_height, block_hash, block) 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 fn the function to run + * + * @return false if the function returns false for any block, otherwise true + */ virtual bool for_all_blocks(std::function) const = 0; + + /** + * @brief runs a function over all transactions stored + * + * The subclass should run the passed function for each transaction it has + * stored, passing (transaction_hash, transaction) 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 fn the function to run + * + * @return false if the function returns false for any transaction, otherwise true + */ virtual bool for_all_transactions(std::function) const = 0; + + /** + * @brief runs a function over all outputs stored + * + * The subclass should run the passed function for each output it has + * stored, passing (amount, transaction_hash, tx_local_output_index) + * 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_outputs(std::function f) const = 0; + + // // Hard fork related storage + // + + // FIXME: verify that this is all correct + // - TW + /** + * @brief sets the height at which a hard fork has been voted to happen + * + * + * @param version the version voted to fork to + * @param height the height of the first block on the new fork + */ virtual void set_hard_fork_starting_height(uint8_t version, uint64_t height) = 0; + + /** + * @brief gets the height at which a hard fork has been voted to happen + * + * @param version the version to check + * + * @return the height at which the hard fork was accepted, if it has been, + * otherwise max(uint64_t) + */ virtual uint64_t get_hard_fork_starting_height(uint8_t version) const = 0; + + /** + * @brief sets which hardfork version a height is on + * + * @param height the height + * @param version the version + */ virtual void set_hard_fork_version(uint64_t height, uint8_t version) = 0; + + /** + * @brief checks which hardfork version a height is on + * + * @param height the height + * + * @return the version + */ virtual uint8_t get_hard_fork_version(uint64_t height) const = 0; + + /** + * @brief verify hard fork info in database + */ virtual void check_hard_fork_info() = 0; + + /** + * @brief delete hard fork info from database + */ virtual void drop_hard_fork_info() = 0; + /** + * @brief is BlockchainDB in read-only mode? + * + * @return true if in read-only mode, otherwise false + */ virtual bool is_read_only() const = 0; - // fix up anything that may be wrong due to past bugs + // TODO: this should perhaps be (or call) a series of functions which + // progressively update through version updates + /** + * @brief fix up anything that may be wrong due to past bugs + */ virtual void fixup(); + /** + * @brief set whether or not to automatically remove logs + * + * This function is only relevant for one implementation (BlockchainBDB), but + * is here to keep BlockchainDB users implementation-agnostic. + * + * @param auto_remove whether or not to auto-remove logs + */ void set_auto_remove_logs(bool auto_remove) { m_auto_remove_logs = auto_remove; } - bool m_open; - mutable epee::critical_section m_synchronization_lock; + bool m_open; //!< Whether or not the BlockchainDB is open/ready for use + mutable epee::critical_section m_synchronization_lock; //!< A lock, currently for when BlockchainLMDB needs to resize the backing db file + }; // class BlockchainDB -- cgit v1.2.3 From a2e378b91bf5d2a54284f8e20df5080f11d25ff6 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 25 Mar 2016 00:48:11 +0000 Subject: wallet: add a --generate-from-json flag It takes a filename containing JSON data to generate a wallet. The following fields are valid: version: integer, should be 1 filename: string, path/filename for the newly created wallet scan_from_height: 64 bit unsigned integer, optional password: string, optional viewkey: string, hex representation spendkey: string, hex representation seed: string, optional, list of words separated by spaces Either seed or private keys should be given. If using private keys, the spend key may be omitted (the wallet will not be able to spend, but will see incoming transactions). If scan_from_height is given, blocks below this height will not be checked for transactions as an optimization. --- src/simplewallet/simplewallet.cpp | 186 ++++++++++++++++++++++++++++++++++++-- src/simplewallet/simplewallet.h | 2 + src/wallet/wallet2.cpp | 2 +- src/wallet/wallet2.h | 12 ++- 4 files changed, 192 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index ea1993c80..1856118f7 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -57,6 +57,7 @@ #include "version.h" #include "crypto/crypto.h" // for crypto::secret_key definition #include "mnemonics/electrum-words.h" +#include "rapidjson/document.h" #include #if defined(WIN32) @@ -81,6 +82,7 @@ namespace const command_line::arg_descriptor arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to or
.wallet by default"), ""}; const command_line::arg_descriptor arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; const command_line::arg_descriptor arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; + const command_line::arg_descriptor arg_generate_from_json = {"generate-from-json", sw::tr("Generate wallet from JSON format file"), ""}; const command_line::arg_descriptor arg_daemon_address = {"daemon-address", sw::tr("Use daemon instance at :"), ""}; const command_line::arg_descriptor arg_daemon_host = {"daemon-host", sw::tr("Use daemon instance at host instead of localhost"), ""}; const command_line::arg_descriptor arg_password = {"password", sw::tr("Wallet password"), "", true}; @@ -716,7 +718,7 @@ bool simple_wallet::ask_wallet_create_if_needed() // add logic to error out if new wallet requested but named wallet file exists if (keys_file_exists || wallet_file_exists) { - if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty()) + if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty() || !m_generate_from_json.empty()) { fail_msg_writer() << tr("attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting."); return false; @@ -763,6 +765,13 @@ void simple_wallet::print_seed(std::string seed) //---------------------------------------------------------------------------------------------------- static bool get_password(const boost::program_options::variables_map& vm, bool allow_entry, tools::password_container &pwd_container) { + // has_arg returns true even when the parameter is not passed ?? + const std::string gfj = command_line::get_arg(vm, arg_generate_from_json); + if (!gfj.empty()) { + // will be in the json file, if any + return true; + } + if (has_arg(vm, arg_password) && has_arg(vm, arg_password_file)) { fail_msg_writer() << tr("can't specify more than one of --password and --password-file"); @@ -808,6 +817,153 @@ static bool get_password(const boost::program_options::variables_map& vm, bool a return false; } +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password) +{ + std::string buf; + bool r = epee::file_io_utils::load_file_to_string(m_generate_from_json, buf); + if (!r) { + fail_msg_writer() << tr("Failed to load file ") << m_generate_from_json; + return false; + } + + rapidjson::Document json; + if (json.Parse(buf.c_str()).HasParseError()) { + fail_msg_writer() << tr("Failed to parse JSON"); + return false; + } + + if (!json.HasMember("version")) { + fail_msg_writer() << tr("Version not found in JSON"); + return false; + } + unsigned int version = json["version"].GetUint(); + const int current_version = 1; + if (version > current_version) { + fail_msg_writer() << boost::format(tr("Version %u too new, we can only grok up to %u")) % version % current_version; + return false; + } + if (!json.HasMember("filename")) { + fail_msg_writer() << tr("Filename not found in JSON"); + return false; + } + std::string filename = json["filename"].GetString(); + + bool recover = false; + uint64_t scan_from_height = 0; + if (json.HasMember("scan_from_height")) { + scan_from_height = json["scan_from_height"].GetUint64(); + recover = true; + } + + password = ""; + if (json.HasMember("password")) { + password = json["password"].GetString(); + } + + std::string viewkey_string(""); + crypto::secret_key viewkey; + if (json.HasMember("viewkey")) { + viewkey_string = json["viewkey"].GetString(); + cryptonote::blobdata viewkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data)) + { + fail_msg_writer() << tr("failed to parse view key secret key"); + return false; + } + viewkey = *reinterpret_cast(viewkey_data.data()); + } + + std::string spendkey_string(""); + crypto::secret_key spendkey; + if (json.HasMember("spendkey")) { + spendkey_string = json["spendkey"].GetString(); + cryptonote::blobdata spendkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data)) + { + fail_msg_writer() << tr("failed to parse spend key secret key"); + return false; + } + spendkey = *reinterpret_cast(spendkey_data.data()); + } + + std::string seed(""); + std::string old_language; + if (json.HasMember("seed")) { + seed = json["seed"].GetString(); + if (!crypto::ElectrumWords::words_to_bytes(seed, m_recovery_key, old_language)) + { + fail_msg_writer() << tr("Electrum-style word list failed verification"); + return false; + } + m_electrum_seed = seed; + m_restore_deterministic_wallet = true; + } + + // compatibility checks + if (seed.empty() && viewkey_string.empty()) { + fail_msg_writer() << tr("At least one of Electrum-style word list and private view key must be specified"); + return false; + } + if (!seed.empty() && (!viewkey_string.empty() || !spendkey_string.empty())) { + fail_msg_writer() << tr("Both Electrum-style word list and private key(s) specified"); + return false; + } + + m_wallet_file = filename; + + bool was_deprecated_wallet = m_restore_deterministic_wallet && ((old_language == crypto::ElectrumWords::old_language_name) || + crypto::ElectrumWords::get_is_old_style_seed(m_electrum_seed)); + if (was_deprecated_wallet) { + fail_msg_writer() << tr("Cannot create deprecated wallets from JSON"); + return false; + } + + bool testnet = command_line::get_arg(vm, arg_testnet); + m_wallet.reset(new tools::wallet2(testnet)); + m_wallet->callback(this); + + try + { + if (!seed.empty()) + { + m_wallet->generate(m_wallet_file, password, m_recovery_key, recover, false); + } + else + { + cryptonote::account_public_address address; + if (!crypto::secret_key_to_public_key(viewkey, address.m_view_public_key)) { + fail_msg_writer() << tr("failed to verify view key secret key"); + return false; + } + if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) { + fail_msg_writer() << tr("failed to verify spend key secret key"); + return false; + } + + if (spendkey_string.empty()) + { + m_wallet->generate(m_wallet_file, password, address, viewkey); + } + else + { + m_wallet->generate(m_wallet_file, password, address, spendkey, viewkey); + } + } + } + catch (const std::exception& e) + { + fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); + return false; + } + + m_wallet->set_refresh_from_block_height(scan_from_height); + + wallet_file = m_wallet_file; + + return r; +} + //---------------------------------------------------------------------------------------------------- bool simple_wallet::init(const boost::program_options::variables_map& vm) { @@ -820,12 +976,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_keys.empty()) > 1) + if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_json.empty()) > 1) { - fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\" and --generate-from-keys=\"wallet_name\""); + fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-keys=\"wallet_name\""); return false; } - else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_keys.empty()) + else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_keys.empty() && m_generate_from_json.empty()) { if(!ask_wallet_create_if_needed()) return false; } @@ -847,7 +1003,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!get_password(vm, true, pwd_container)) return false; - if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty()) + if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty() || !m_generate_from_json.empty()) { if (m_wallet_file.empty()) m_wallet_file = m_generate_new; // alias for simplicity later @@ -993,6 +1149,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) bool r = new_wallet(m_wallet_file, pwd_container.password(), address, spendkey, viewkey, testnet); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); } + else if (!m_generate_from_json.empty()) + { + std::string wallet_file, password; // we don't need to remember them + if (!generate_from_json(vm, wallet_file, password)) + return false; + } else { bool r = new_wallet(m_wallet_file, pwd_container.password(), m_recovery_key, m_restore_deterministic_wallet, @@ -1023,6 +1185,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet); m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key); m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys); + m_generate_from_json = command_line::get_arg(vm, arg_generate_from_json); m_daemon_address = command_line::get_arg(vm, arg_daemon_address); m_daemon_host = command_line::get_arg(vm, arg_daemon_host); m_daemon_port = command_line::get_arg(vm, arg_daemon_port); @@ -2575,6 +2738,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_generate_new_wallet); command_line::add_arg(desc_params, arg_generate_from_view_key); command_line::add_arg(desc_params, arg_generate_from_keys); + command_line::add_arg(desc_params, arg_generate_from_json); command_line::add_arg(desc_params, arg_password); command_line::add_arg(desc_params, arg_password_file); command_line::add_arg(desc_params, arg_daemon_address); @@ -2707,11 +2871,21 @@ int main(int argc, char* argv[]) if (daemon_address.empty()) daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); + std::string password; + const std::string gfj = command_line::get_arg(vm, arg_generate_from_json); + if (!gfj.empty()) { + if (!w.generate_from_json(vm, wallet_file, password)) + return 1; + } + else { + password = pwd_container.password(); + } + tools::wallet2 wal(testnet,restricted); try { LOG_PRINT_L0(sw::tr("Loading wallet...")); - wal.load(wallet_file, pwd_container.password()); + wal.load(wallet_file, password); wal.init(daemon_address); wal.refresh(); LOG_PRINT_GREEN(sw::tr("Loaded ok"), LOG_LEVEL_0); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index d1617dbf4..7dadb8536 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -69,6 +69,7 @@ namespace cryptonote bool run(); void stop(); void interrupt(); + bool generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password); //wallet *create_wallet(); bool process_command(const std::vector &args); @@ -221,6 +222,7 @@ namespace cryptonote std::string m_generate_new; std::string m_generate_from_view_key; std::string m_generate_from_keys; + std::string m_generate_from_json; std::string m_import_path; std::string m_electrum_seed; // electrum-style seed parameter diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2afe08cb1..1c7187cf0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -490,7 +490,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry //handle transactions from new block //optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup - if(b.timestamp + 60*60*24 > m_account.get_createtime()) + if(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height) { TIME_MEASURE_START(miner_tx_handle_time); process_new_transaction(b.miner_tx, height, true); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f798f404d..e7b002925 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -88,10 +88,10 @@ namespace tools }; private: - wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true) {} + wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} public: - wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true) {} + wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} struct transfer_details { uint64_t m_block_height; @@ -226,6 +226,8 @@ namespace tools cryptonote::account_base& get_account(){return m_account;} const cryptonote::account_base& get_account()const{return m_account;} + void set_refresh_from_block_height(uint64_t height) {m_refresh_from_block_height = height;} + // upper_transaction_size_limit as defined below is set to // approximately 125% of the fixed minimum allowable penalty // free block size. TODO: fix this so that it actually takes @@ -319,6 +321,9 @@ namespace tools if(ver < 9) return; a & m_confirmed_txs; + if(ver < 11) + return; + a & m_refresh_from_block_height; } /*! @@ -430,9 +435,10 @@ namespace tools uint32_t m_default_mixin; RefreshType m_refresh_type; bool m_auto_refresh; + uint64_t m_refresh_from_block_height; }; } -BOOST_CLASS_VERSION(tools::wallet2, 10) +BOOST_CLASS_VERSION(tools::wallet2, 11) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 0) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 2) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 1) -- cgit v1.2.3 From 01e0a69c175852adb01897431a138739faf39fe1 Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Fri, 25 Mar 2016 08:42:42 +0200 Subject: Revert "Merge pull request #749" This reverts commit 7fa63a82a1c3a0243f6757c1689855ed3ca61695, reversing changes made to cb6be986c36b78eddb4b7f16e9ad440af8567dc4. --- Doxyfile | 14 +- src/blockchain_db/blockchain_db.h | 1092 ++++------------------------ src/cryptonote_core/CMakeLists.txt | 2 + src/cryptonote_core/blockchain.cpp | 49 +- src/cryptonote_core/blockchain.h | 890 +---------------------- src/cryptonote_core/blockchain_storage.cpp | 8 +- src/cryptonote_core/checkpoints.cpp | 251 +------ src/cryptonote_core/checkpoints.h | 181 +---- src/cryptonote_core/checkpoints_create.cpp | 280 +++++++ src/cryptonote_core/checkpoints_create.h | 48 ++ src/cryptonote_core/cryptonote_core.cpp | 19 +- src/cryptonote_core/cryptonote_core.h | 650 +---------------- src/cryptonote_core/difficulty.cpp | 6 +- src/cryptonote_core/difficulty.h | 12 - src/daemon/core.h | 1 + 15 files changed, 594 insertions(+), 2909 deletions(-) create mode 100644 src/cryptonote_core/checkpoints_create.cpp create mode 100644 src/cryptonote_core/checkpoints_create.h (limited to 'src') diff --git a/Doxyfile b/Doxyfile index 93a5c6e76..a70ef812b 100644 --- a/Doxyfile +++ b/Doxyfile @@ -409,13 +409,13 @@ LOOKUP_CACHE_SIZE = 0 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = YES +EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. -EXTRACT_PRIVATE = YES +EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. @@ -427,7 +427,7 @@ EXTRACT_PACKAGE = NO # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = YES +EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO @@ -452,7 +452,7 @@ EXTRACT_LOCAL_METHODS = NO # are hidden. # The default value is: NO. -EXTRACT_ANON_NSPACES = YES +EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these @@ -1902,7 +1902,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = YES +MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -1910,7 +1910,7 @@ MACRO_EXPANSION = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = YES +EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES the includes files in the # INCLUDE_PATH will be searched if a #include is found. @@ -1942,7 +1942,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = "BLOCKCHAIN_DB=2" \ # DB_LMDB +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 3e0ca141e..3396b8c20 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -38,20 +38,18 @@ #include "cryptonote_core/difficulty.h" #include "cryptonote_core/hardfork.h" -/** \file - * Cryptonote Blockchain Database Interface +/* DB Driver Interface * * The DB interface is a store for the canonical block chain. * It serves as a persistent storage for the blockchain. * - * For the sake of efficiency, a concrete implementation may also + * For the sake of efficiency, the reference implementation will also * store some blockchain data outside of the blocks, such as spent * transfer key images, unspent transaction outputs, etc. * - * Examples are as follows: - * * Transactions are duplicated so that we don't have to fetch a whole block - * in order to fetch a transaction from that block. + * in order to fetch a transaction from that block. If this is deemed + * unnecessary later, this can change. * * Spent key images are duplicated outside of the blocks so it is quick * to verify an output hasn't already been spent @@ -59,34 +57,100 @@ * Unspent transaction outputs are duplicated to quickly gather random * outputs to use for mixins * + * IMPORTANT: + * A concrete implementation of this interface should populate these + * duplicated members! It is possible to have a partial implementation + * of this interface call to private members of the interface to be added + * later that will then populate as needed. + * + * General: + * open() + * is_open() + * close() + * sync() + * reset() + * + * Lock and unlock provided for reorg externally, and for block + * additions internally, this way threaded reads are completely fine + * unless the blockchain is changing. + * bool lock() + * unlock() + * + * vector get_filenames() + * + * Blocks: + * bool block_exists(hash) + * height add_block(block, block_size, cumulative_difficulty, coins_generated, transactions) + * block get_block(hash) + * height get_block_height(hash) + * header get_block_header(hash) + * block get_block_from_height(height) + * size_t get_block_size(height) + * difficulty get_block_cumulative_difficulty(height) + * uint64_t get_block_already_generated_coins(height) + * uint64_t get_block_timestamp(height) + * uint64_t get_top_block_timestamp() + * hash get_block_hash_from_height(height) + * blocks get_blocks_range(height1, height2) + * hashes get_hashes_range(height1, height2) + * hash top_block_hash() + * block get_top_block() + * height height() + * void pop_block(block&, tx_list&) + * + * Transactions: + * bool tx_exists(hash) + * uint64_t get_tx_unlock_time(hash) + * tx get_tx(hash) + * uint64_t get_tx_count() + * tx_list get_tx_list(hash_list) + * height get_tx_block_height(hash) + * + * Outputs: + * uint64_t get_num_outputs(amount) + * pub_key get_output_key(amount, index) + * hash,index get_output_tx_and_index_from_global(index) + * hash,index get_output_tx_and_index(amount, index) + * vec get_tx_output_indices(tx_hash) + * + * + * Spent Output Key Images: + * bool has_key_image(key_image) + * + * Exceptions: + * DB_ERROR -- generic + * DB_OPEN_FAILURE + * DB_CREATE_FAILURE + * DB_SYNC_FAILURE + * BLOCK_DNE + * BLOCK_PARENT_DNE + * BLOCK_EXISTS + * BLOCK_INVALID -- considering making this multiple errors + * TX_DNE + * TX_EXISTS + * OUTPUT_DNE + * OUTPUT_EXISTS + * KEY_IMAGE_EXISTS */ namespace cryptonote { -/** a pair of , typedef for convenience */ +// typedef for convenience typedef std::pair tx_out_index; #pragma pack(push, 1) - -/** - * @brief a struct containing output metadata - */ struct output_data_t { - crypto::public_key pubkey; //!< the output's public key (for spend verification) - uint64_t unlock_time; //!< the output's unlock time (or height) - uint64_t height; //!< the height of the block which created the output + crypto::public_key pubkey; + uint64_t unlock_time; + uint64_t height; }; #pragma pack(pop) /*********************************** * Exception Definitions ***********************************/ - -/** - * @brief A base class for BlockchainDB exceptions - */ class DB_EXCEPTION : public std::exception { private: @@ -104,9 +168,6 @@ class DB_EXCEPTION : public std::exception } }; -/** - * @brief A generic BlockchainDB exception - */ class DB_ERROR : public DB_EXCEPTION { public: @@ -114,9 +175,7 @@ class DB_ERROR : public DB_EXCEPTION DB_ERROR(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when there is an error starting a DB transaction - */ +// For distinguishing errors trying to set up a DB txn from other errors class DB_ERROR_TXN_START : public DB_EXCEPTION { public: @@ -124,9 +183,6 @@ class DB_ERROR_TXN_START : public DB_EXCEPTION DB_ERROR_TXN_START(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when opening the BlockchainDB fails - */ class DB_OPEN_FAILURE : public DB_EXCEPTION { public: @@ -134,9 +190,6 @@ class DB_OPEN_FAILURE : public DB_EXCEPTION DB_OPEN_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when creating the BlockchainDB fails - */ class DB_CREATE_FAILURE : public DB_EXCEPTION { public: @@ -144,9 +197,6 @@ class DB_CREATE_FAILURE : public DB_EXCEPTION DB_CREATE_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when synchronizing the BlockchainDB to disk fails - */ class DB_SYNC_FAILURE : public DB_EXCEPTION { public: @@ -154,9 +204,6 @@ class DB_SYNC_FAILURE : public DB_EXCEPTION DB_SYNC_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when a requested block does not exist - */ class BLOCK_DNE : public DB_EXCEPTION { public: @@ -164,9 +211,6 @@ class BLOCK_DNE : public DB_EXCEPTION BLOCK_DNE(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when a block's parent does not exist (and it needed to) - */ class BLOCK_PARENT_DNE : public DB_EXCEPTION { public: @@ -174,9 +218,6 @@ class BLOCK_PARENT_DNE : public DB_EXCEPTION BLOCK_PARENT_DNE(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when a block exists, but shouldn't, namely when adding a block - */ class BLOCK_EXISTS : public DB_EXCEPTION { public: @@ -184,9 +225,6 @@ class BLOCK_EXISTS : public DB_EXCEPTION BLOCK_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when something is wrong with the block to be added - */ class BLOCK_INVALID : public DB_EXCEPTION { public: @@ -194,9 +232,6 @@ class BLOCK_INVALID : public DB_EXCEPTION BLOCK_INVALID(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when a requested transaction does not exist - */ class TX_DNE : public DB_EXCEPTION { public: @@ -204,9 +239,6 @@ class TX_DNE : public DB_EXCEPTION TX_DNE(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when a transaction exists, but shouldn't, namely when adding a block - */ class TX_EXISTS : public DB_EXCEPTION { public: @@ -214,9 +246,6 @@ class TX_EXISTS : public DB_EXCEPTION TX_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when a requested output does not exist - */ class OUTPUT_DNE : public DB_EXCEPTION { public: @@ -224,9 +253,6 @@ class OUTPUT_DNE : public DB_EXCEPTION OUTPUT_DNE(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when an output exists, but shouldn't, namely when adding a block - */ class OUTPUT_EXISTS : public DB_EXCEPTION { public: @@ -234,9 +260,6 @@ class OUTPUT_EXISTS : public DB_EXCEPTION OUTPUT_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; -/** - * @brief thrown when a spent key image exists, but shouldn't, namely when adding a block - */ class KEY_IMAGE_EXISTS : public DB_EXCEPTION { public: @@ -249,18 +272,6 @@ class KEY_IMAGE_EXISTS : public DB_EXCEPTION ***********************************/ -/** - * @brief The BlockchainDB backing store interface declaration/contract - * - * This class provides a uniform interface for using BlockchainDB to store - * a blockchain. Any implementation of this class will also implement all - * functions exposed here, so one can use this class without knowing what - * implementation is being used. Refer to each pure virtual function's - * documentation here when implementing a BlockchainDB subclass. - * - * A subclass which encounters an issue should report that issue by throwing - * a DB_EXCEPTION which adequately conveys the issue. - */ class BlockchainDB { private: @@ -268,22 +279,7 @@ private: * private virtual members *********************************************************************/ - /** - * @brief add the block and metadata to the db - * - * The subclass implementing this will add the specified block and - * block metadata to its backing store. This does not include its - * transactions, those are added in a separate step. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param blk the block to be added - * @param block_size the size of the block (transactions and all) - * @param cumulative_difficulty the accumulated difficulty after this block - * @param coins_generated the number of coins generated total after this block - * @param blk_hash the hash of the block - */ + // tells the subclass to add the block and metadata to storage virtual void add_block( const block& blk , const size_t& block_size , const difficulty_type& cumulative_difficulty @@ -291,274 +287,84 @@ private: , const crypto::hash& blk_hash ) = 0; - /** - * @brief remove data about the top block - * - * The subclass implementing this will remove the block data from the top - * block in the chain. The data to be removed is that which was added in - * BlockchainDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash) - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ + // tells the subclass to remove data about the top block virtual void remove_block() = 0; - /** - * @brief store the transaction and its metadata - * - * The subclass implementing this will add the specified transaction data - * to its backing store. This includes only the transaction blob itself - * and the other data passed here, not the separate outputs of the - * transaction. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param blk_hash the hash of the block containing the transaction - * @param tx the transaction to be added - * @param tx_hash the hash of the transaction - */ + // tells the subclass to store the transaction and its metadata virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0; - /** - * @brief remove data about a transaction - * - * The subclass implementing this will remove the transaction data - * for the passed transaction. The data to be removed was added in - * add_transaction_data(). Additionally, current subclasses have behavior - * which requires the transaction itself as a parameter here. Future - * implementations should note that this parameter is subject to be removed - * at a later time. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param tx_hash the hash of the transaction to be removed - * @param tx the transaction - */ + // tells the subclass to remove data about a transaction virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0; - /** - * @brief store an output - * - * The subclass implementing this will add the output data passed to its - * backing store in a suitable manner. In addition, the subclass is responsible - * for keeping track of the global output count in some manner, so that - * outputs may be indexed by the order in which they were created. In the - * future, this tracking (of the number, at least) should be moved to - * this class, as it is necessary and the same among all BlockchainDB. - * - * This data should be stored in such a manner that the only thing needed to - * reverse the process is the tx_out. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param tx_hash hash of the transaction the output was created by - * @param tx_output the output - * @param local_index index of the output in its transaction - * @param unlock_time unlock time/height of the output - */ + // tells the subclass to store an output virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) = 0; - /** - * @brief remove an output - * - * The subclass implementing this will remove all output data it stored - * in add_output(). - * - * In addition, the subclass is responsible for correctly decrementing - * its global output counter (this may be automatic for some, such as using - * a database backend "count" feature). - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param tx_output the output to be removed - */ + // tells the subclass to remove an output virtual void remove_output(const tx_out& tx_output) = 0; - /** - * @brief store a spent key - * - * The subclass implementing this will store the spent key image. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param k_image the spent key image to store - */ + // tells the subclass to store a spent key virtual void add_spent_key(const crypto::key_image& k_image) = 0; - /** - * @brief remove a spent key - * - * The subclass implementing this will remove the key image. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param k_image the spent key image to remove - */ + // tells the subclass to remove a spent key virtual void remove_spent_key(const crypto::key_image& k_image) = 0; /********************************************************************* * private concrete members *********************************************************************/ - /** - * @brief private version of pop_block, for undoing if an add_block fails - * - * This function simply calls pop_block(block& blk, std::vector& txs) - * with dummy parameters, as the returns-by-reference can be discarded. - */ + // private version of pop_block, for undoing if an add_block goes tits up void pop_block(); - /** - * @brief helper function for add_transactions, to add each individual transaction - * - * This function is called by add_transactions() for each transaction to be - * added. - * - * @param blk_hash hash of the block which has the transaction - * @param tx the transaction to add - * @param tx_hash_ptr the hash of the transaction, if already calculated - */ + // helper function for add_transactions, to add each individual tx void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL); // helper function to remove transaction from blockchain - /** - * @brief helper function to remove transaction from the blockchain - * - * This function encapsulates aspects of removing a transaction. - * - * @param tx_hash the hash of the transaction to be removed - */ void remove_transaction(const crypto::hash& tx_hash); - uint64_t num_calls = 0; //!< a performance metric - uint64_t time_blk_hash = 0; //!< a performance metric - uint64_t time_add_block1 = 0; //!< a performance metric - uint64_t time_add_transaction = 0; //!< a performance metric + uint64_t num_calls = 0; + uint64_t time_blk_hash = 0; + uint64_t time_add_block1 = 0; + uint64_t time_add_transaction = 0; protected: - mutable uint64_t time_tx_exists = 0; //!< a performance metric - uint64_t time_commit1 = 0; //!< a performance metric - bool m_auto_remove_logs = true; //!< whether or not to automatically remove old logs + mutable uint64_t time_tx_exists = 0; + uint64_t time_commit1 = 0; + bool m_auto_remove_logs = true; HardFork* m_hardfork; public: - /** - * @brief An empty destructor. - */ + // virtual dtor virtual ~BlockchainDB() { }; - /** - * @brief reset profiling stats - */ + // reset profiling stats void reset_stats(); - /** - * @brief show profiling stats - * - * This function prints current performance/profiling data to whichever - * log file(s) are set up (possibly including stdout or stderr) - */ + // show profiling stats void show_stats(); - /** - * @brief open a db, or create it if necessary. - * - * This function opens an existing database or creates it if it - * does not exist. - * - * The subclass implementing this will handle all file opening/creation, - * and is responsible for maintaining its state. - * - * The parameter may not refer to a file name, necessarily, but - * could be an IP:PORT for a database which needs it, and so on. Calling it - * is convenient and should be descriptive enough, however. - * - * For now, db_flags are - * specific to the subclass being instantiated. This is subject to change, - * and the db_flags parameter may be deprecated. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param filename a string referring to the BlockchainDB to open - * @param db_flags flags relevant to how to open/use the BlockchainDB - */ + // open the db at location , or create it if there isn't one. virtual void open(const std::string& filename, const int db_flags = 0) = 0; - /** - * @brief Gets the current open/ready state of the BlockchainDB - * - * @return true if open/ready, otherwise false - */ + // returns true of the db is open/ready, else false bool is_open() const; - /** - * @brief close the BlockchainDB - * - * At minimum, this call ensures that further use of the BlockchainDB - * instance will not have effect. In any case where it is necessary - * to do so, a subclass implementing this will sync with disk. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ + // close and sync the db virtual void close() = 0; - /** - * @brief sync the BlockchainDB with disk - * - * This function should write any changes to whatever permanent backing - * store the subclass uses. Example: a BlockchainDB instance which - * keeps the whole blockchain in RAM won't need to regularly access a - * disk, but should write out its state when this is called. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ + // sync the db virtual void sync() = 0; - /** - * @brief Remove everything from the BlockchainDB - * - * This function should completely remove all data from a BlockchainDB. - * - * Use with caution! - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ + // reset the db -- USE WITH CARE virtual void reset() = 0; - /** - * @brief get all files used by the BlockchainDB (if any) - * - * This function is largely for ease of automation, namely for unit tests. - * - * The subclass implementation should return all filenames it uses. - * - * @return a list of filenames - */ + // get all files used by this db (if any) virtual std::vector get_filenames() const = 0; // return the name of the folder the db's file(s) should reside in - /** - * @brief gets the name of the folder the BlockchainDB's file(s) should be in - * - * The subclass implementation should return the name of the folder in which - * it stores files, or an empty string if there is none. - * - * @return the name of the folder with the BlockchainDB's files, if any. - */ virtual std::string get_db_name() const = 0; @@ -566,86 +372,13 @@ public: // RAII-friendly and multi-read one-write friendly locking mechanism // // acquire db lock - /** - * @brief acquires the BlockchainDB lock - * - * This function is a stub until such a time as locking is implemented at - * this level. - * - * The subclass implementation should return true unless implementing a - * locking scheme of some sort, in which case it should return true upon - * acquisition of the lock and block until then. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @return true, unless at a future time false makes sense (timeout, etc) - */ virtual bool lock() = 0; // release db lock - /** - * @brief This function releases the BlockchainDB lock - * - * The subclass, should it have implemented lock(), will release any lock - * held by the calling thread. In the case of recursive locking, it should - * release one instance of a lock. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ virtual void unlock() = 0; - /** - * @brief tells the BlockchainDB to start a new "batch" of blocks - * - * If the subclass implements a batching method of caching blocks in RAM to - * be added to a backing store in groups, it should start a batch which will - * end either when has been added or batch_stop() has - * been called. In either case, it should end the batch and write to its - * backing store. - * - * If a batch is already in-progress, this function should throw a DB_ERROR. - * This exception may change in the future if it is deemed necessary to - * have a more granular exception type for this scenario. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param batch_num_blocks number of blocks to batch together - */ virtual void batch_start(uint64_t batch_num_blocks=0) = 0; - - /** - * @brief ends a batch transaction - * - * If the subclass implements batching, this function should store the - * batch it is currently on and mark it finished. - * - * 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_stop() = 0; - - /** - * @brief sets whether or not to batch transactions - * - * If the subclass implements batching, this function tells it to begin - * batching automatically. - * - * If the subclass implements batching and has a batch in-progress, a - * parameter of false should disable batching and call batch_stop() to - * store the current batch. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param bool batch whether or not to use batch transactions. - */ virtual void set_batch_transactions(bool) = 0; virtual void block_txn_start(bool readonly=false) = 0; @@ -655,26 +388,8 @@ public: virtual void set_hard_fork(HardFork* hf); // adds a block with the given metadata to the top of the blockchain, returns the new height - /** - * @brief handles the addition of a new block to BlockchainDB - * - * This function organizes block addition and calls various functions as - * necessary. - * - * NOTE: subclass implementations of this (or the functions it calls) need - * to handle undoing any partially-added blocks in the event of a failure. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param blk the block to be added - * @param block_size the size of the block (transactions and all) - * @param cumulative_difficulty the accumulated difficulty after this block - * @param coins_generated the number of coins generated total after this block - * @param txs the transactions in the block - * - * @return the height of the chain post-addition - */ + // NOTE: subclass implementations of this (or the functions it calls) need + // to handle undoing any partially-added blocks in the event of a failure. virtual uint64_t add_block( const block& blk , const size_t& block_size , const difficulty_type& cumulative_difficulty @@ -682,639 +397,142 @@ public: , const std::vector& txs ); - /** - * @brief checks if a block exists - * - * @param h the hash of the requested block - * - * @return true of the block exists, otherwise false - */ + // return true if a block with hash exists in the blockchain virtual bool block_exists(const crypto::hash& h) const = 0; - /** - * @brief fetches the block with the given hash - * - * The subclass should return the requested block. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param h the hash to look for - * - * @return the block requested - */ + // return block with hash virtual block get_block(const crypto::hash& h) const = 0; - /** - * @brief gets the height of the block with a given hash - * - * The subclass should return the requested height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param h the hash to look for - * - * @return the height - */ + // return the height of the block with hash on the blockchain, + // throw if it doesn't exist virtual uint64_t get_block_height(const crypto::hash& h) const = 0; - /** - * @brief fetch a block header - * - * The subclass should return the block header from the block with - * the given hash. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param h the hash to look for - * - * @return the block header - */ + // return header for block with hash virtual block_header get_block_header(const crypto::hash& h) const = 0; - /** - * @brief fetch a block by height - * - * The subclass should return the block at the given height. - * - * If the block does not exist, that is to say if the blockchain is not - * that high, then the subclass should throw BLOCK_DNE - * - * @param height the height to look for - * - * @return the block - */ + // return block at height virtual block get_block_from_height(const uint64_t& height) const = 0; - /** - * @brief fetch a block's timestamp - * - * The subclass should return the timestamp of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the timestamp - */ + // return timestamp of block at height virtual uint64_t get_block_timestamp(const uint64_t& height) const = 0; - /** - * @brief fetch the top block's timestamp - * - * The subclass should return the timestamp of the most recent block. - * - * @return the top block's timestamp - */ + // return timestamp of most recent block virtual uint64_t get_top_block_timestamp() const = 0; - /** - * @brief fetch a block's size - * - * The subclass should return the size of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the size - */ + // return block size of block at height virtual size_t get_block_size(const uint64_t& height) const = 0; - /** - * @brief fetch a block's cumulative difficulty - * - * The subclass should return the cumulative difficulty of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the cumulative difficulty - */ + // return cumulative difficulty up to and including block at height virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const = 0; - /** - * @brief fetch a block's difficulty - * - * The subclass should return the difficulty of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the difficulty - */ + // return difficulty of block at height virtual difficulty_type get_block_difficulty(const uint64_t& height) const = 0; - /** - * @brief fetch a block's already generated coins - * - * The subclass should return the total coins generated as of the block - * with the given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the already generated coins - */ + // return number of coins generated up to and including block at height virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const = 0; - /** - * @brief fetch a block's hash - * - * The subclass should return hash of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the hash - */ + // return hash of block at height virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const = 0; - /** - * @brief fetch a list of blocks - * - * The subclass should return a vector of blocks with heights starting at - * h1 and ending at h2, inclusively. - * - * If the height range requested goes past the end of the blockchain, - * the subclass should throw BLOCK_DNE. (current implementations simply - * don't catch this exception as thrown by methods called within) - * - * @param h1 the start height - * @param h2 the end height - * - * @return a vector of blocks - */ + // return vector of blocks in range of height (inclusively) virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const = 0; - /** - * @brief fetch a list of block hashes - * - * The subclass should return a vector of block hashes from blocks with - * heights starting at h1 and ending at h2, inclusively. - * - * If the height range requested goes past the end of the blockchain, - * the subclass should throw BLOCK_DNE. (current implementations simply - * don't catch this exception as thrown by methods called within) - * - * @param h1 the start height - * @param h2 the end height - * - * @return a vector of block hashes - */ + // return vector of block hashes in range of height (inclusively) virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const = 0; - /** - * @brief fetch the top block's hash - * - * The subclass should return the hash of the most recent block - * - * @return the top block's hash - */ + // return the hash of the top block on the chain virtual crypto::hash top_block_hash() const = 0; - /** - * @brief fetch the top block - * - * The subclass should return most recent block - * - * @return the top block - */ + // return the block at the top of the blockchain virtual block get_top_block() const = 0; - /** - * @brief fetch the current blockchain height - * - * The subclass should return the current blockchain height - * - * @return the current blockchain height - */ + // return the height of the chain virtual uint64_t height() const = 0; - - /** - * - * - * @brief pops the top block off the blockchain - * - * The subclass should remove the most recent block from the blockchain, - * along with all transactions, outputs, and other metadata created as - * a result of its addition to the blockchain. Most of this is handled - * by the concrete members of the base class provided the subclass correctly - * implements remove_* functions. - * - * The subclass should return by reference the popped block and - * its associated transactions - * - * @param blk return-by-reference the block which was popped - * @param txs return-by-reference the transactions from the popped block - */ + // pops the top block off the blockchain. + // Returns by reference the popped block and its associated transactions + // + // IMPORTANT: + // When a block is popped, the transactions associated with it need to be + // removed, as well as outputs and spent key images associated with + // those transactions. virtual void pop_block(block& blk, std::vector& txs); - /** - * @brief check if a transaction with a given hash exists - * - * The subclass should check if a transaction is stored which has the - * given hash and return true if so, false otherwise. - * - * @param h the hash to check against - * - * @return true if the transaction exists, otherwise false - */ + // return true if a transaction with hash exists virtual bool tx_exists(const crypto::hash& h) const = 0; // return unlock time of tx with hash - /** - * @brief fetch a transaction's unlock time/height - * - * The subclass should return the stored unlock time for the transaction - * with the given hash. - * - * If no such transaction exists, the subclass should throw TX_DNE. - * - * @param h the hash of the requested transaction - * - * @return the unlock time/height - */ virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const = 0; // return tx with hash // throw if no such tx exists - /** - * @brief fetches the transaction with the given hash - * - * The subclass should return the transaction stored which has the given - * hash. - * - * If the transaction does not exist, the subclass should throw TX_DNE. - * - * @param h the hash to look for - * - * @return the transaction with the given hash - */ virtual transaction get_tx(const crypto::hash& h) const = 0; - /** - * @brief fetches the total number of transactions ever - * - * The subclass should return a count of all the transactions from - * all blocks. - * - * @return the number of transactions in the blockchain - */ + // returns the total number of transactions in all blocks virtual uint64_t get_tx_count() const = 0; - /** - * @brief fetches a list of transactions based on their hashes - * - * The subclass should attempt to fetch each transaction referred to by - * the hashes passed. - * - * Currently, if any of the transactions is not in BlockchainDB, the call - * to get_tx in the implementation will throw TX_DNE. - * - * - * - * @param hlist a list of hashes - * - * @return the list of transactions - */ + // return list of tx with hashes . + // TODO: decide if a missing hash means return empty list + // or just skip that hash virtual std::vector get_tx_list(const std::vector& hlist) const = 0; // returns height of block that contains transaction with hash - /** - * @brief fetches the height of a transaction's block - * - * The subclass should attempt to return the height of the block containing - * the transaction with the given hash. - * - * If the transaction cannot be found, the subclass should throw TX_DNE. - * - * @param h the hash of the transaction - * - * @return the height of the transaction's block - */ virtual uint64_t get_tx_block_height(const crypto::hash& h) const = 0; // returns the total number of outputs of amount - /** - * @brief fetches the number of outputs of a given amount - * - * The subclass should return a count of outputs of the given amount, - * or zero if there are none. - * - * - * - * @param amount the output amount being looked up - * - * @return the number of outputs of the given amount - */ virtual uint64_t get_num_outputs(const uint64_t& amount) const = 0; - /** - * @brief return index of the first element (should be hidden, but isn't) - * - * @return the index - */ + // return index of the first element (should be hidden, but isn't) virtual uint64_t get_indexing_base() const { return 0; } - /** - * @brief get some of an output's data - * - * The subclass should return the public key, unlock time, and block height - * for the output with the given amount and index, collected in a struct. - * - * If the output cannot be found, the subclass should throw OUTPUT_DNE. - * - * If any of these parts cannot be found, but some are, the subclass - * should throw DB_ERROR with a message stating as much. - * - * @param amount the output amount - * @param index the output's index (indexed by amount) - * - * @return the requested output data - */ + // return public key for output with global output amount and index virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0; - - /** - * @brief get some of an output's data - * - * The subclass should return the public key, unlock time, and block height - * for the output with the given global index, collected in a struct. - * - * If the output cannot be found, the subclass should throw OUTPUT_DNE. - * - * If any of these parts cannot be found, but some are, the subclass - * should throw DB_ERROR with a message stating as much. - * - * @param global_index the output's index (global) - * - * @return the requested output data - */ virtual output_data_t get_output_key(const uint64_t& global_index) const = 0; - /** - * @brief gets an output's tx hash and index - * - * The subclass should return the hash of the transaction which created the - * output with the global index given, as well as its index in that transaction. - * - * @param index an output's global index - * - * @return the tx hash and output index - */ + // returns the tx hash associated with an output, referenced by global output index virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const = 0; - /** - * @brief gets an output's tx hash and index - * - * The subclass should return the hash of the transaction which created the - * output with the amount and index given, as well as its index in that - * transaction. - * - * @param amount an output amount - * @param index an output's amount-specific index - * - * @return the tx hash and output index - */ + // returns the transaction-local reference for the output with at + // return type is pair of tx hash and index virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) = 0; - - /** - * @brief gets some outputs' tx hashes and indices - * - * This function is a mirror of - * get_output_tx_and_index(const uint64_t& amount, const uint64_t& index), - * but for a list of outputs rather than just one. - * - * @param amount an output amount - * @param offsets a list of amount-specific output indices - * @param indices return-by-reference a list of tx hashes and output indices (as pairs) - */ virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) = 0; - - /** - * @brief gets outputs' data - * - * This function is a mirror of - * get_output_data(const uint64_t& amount, const uint64_t& index) - * but for a list of outputs rather than just one. - * - * @param amount an output amount - * @param offsets a list of amount-specific output indices - * @param outputs return-by-reference a list of outputs' metadata - */ virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) = 0; - - /* - * FIXME: Need to check with git blame and ask what this does to - * document it - */ + virtual bool can_thread_bulk_indices() const = 0; - /** - * @brief gets output indices (global) for a transaction's outputs - * - * The subclass should fetch the global output indices for each output - * in the transaction with the given hash. - * - * If the transaction does not exist, the subclass should throw TX_DNE. - * - * If an output cannot be found, the subclass should throw OUTPUT_DNE. - * - * @param h a transaction hash - * - * @return a list of global output indices - */ + // return a vector of indices corresponding to the global output index for + // each output in the transaction with hash virtual std::vector get_tx_output_indices(const crypto::hash& h) const = 0; - - /** - * @brief gets output indices (amount-specific) for a transaction's outputs - * - * The subclass should fetch the amount-specific output indices for each - * output in the transaction with the given hash. - * - * If the transaction does not exist, the subclass should throw TX_DNE. - * - * If an output cannot be found, the subclass should throw OUTPUT_DNE. - * - * @param h a transaction hash - * - * @return a list of amount-specific output indices - */ + // return a vector of indices corresponding to the amount output index for + // each output in the transaction with hash virtual std::vector get_tx_amount_output_indices(const crypto::hash& h) const = 0; - /** - * @brief check if a key image is stored as spent - * - * @param img the key image to check for - * - * @return true if the image is present, otherwise false - */ + // returns true if key image is present in spent key images storage virtual bool has_key_image(const crypto::key_image& img) const = 0; - /** - * @brief runs a function over all key images stored - * - * The subclass should run the passed function for each key image it has - * stored, passing the key image as its parameter. - * - * If any call to the function returns false, the subclass should return - * false. Otherwise, the subclass returns true. - * - * @param std::function fn the function to run - * - * @return false if the function returns false for any key image, otherwise true - */ virtual bool for_all_key_images(std::function) const = 0; - - /** - * @brief runs a function over all blocks stored - * - * The subclass should run the passed function for each block it has - * stored, passing (block_height, block_hash, block) 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 fn the function to run - * - * @return false if the function returns false for any block, otherwise true - */ virtual bool for_all_blocks(std::function) const = 0; - - /** - * @brief runs a function over all transactions stored - * - * The subclass should run the passed function for each transaction it has - * stored, passing (transaction_hash, transaction) 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 fn the function to run - * - * @return false if the function returns false for any transaction, otherwise true - */ virtual bool for_all_transactions(std::function) const = 0; - - /** - * @brief runs a function over all outputs stored - * - * The subclass should run the passed function for each output it has - * stored, passing (amount, transaction_hash, tx_local_output_index) - * 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_outputs(std::function f) const = 0; - - // // Hard fork related storage - // - - // FIXME: verify that this is all correct - // - TW - /** - * @brief sets the height at which a hard fork has been voted to happen - * - * - * @param version the version voted to fork to - * @param height the height of the first block on the new fork - */ virtual void set_hard_fork_starting_height(uint8_t version, uint64_t height) = 0; - - /** - * @brief gets the height at which a hard fork has been voted to happen - * - * @param version the version to check - * - * @return the height at which the hard fork was accepted, if it has been, - * otherwise max(uint64_t) - */ virtual uint64_t get_hard_fork_starting_height(uint8_t version) const = 0; - - /** - * @brief sets which hardfork version a height is on - * - * @param height the height - * @param version the version - */ virtual void set_hard_fork_version(uint64_t height, uint8_t version) = 0; - - /** - * @brief checks which hardfork version a height is on - * - * @param height the height - * - * @return the version - */ virtual uint8_t get_hard_fork_version(uint64_t height) const = 0; - - /** - * @brief verify hard fork info in database - */ virtual void check_hard_fork_info() = 0; - - /** - * @brief delete hard fork info from database - */ virtual void drop_hard_fork_info() = 0; - /** - * @brief is BlockchainDB in read-only mode? - * - * @return true if in read-only mode, otherwise false - */ virtual bool is_read_only() const = 0; - // TODO: this should perhaps be (or call) a series of functions which - // progressively update through version updates - /** - * @brief fix up anything that may be wrong due to past bugs - */ + // fix up anything that may be wrong due to past bugs virtual void fixup(); - /** - * @brief set whether or not to automatically remove logs - * - * This function is only relevant for one implementation (BlockchainBDB), but - * is here to keep BlockchainDB users implementation-agnostic. - * - * @param auto_remove whether or not to auto-remove logs - */ void set_auto_remove_logs(bool auto_remove) { m_auto_remove_logs = auto_remove; } - bool m_open; //!< Whether or not the BlockchainDB is open/ready for use - mutable epee::critical_section m_synchronization_lock; //!< A lock, currently for when BlockchainLMDB needs to resize the backing db file - + bool m_open; + mutable epee::critical_section m_synchronization_lock; }; // class BlockchainDB diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 205356797..88eea1d7e 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -31,6 +31,7 @@ set(cryptonote_core_sources blockchain_storage.cpp blockchain.cpp checkpoints.cpp + checkpoints_create.cpp cryptonote_basic_impl.cpp cryptonote_core.cpp cryptonote_format_utils.cpp @@ -48,6 +49,7 @@ set(cryptonote_core_private_headers blockchain_storage_boost_serialization.h blockchain.h checkpoints.h + checkpoints_create.h connection_context.h cryptonote_basic.h cryptonote_basic_impl.h diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 2f42e1db5..131f56a4d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -49,7 +49,7 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "cryptonote_core/checkpoints.h" +#include "cryptonote_core/checkpoints_create.h" #include "cryptonote_core/cryptonote_core.h" #if defined(PER_BLOCK_CHECKPOINT) #include "blocks/blocks.h" @@ -840,7 +840,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list blocks, and return by reference . +// get the block sizes of the last blocks, starting at +// and return by reference . void Blockchain::get_last_n_blocks_sizes(std::vector& sz, size_t count) const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -1407,10 +1408,6 @@ bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::list missed_tx_ids; std::list txs; - - // FIXME: s/rsp.missed_ids/missed_tx_id/ ? Seems like rsp.missed_ids - // is for missed blocks, not missed transactions as well. get_transactions(bl.tx_hashes, txs, missed_tx_ids); if (missed_tx_ids.size() != 0) @@ -1674,8 +1668,6 @@ uint64_t Blockchain::block_difficulty(uint64_t i) const return 0; } //------------------------------------------------------------------ -//TODO: return type should be void, throw on exception -// alternatively, return true only if no blocks missed template bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const { @@ -1700,8 +1692,6 @@ bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container return true; } //------------------------------------------------------------------ -//TODO: return type should be void, throw on exception -// alternatively, return true only if no transactions missed template bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const { @@ -1718,6 +1708,7 @@ bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container { missed_txs.push_back(tx_hash); } + //FIXME: is this the correct way to handle this? catch (const std::exception& e) { return false; @@ -1974,11 +1965,6 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vectorheight() < m_blocks_hash_check.size() && kept_by_block) { TIME_MEASURE_START(a); @@ -2053,10 +2038,6 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const } //------------------------------------------------------------------ // This function validates transaction inputs and their keys. -// FIXME: consider moving functionality specific to one input into -// check_tx_input() rather than here, and use this function simply -// to iterate the inputs as necessary (splitting the task -// using threads, etc.) bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height) { LOG_PRINT_L3("Blockchain::" << __func__); @@ -2339,7 +2320,7 @@ bool Blockchain::check_tx_input(const txin_to_key& txin, const crypto::hash& tx_ output_keys.clear(); - // collect output keys + //check ring signature outputs_visitor vi(output_keys, *this); if (!scan_outputkeys_for_indexes(txin, vi, tx_prefix_hash, pmax_related_block_height)) { @@ -2636,11 +2617,6 @@ leave: txs.push_back(tx); TIME_MEASURE_START(dd); - // FIXME: the storage should not be responsible for validation. - // If it does any, it is merely a sanity check. - // Validation is the purview of the Blockchain class - // - TW - // // ND: this is not needed, db->add_block() checks for duplicate k_images and fails accordingly. // if (!check_for_double_spend(tx, keys)) // { @@ -2821,8 +2797,6 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc return handle_block_to_main_chain(bl, id, bvc); } //------------------------------------------------------------------ -//TODO: Refactor, consider returning a failure height and letting -// caller decide course of action. void Blockchain::check_against_checkpoints(const checkpoints& points, bool enforce) { const auto& pts = points.get_points(); @@ -2860,16 +2834,16 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor // with an existing checkpoint. bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns) { - if (!m_checkpoints.load_checkpoints_from_json(file_path)) + if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) { - return false; + return false; } // if we're checking both dns and json, load checkpoints from dns. // if we're not hard-enforcing dns checkpoints, handle accordingly if (m_enforce_dns_checkpoints && check_dns) { - if (!m_checkpoints.load_checkpoints_from_dns()) + if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) { return false; } @@ -2877,7 +2851,7 @@ bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns else if (check_dns) { checkpoints dns_points; - dns_points.load_checkpoints_from_dns(); + cryptonote::load_checkpoints_from_dns(dns_points); if (m_checkpoints.check_for_conflicts(dns_points)) { check_against_checkpoints(dns_points, false); @@ -2904,8 +2878,6 @@ void Blockchain::block_longhash_worker(const uint64_t height, const std::vector< TIME_MEASURE_START(t); slow_hash_allocate_state(); - //FIXME: height should be changing here, as get_block_longhash expects - // the height of the block passed to it for (const auto & block : blocks) { crypto::hash id = get_block_hash(block); @@ -2961,7 +2933,6 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) } //------------------------------------------------------------------ -//FIXME: unused parameter txs void Blockchain::output_scan_worker(const uint64_t amount, const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const { try diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 94def1aa9..ab2c8f9e8 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -60,14 +60,11 @@ namespace cryptonote class tx_memory_pool; struct test_options; - /** Declares ways in which the BlockchainDB backend should be told to sync - * - */ enum blockchain_db_sync_mode { - db_sync, //!< handle syncing calls instead of the backing db, synchronously - db_async, //!< handle syncing calls instead of the backing db, asynchronously - db_nosync //!< Leave syncing up to the backing db (safest, but slowest because of disk I/O) + db_sync, + db_async, + db_nosync }; /************************************************************************/ @@ -76,9 +73,6 @@ namespace cryptonote class Blockchain { public: - /** - * @brief Now-defunct (TODO: remove) struct from in-memory blockchain - */ struct transaction_chain_entry { transaction tx; @@ -87,697 +81,127 @@ namespace cryptonote std::vector 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_size; //!< the size (in bytes) 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 + block bl; + uint64_t height; + size_t block_cumulative_size; + difficulty_type cumulative_difficulty; + uint64_t already_generated_coins; }; - /** - * @brief Blockchain constructor - * - * @param tx_pool a reference to the transaction pool to be kept by the Blockchain - */ Blockchain(tx_memory_pool& tx_pool); - /** - * @brief Initialize the Blockchain state - * - * @param db a pointer to the backing store to use for the blockchain - * @param testnet true if on testnet, else false - * @param test_options test parameters - * - * @return true on success, false if any initialization steps fail - */ bool init(BlockchainDB* db, const bool testnet = false, const cryptonote::test_options *test_options = NULL); - - /** - * @brief Initialize the Blockchain state - * - * @param db a pointer to the backing store to use for the blockchain - * @param hf a structure containing hardfork information - * @param testnet true if on testnet, else false - * - * @return true on success, false if any initialization steps fail - */ bool init(BlockchainDB* db, HardFork*& hf, const bool testnet = false); - - /** - * @brief Uninitializes the blockchain state - * - * Saves to disk any state that needs to be maintained - * - * @return true on success, false if any uninitialization steps fail - */ bool deinit(); - /** - * @brief assign a set of blockchain checkpoint hashes - * - * @param chk_pts the set of checkpoints to assign - */ void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; } - /** - * @brief get blocks and transactions from blocks based on start height and count - * - * @param start_offset the height on the blockchain to start at - * @param count the number of blocks to get, if there are as many after start_offset - * @param blocks return-by-reference container to put result blocks in - * @param txs return-by-reference container to put result transactions in - * - * @return false if start_offset > blockchain height, else true - */ + //bool push_new_block(); bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const; - - /** - * @brief get blocks from blocks based on start height and count - * - * @param start_offset the height on the blockchain to start at - * @param count the number of blocks to get, if there are as many after start_offset - * @param blocks return-by-reference container to put result blocks in - * - * @return false if start_offset > blockchain height, else true - */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const; - - /** - * @brief compiles a list of all blocks stored as alternative chains - * - * @param blocks return-by-reference container to put result blocks in - * - * @return true - */ bool get_alternative_blocks(std::list& blocks) const; - - /** - * @brief returns the number of alternative blocks stored - * - * @return the number of alternative blocks stored - */ size_t get_alternative_blocks_count() const; - - /** - * @brief gets a block's hash given a height - * - * @param height the height of the block - * - * @return the hash of the block at the requested height, or a zeroed hash if there is no such block - */ crypto::hash get_block_id_by_height(uint64_t height) const; - - /** - * @brief gets the block with a given hash - * - * @param h the hash to look for - * @param blk return-by-reference variable to put result block in - * - * @return true if the block was found, else false - */ bool get_block_by_hash(const crypto::hash &h, block &blk) const; - - /** - * @brief get all block hashes (main chain, alt chains, and invalid blocks) - * - * @param main return-by-reference container to put result main chain blocks' hashes in - * @param alt return-by-reference container to put result alt chain blocks' hashes in - * @param invalid return-by-reference container to put result invalid blocks' hashes in - */ void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) const; - - /** - * @brief performs some preprocessing on a group of incoming blocks to speed up verification - * - * @param blocks a list of incoming blocks - * - * @return false on erroneous blocks, else true - */ bool prepare_handle_incoming_blocks(const std::list &blocks); - - /** - * @brief incoming blocks post-processing, cleanup, and disk sync - * - * @param force_sync if true, and Blockchain is handling syncing to disk, always sync - * - * @return true - */ bool cleanup_handle_incoming_blocks(bool force_sync = false); - /** - * @brief search the blockchain for a transaction by hash - * - * @param id the hash to search for - * - * @return true if the tx exists, else false - */ bool have_tx(const crypto::hash &id) const; - - /** - * @brief check if any key image in a transaction has already been spent - * - * @param tx the transaction to check - * - * @return true if any key image is already spent in the blockchain, else false - */ bool have_tx_keyimges_as_spent(const transaction &tx) const; - - /** - * @brief check if a key image is already spent on the blockchain - * - * Whenever a transaction output is used as an input for another transaction - * (a true input, not just one of a mixing set), a key image is generated - * and stored in the transaction in order to prevent double spending. If - * this key image is seen again, the transaction using it is rejected. - * - * @param key_im the key image to search for - * - * @return true if the key image is already spent in the blockchain, else false - */ bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const; - /** - * @brief get the current height of the blockchain - * - * @return the height - */ uint64_t get_current_blockchain_height() const; - - /** - * @brief get the hash of the most recent block on the blockchain - * - * @return the hash - */ crypto::hash get_tail_id() const; - - /** - * @brief get the height and hash of the most recent block on the blockchain - * - * @param height return-by-reference variable to store the height in - * - * @return the hash - */ crypto::hash get_tail_id(uint64_t& height) const; - - /** - * @brief returns the difficulty target the next block to be added must meet - * - * @return the target - */ difficulty_type get_difficulty_for_next_block(); - - /** - * @brief adds a block to the blockchain - * - * Adds a new block to the blockchain. If the block's parent is not the - * current top of the blockchain, the block may be added to an alternate - * chain. If the block does not belong, is already in the blockchain - * or an alternate chain, or is invalid, return false. - * - * @param bl_ the block to be added - * @param bvc metadata about the block addition's success/failure - * - * @return true on successful addition to the blockchain, else false - */ bool add_new_block(const block& bl_, block_verification_context& bvc); - - /** - * @brief clears the blockchain and starts a new one - * - * @param b the first block in the new chain (the genesis block) - * - * @return true on success, else false - */ bool reset_and_set_genesis_block(const block& b); - - /** - * @brief creates a new block to mine against - * - * @param b return-by-reference block to be filled in - * @param miner_address address new coins for the block will go to - * @param di return-by-reference tells the miner what the difficulty target is - * @param height return-by-reference tells the miner what height it's mining against - * @param ex_nonce extra data to be added to the miner transaction's extra - * - * @return true if block template filled in successfully, else false - */ bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce); - - /** - * @brief checks if a block is known about with a given hash - * - * This function checks the main chain, alternate chains, and invalid blocks - * for a block with the given hash - * - * @param id the hash to search for - * - * @return true if the block is known, else false - */ bool have_block(const crypto::hash& id) const; - - /** - * @brief gets the total number of transactions on the main chain - * - * @return the number of transactions on the main chain - */ size_t get_total_transactions() const; - - /** - * @brief gets the hashes for a subset of the blockchain - * - * puts into list a list of hashes representing certain blocks - * from the blockchain in reverse chronological order - * - * the blocks chosen, at the time of this writing, are: - * the most recent 11 - * powers of 2 less recent from there, so 13, 17, 25, etc... - * - * @param ids return-by-reference list to put the resulting hashes in - * - * @return true - */ bool get_short_chain_history(std::list& ids) const; - - /** - * @brief get recent block hashes for a foreign chain - * - * Find the split point between us and foreign blockchain and return - * (by reference) the most recent common block hash along with up to - * BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes. - * - * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) - * @param resp return-by-reference the split height and subsequent blocks' hashes - * - * @return true if a block found in common, else false - */ bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const; - - /** - * @brief find the most recent common point between ours and a foreign chain - * - * This function takes a list of block hashes from another node - * on the network to find where the split point is between us and them. - * This is used to see what to send another node that needs to sync. - * - * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) - * @param starter_offset return-by-reference the most recent common block's height - * - * @return true if a block found in common, else false - */ bool find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset) const; - - /** - * @brief get recent blocks for a foreign chain - * - * This function gets recent blocks relative to a foreign chain, starting either at - * a requested height or whatever height is the most recent ours and the foreign - * chain have in common. - * - * @param req_start_block if non-zero, specifies a start point (otherwise find most recent commonality) - * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) - * @param blocks return-by-reference the blocks and their transactions - * @param total_height return-by-reference our current blockchain height - * @param start_height return-by-reference the height of the first block returned - * @param max_count the max number of blocks to get - * - * @return true if a block found in common or req_start_block specified, else false - */ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const; - - /** - * @brief retrieves a set of blocks and their transactions, and possibly other transactions - * - * the request object encapsulates a list of block hashes and a (possibly empty) list of - * transaction hashes. for each block hash, the block is fetched along with all of that - * block's transactions. Any transactions requested separately are fetched afterwards. - * - * @param arg the request - * @param rsp return-by-reference the response to fill in - * - * @return true unless any blocks or transactions are missing - */ bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp); - - /** - * @brief gets random outputs to mix with - * - * This function takes an RPC request for outputs to mix with - * and creates an RPC response with the resultant output indices. - * - * Outputs to mix with are randomly selected from the utxo set - * for each output amount in the request. - * - * @param req the output amounts and number of mixins to select - * @param res return-by-reference the resultant output indices - * - * @return true - */ + bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res); bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const; - - /** - * @brief gets the global indices for outputs from a given transaction - * - * This function gets the global indices for all outputs belonging - * to a specific transaction. - * - * @param tx_id the hash of the transaction to fetch indices for - * @param indexs return-by-reference the global indices for the transaction's outputs - * - * @return false if the transaction does not exist, or if no indices are found, otherwise true - */ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; - - /** - * @brief stores the blockchain - * - * If Blockchain is handling storing of the blockchain (rather than BlockchainDB), - * this initiates a blockchain save. - * - * @return true unless saving the blockchain fails - */ bool store_blockchain(); - /** - * @brief validates a transaction's inputs - * - * validates a transaction's inputs as correctly used and not previously - * spent. also returns the hash and height of the most recent block - * which contains an output that was used as an input to the transaction. - * - * @param tx the transaction to validate - * @param pmax_used_block_height return-by-reference block height of most recent input - * @param max_used_block_id return-by-reference block hash of most recent input - * @param kept_by_block whether or not the transaction is from a previously-verified block - * - * @return false if any input is invalid, otherwise true - */ bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, bool kept_by_block = false); - - /** - * @brief check that a transaction's outputs conform to current standards - * - * This function checks, for example at the time of this writing, that - * each output is of the form a * 10^b (phrased differently, that if - * written out would have only one non-zero digit in base 10). - * - * @param tx the transaction to check the outputs of - * - * @return false if any outputs do not conform, otherwise true - */ bool check_tx_outputs(const transaction& tx); - - /** - * @brief gets the blocksize limit based on recent blocks - * - * @return the limit - */ uint64_t get_current_cumulative_blocksize_limit() const; - - /** - * @brief checks if the blockchain is currently being stored - * - * Note: this should be meaningless in cases where Blockchain is not - * directly managing saving the blockchain to disk. - * - * @return true if Blockchain is having the chain stored currently, else false - */ bool is_storing_blockchain()const{return m_is_blockchain_storing;} - - /** - * @brief gets the difficulty of the block with a given height - * - * @param i the height - * - * @return the difficulty - */ uint64_t block_difficulty(uint64_t i) const; - /** - * @brief gets blocks based on a list of block hashes - * - * @tparam t_ids_container a standard-iterable container - * @tparam t_blocks_container a standard-iterable container - * @tparam t_missed_container a standard-iterable container - * @param block_ids a container of block hashes for which to get the corresponding blocks - * @param blocks return-by-reference a container to store result blocks in - * @param missed_bs return-by-reference a container to store missed blocks in - * - * @return false if an unexpected exception occurs, else true - */ template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const; - /** - * @brief gets transactions based on a list of transaction hashes - * - * @tparam t_ids_container a standard-iterable container - * @tparam t_tx_container a standard-iterable container - * @tparam t_missed_container a standard-iterable container - * @param txs_ids a container of hashes for which to get the corresponding transactions - * @param txs return-by-reference a container to store result transactions in - * @param missed_txs return-by-reference a container to store missed transactions in - * - * @return false if an unexpected exception occurs, else true - */ template bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const; - //debug functions - - /** - * @brief prints data about a snippet of the blockchain - * - * if start_index is greater than the blockchain height, do nothing - * - * @param start_index height on chain to start at - * @param end_index height on chain to end at - */ void print_blockchain(uint64_t start_index, uint64_t end_index) const; - - /** - * @brief prints every block's hash - * - * WARNING: This function will absolutely crush a terminal in prints, so - * it is recommended to redirect this output to a log file (or null sink - * if a log file is already set up, as should be the default) - */ void print_blockchain_index() const; - - /** - * @brief currently does nothing, candidate for removal - * - * @param file - */ void print_blockchain_outs(const std::string& file) const; - /** - * @brief check the blockchain against a set of checkpoints - * - * If a block fails a checkpoint and enforce is enabled, the blockchain - * will be rolled back to two blocks prior to that block. If enforce - * is disabled, as is currently the default case with DNS-based checkpoints, - * an error will be printed to the user but no other action will be taken. - * - * @param points the checkpoints to check against - * @param enforce whether or not to take action on failure - */ void check_against_checkpoints(const checkpoints& points, bool enforce); - - /** - * @brief configure whether or not to enforce DNS-based checkpoints - * - * @param enforce the new enforcement setting - */ void set_enforce_dns_checkpoints(bool enforce); - - /** - * @brief loads new checkpoints from a file and optionally from DNS - * - * @param file_path the path of the file to look for and load checkpoints from - * @param check_dns whether or not to check for new DNS-based checkpoints - * - * @return false if any enforced checkpoint type fails to load, otherwise true - */ bool update_checkpoints(const std::string& file_path, bool check_dns); - // user options, must be called before calling init() - - //FIXME: parameter names don't match function definition in .cpp file - /** - * @brief sets various performance options - * - * @param block_threads max number of threads when preparing blocks for addition - * @param blocks_per_sync number of blocks to cache before syncing to database - * @param sync_mode the ::blockchain_db_sync_mode to use - * @param fast_sync sync using built-in block hashes as trusted - */ void set_user_options(uint64_t block_threads, uint64_t blocks_per_sync, blockchain_db_sync_mode sync_mode, bool fast_sync); - /** - * @brief set whether or not to show/print time statistics - * - * @param stats the new time stats setting - */ void set_show_time_stats(bool stats) { m_show_time_stats = stats; } - /** - * @brief gets the hardfork voting state object - * - * @return the HardFork object - */ HardFork::State get_hard_fork_state() const; - - /** - * @brief gets the current hardfork version in use/voted for - * - * @return the version - */ uint8_t get_current_hard_fork_version() const { return m_hardfork->get_current_version(); } - - /** - * @brief returns the newest hardfork version known to the blockchain - * - * @return the version - */ uint8_t get_ideal_hard_fork_version() const { return m_hardfork->get_ideal_version(); } - - /** - * @brief returns the newest hardfork version voted to be enabled - * as of a certain height - * - * @param height the height for which to check version info - * - * @return the version - */ uint8_t get_ideal_hard_fork_version(uint64_t height) const { return m_hardfork->get_ideal_version(height); } - /** - * @brief get information about hardfork voting for a version - * - * @param version the version in question - * @param window the size of the voting window - * @param votes the number of votes to enable - * @param threshold the number of votes required to enable - * @param earliest_height the earliest height at which is allowed - * @param voting which version this node is voting for/using - * - * @return whether the version queried is enabled - */ bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const; - /** - * @brief remove transactions from the transaction pool (if present) - * - * @param txids a list of hashes of transactions to be removed - * - * @return false if any removals fail, otherwise true - */ bool flush_txes_from_pool(const std::list &txids); - /** - * @brief perform a check on all key images in the blockchain - * - * @param std::function the check to perform, pass/fail - * - * @return false if any key image fails the check, otherwise true - */ bool for_all_key_images(std::function) const; - - /** - * @brief perform a check on all blocks in the blockchain - * - * @param std::function the check to perform, pass/fail - * - * @return false if any block fails the check, otherwise true - */ bool for_all_blocks(std::function) const; - - /** - * @brief perform a check on all transactions in the blockchain - * - * @param std::function the check to perform, pass/fail - * - * @return false if any transaction fails the check, otherwise true - */ bool for_all_transactions(std::function) const; - - /** - * @brief perform a check on all outputs in the blockchain - * - * @param std::function the check to perform, pass/fail - * - * @return false if any output fails the check, otherwise true - */ bool for_all_outputs(std::function) const; - /** - * @brief get a reference to the BlockchainDB in use by Blockchain - * - * @return a reference to the BlockchainDB instance - */ BlockchainDB& get_db() { return *m_db; } - /** - * @brief get a number of outputs of a specific amount - * - * @param amount the amount - * @param offsets the indices (indexed to the amount) of the outputs - * @param outputs return-by-reference the outputs collected - * @param txs unused, candidate for removal - */ void output_scan_worker(const uint64_t amount,const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const; - /** - * @brief computes the "short" and "long" hashes for a set of blocks - * - * @param height the height of the first block - * @param blocks the blocks to be hashed - * @param map return-by-reference the hashes for each block - */ void block_longhash_worker(const uint64_t height, const std::vector &blocks, std::unordered_map &map) const; private: - - // TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage typedef std::unordered_map blocks_by_id_index; - typedef std::unordered_map transactions_container; - typedef std::unordered_set key_images_container; - typedef std::vector blocks_container; - typedef std::unordered_map blocks_ext_by_hash; - typedef std::unordered_map blocks_by_hash; - typedef std::map>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction - BlockchainDB* m_db; tx_memory_pool& m_tx_pool; - 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_sz_limit; - // metadata containers std::unordered_map>> m_scan_table; std::unordered_map> m_check_tx_inputs_table; std::unordered_map m_blocks_longhash_table; @@ -819,323 +243,39 @@ namespace cryptonote bool m_testnet; - /** - * @brief collects the keys for all outputs being "spent" as an input - * - * This function makes sure that each "input" in an input (mixins) exists - * and collects the public key for each from the transaction it was included in - * via the visitor passed to it. - * - * If pmax_related_block_height is not NULL, its value is set to the height - * of the most recent block which contains an output used in the input set - * - * @tparam visitor_t a class encapsulating tx is unlocked and collect tx key - * @param tx_in_to_key a transaction input instance - * @param vis an instance of the visitor to use - * @param tx_prefix_hash the hash of the associated transaction_prefix - * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set - * - * @return false if any keys are not found or any inputs are not unlocked, otherwise true - */ template inline bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t &vis, const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height = NULL) const; - - /** - * @brief collect output public keys of a transaction input set - * - * This function locates all outputs associated with a given input set (mixins) - * and validates that they exist and are usable - * (unlocked, unspent is checked elsewhere). - * - * If pmax_related_block_height is not NULL, its value is set to the height - * of the most recent block which contains an output used in the input set - * - * @param txin the transaction input - * @param tx_prefix_hash the transaction prefix hash, for caching organization - * @param sig the input signature - * @param output_keys return-by-reference the public keys of the outputs in the input set - * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set - * - * @return false if any output is not yet unlocked, or is missing, otherwise true - */ bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); - - /** - * @brief validate a transaction's inputs and their keys - * - * This function validates transaction inputs and their keys. Previously - * it also performed double spend checking, but that has been moved to its - * own function. - * - * If pmax_related_block_height is not NULL, its value is set to the height - * of the most recent block which contains an output used in any input set - * - * Currently this function calls ring signature validation for each - * transaction. - * - * @param tx the transaction to validate - * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set - * - * @return false if any validation step fails, otherwise true - */ bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL); - /** - * @brief performs a blockchain reorganization according to the longest chain rule - * - * This function aggregates all the actions necessary to switch to a - * newly-longer chain. If any step in the reorganization process fails, - * the blockchain is reverted to its previous state. - * - * @param alt_chain the chain to switch to - * @param discard_disconnected_chain whether or not to keep the old chain as an alternate - * - * @return false if the reorganization fails, otherwise true - */ bool switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain); - - /** - * @brief removes the most recent block from the blockchain - * - * @return the block removed - */ block pop_block_from_blockchain(); - /** - * @brief validate and add a new block to the end of the blockchain - * - * This function is merely a convenience wrapper around the other - * of the same name. This one passes the block's hash to the other - * as well as the block and verification context. - * - * @param bl the block to be added - * @param bvc metadata concerning the block's validity - * - * @return true if the block was added successfully, otherwise false - */ bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc); - - /** - * @brief validate and add a new block to the end of the blockchain - * - * When a block is given to Blockchain to be added to the blockchain, it - * is passed here if it is determined to belong at the end of the current - * chain. - * - * @param bl the block to be added - * @param id the hash of the block - * @param bvc metadata concerning the block's validity - * - * @return true if the block was added successfully, otherwise false - */ bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc); - - /** - * @brief validate and add a new block to an alternate blockchain - * - * If a block to be added does not belong to the main chain, but there - * is an alternate chain to which it should be added, that is handled - * here. - * - * @param b the block to be added - * @param id the hash of the block - * @param bvc metadata concerning the block's validity - * - * @return true if the block was added successfully, otherwise false - */ bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc); - - /** - * @brief gets the difficulty requirement for a new block on an alternate chain - * - * @param alt_chain the chain to be added to - * @param bei the block being added (and metadata, see ::block_extended_info) - * - * @return the difficulty requirement - */ difficulty_type get_next_difficulty_for_alternative_chain(const std::list& alt_chain, block_extended_info& bei) const; - - /** - * @brief sanity checks a miner transaction before validating an entire block - * - * This function merely checks basic things like the structure of the miner - * transaction, the unlock time, and that the amount doesn't overflow. - * - * @param b the block containing the miner transaction - * @param height the height at which the block will be added - * - * @return false if anything is found wrong with the miner transaction, otherwise true - */ bool prevalidate_miner_transaction(const block& b, uint64_t height); - - /** - * @brief validates a miner (coinbase) transaction - * - * This function makes sure that the miner calculated his reward correctly - * and that his miner transaction totals reward + fee. - * - * @param b the block containing the miner transaction to be validated - * @param cumulative_block_size the block's size - * @param fee the total fees collected in the block - * @param base_reward return-by-reference the new block's generated coins - * @param already_generated_coins the amount of currency generated prior to this block - * @param partial_block_reward return-by-reference true if miner accepted only partial reward - * - * @return false if anything is found wrong with the miner transaction, otherwise true - */ bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward); - - /** - * @brief reverts the blockchain to its previous state following a failed switch - * - * If Blockchain fails to switch to an alternate chain when it means - * to do so, this function reverts the blockchain to how it was before - * the attempted switch. - * - * @param original_chain the chain to switch back to - * @param rollback_height the height to revert to before appending the original chain - * - * @return false if something goes wrong with reverting (very bad), otherwise true - */ + bool validate_transaction(const block& b, uint64_t height, const transaction& tx); bool rollback_blockchain_switching(std::list& original_chain, uint64_t rollback_height); - - /** - * @brief gets recent block sizes for median calculation - * - * get the block sizes of the last blocks, and return by reference . - * - * @param sz return-by-reference the list of sizes - * @param count the number of blocks to get sizes for - */ + bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height); + bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); + bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); void get_last_n_blocks_sizes(std::vector& sz, size_t count) const; - - /** - * @brief adds the given output to the requested set of random outputs - * - * @param result_outs return-by-reference the set the output is to be added to - * @param amount the output amount - * @param i the output index (indexed to amount) - */ void add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i) const; - - /** - * @brief checks if a transaction is unlocked (its outputs spendable) - * - * This function checks to see if a transaction is unlocked. - * unlock_time is either a block index or a unix time. - * - * @param unlock_time the unlock parameter (height or time) - * - * @return true if spendable, otherwise false - */ bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; - - /** - * @brief stores an invalid block in a separate container - * - * Storing invalid blocks allows quick dismissal of the same block - * if it is seen again. - * - * @param bl the invalid block - * @param h the block's hash - * - * @return false if the block cannot be stored for some reason, otherwise true - */ bool add_block_as_invalid(const block& bl, const crypto::hash& h); - - /** - * @brief stores an invalid block in a separate container - * - * Storing invalid blocks allows quick dismissal of the same block - * if it is seen again. - * - * @param bei the invalid block (see ::block_extended_info) - * @param h the block's hash - * - * @return false if the block cannot be stored for some reason, otherwise true - */ bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); - - /** - * @brief checks a block's timestamp - * - * This function grabs the timestamps from the most recent blocks, - * where n = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. If there are not those many - * blocks in the blockchain, the timestap is assumed to be valid. If there - * are, this function returns: - * true if the block's timestamp is not less than the timestamp of the - * median of the selected blocks - * false otherwise - * - * @param b the block to be checked - * - * @return true if the block's timestamp is valid, otherwise false - */ bool check_block_timestamp(const block& b) const; - - /** - * @brief checks a block's timestamp - * - * If the block is not more recent than the median of the recent - * timestamps passed here, it is considered invalid. - * - * @param timestamps a list of the most recent timestamps to check against - * @param b the block to be checked - * - * @return true if the block's timestamp is valid, otherwise false - */ bool check_block_timestamp(std::vector& timestamps, const block& b) const; - - /** - * @brief get the "adjusted time" - * - * Currently this simply returns the current time according to the - * user's machine. - * - * @return the current time - */ uint64_t get_adjusted_time() const; - - /** - * @brief finish an alternate chain's timestamp window from the main chain - * - * for an alternate chain, get the timestamps from the main chain to complete - * the needed number of timestamps for the BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. - * - * @param start_height the alternate chain's attachment height to the main chain - * @param timestamps return-by-value the timestamps set to be populated - * - * @return true unless start_height is greater than the current blockchain height - */ bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); - - /** - * @brief calculate the block size limit for the next block to be added - * - * @return true - */ bool update_next_cumulative_size_limit(); void return_tx_to_pool(const std::vector &txs); - /** - * @brief make sure a transaction isn't attempting a double-spend - * - * @param tx the transaction to check - * @param keys_this_block a cumulative list of spent keys for the current block - * - * @return false if a double spend was detected, otherwise true - */ bool check_for_double_spend(const transaction& tx, key_images_container& keys_this_block) const; - - /** - * @brief validates a transaction input's ring signature - * - * @param tx_prefix_hash the transaction prefix' hash - * @param key_image the key image generated from the true input - * @param pubkeys the public keys for each input in the ring signature - * @param sig the signature generated for each input in the ring signature - * @param result false if the ring signature is invalid, otherwise true - */ + void get_timestamp_and_difficulty(uint64_t ×tamp, difficulty_type &difficulty, const int offset) const; void check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector &pubkeys, const std::vector &sig, uint64_t &result); diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index a829b7cbe..e1b89f887 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -48,7 +48,7 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "cryptonote_core/checkpoints.h" +#include "cryptonote_core/checkpoints_create.h" //#include "serialization/json_archive.h" #include "../../contrib/otshell_utils/utils.hpp" #include "../../src/p2p/data_logger.hpp" @@ -1854,7 +1854,7 @@ void blockchain_storage::check_against_checkpoints(const checkpoints& points, bo // with an existing checkpoint. bool blockchain_storage::update_checkpoints(const std::string& file_path, bool check_dns) { - if (!m_checkpoints.load_checkpoints_from_json(file_path)) + if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) { return false; } @@ -1863,7 +1863,7 @@ bool blockchain_storage::update_checkpoints(const std::string& file_path, bool c // if we're not hard-enforcing dns checkpoints, handle accordingly if (m_enforce_dns_checkpoints && check_dns) { - if (!m_checkpoints.load_checkpoints_from_dns()) + if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) { return false; } @@ -1871,7 +1871,7 @@ bool blockchain_storage::update_checkpoints(const std::string& file_path, bool c else if (check_dns) { checkpoints dns_points; - dns_points.load_checkpoints_from_dns(m_testnet); + cryptonote::load_checkpoints_from_dns(dns_points, m_testnet); if (m_checkpoints.check_for_conflicts(dns_points)) { check_against_checkpoints(dns_points, false); diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index c038a4802..24d066dae 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -1,21 +1,21 @@ // Copyright (c) 2014-2016, 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 @@ -25,44 +25,14 @@ // 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. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include "include_base_utils.h" - using namespace epee; #include "checkpoints.h" -#include "common/dns_utils.h" -#include "include_base_utils.h" -#include -#include - -namespace -{ - bool dns_records_match(const std::vector& a, const std::vector& b) - { - if (a.size() != b.size()) return false; - - for (const auto& record_in_a : a) - { - bool ok = false; - for (const auto& record_in_b : b) - { - if (record_in_a == record_in_b) - { - ok = true; - break; - } - } - if (!ok) return false; - } - - return true; - } -} // anonymous namespace - namespace cryptonote { //--------------------------------------------------------------------------- @@ -114,7 +84,10 @@ namespace cryptonote return check_block(height, h, ignored); } //--------------------------------------------------------------------------- - //FIXME: is this the desired behavior? + // this basically says if the blockchain is smaller than the first + // checkpoint then alternate blocks are allowed. Alternatively, if the + // last checkpoint *before* the end of the current chain is also before + // the block to be added, then this is fine. bool checkpoints::is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const { if (0 == block_height) @@ -155,206 +128,4 @@ namespace cryptonote } return true; } - - bool checkpoints::init_default_checkpoints() - { - ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); - ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); - ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); - ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876"); - ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2"); - ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); - ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); - ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); - ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3"); - ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"); - ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); - ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); - ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); - ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553"); - ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61"); - ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf"); - ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131"); - ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8"); - ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d"); - ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831"); - ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02"); - ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5"); - ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd"); - ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60"); - ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337"); - ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f"); - - return true; - } - - bool checkpoints::load_checkpoints_from_json(const std::string json_hashfile_fullpath) - { - boost::system::error_code errcode; - if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode))) - { - LOG_PRINT_L1("Blockchain checkpoints file not found"); - return true; - } - - LOG_PRINT_L1("Adding checkpoints from blockchain hashfile"); - - uint64_t prev_max_height = get_max_height(); - LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height); - t_hash_json hashes; - epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath); - for (std::vector::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); ) - { - uint64_t height; - height = it->height; - if (height <= prev_max_height) { - LOG_PRINT_L1("ignoring checkpoint height " << height); - } else { - std::string blockhash = it->hash; - LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash); - ADD_CHECKPOINT(height, blockhash); - } - ++it; - } - - return true; - } - - bool checkpoints::load_checkpoints_from_dns(bool testnet) - { - // All four MoneroPulse domains have DNSSEC on and valid - static const std::vector dns_urls = { "checkpoints.moneropulse.se" - , "checkpoints.moneropulse.org" - , "checkpoints.moneropulse.net" - , "checkpoints.moneropulse.co" - }; - - static const std::vector testnet_dns_urls = { "testpoints.moneropulse.se" - , "testpoints.moneropulse.org" - , "testpoints.moneropulse.net" - , "testpoints.moneropulse.co" - }; - - std::vector > records; - records.resize(dns_urls.size()); - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(0, dns_urls.size() - 1); - size_t first_index = dis(gen); - - bool avail, valid; - size_t cur_index = first_index; - do - { - std::string url; - if (testnet) - { - url = testnet_dns_urls[cur_index]; - } - else - { - url = dns_urls[cur_index]; - } - - records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid); - if (!avail) - { - records[cur_index].clear(); - LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); - } - if (!valid) - { - records[cur_index].clear(); - LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); - } - - cur_index++; - if (cur_index == dns_urls.size()) - { - cur_index = 0; - } - records[cur_index].clear(); - } while (cur_index != first_index); - - size_t num_valid_records = 0; - - for( const auto& record_set : records) - { - if (record_set.size() != 0) - { - num_valid_records++; - } - } - - if (num_valid_records < 2) - { - LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received"); - return true; - } - - int good_records_index = -1; - for (size_t i = 0; i < records.size() - 1; ++i) - { - if (records[i].size() == 0) continue; - - for (size_t j = i + 1; j < records.size(); ++j) - { - if (dns_records_match(records[i], records[j])) - { - good_records_index = i; - break; - } - } - if (good_records_index >= 0) break; - } - - if (good_records_index < 0) - { - LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched"); - return true; - } - - for (auto& record : records[good_records_index]) - { - auto pos = record.find(":"); - if (pos != std::string::npos) - { - uint64_t height; - crypto::hash hash; - - // parse the first part as uint64_t, - // if this fails move on to the next record - std::stringstream ss(record.substr(0, pos)); - if (!(ss >> height)) - { - continue; - } - - // parse the second part as crypto::hash, - // if this fails move on to the next record - std::string hashStr = record.substr(pos + 1); - if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash)) - { - continue; - } - - ADD_CHECKPOINT(height, hashStr); - } - } - return true; - } - - bool checkpoints::load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet, bool dns) - { - bool result; - - result = load_checkpoints_from_json(json_hashfile_fullpath); - if (dns) - { - result &= load_checkpoints_from_dns(testnet); - } - - return result; - } } diff --git a/src/cryptonote_core/checkpoints.h b/src/cryptonote_core/checkpoints.h index 71727753e..00a53ec24 100644 --- a/src/cryptonote_core/checkpoints.h +++ b/src/cryptonote_core/checkpoints.h @@ -1,21 +1,21 @@ // Copyright (c) 2014-2016, 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 @@ -25,193 +25,30 @@ // 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. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once #include #include #include "cryptonote_basic_impl.h" -#include "misc_log_ex.h" -#include "storages/portable_storage_template_helper.h" // epee json include - -#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false); -#define JSON_HASH_FILE_NAME "checkpoints.json" namespace cryptonote { - /** - * @brief A container for blockchain checkpoints - * - * A checkpoint is a pre-defined hash for the block at a given height. - * Some of these are compiled-in, while others can be loaded at runtime - * either from a json file or via DNS from a checkpoint-hosting server. - */ class checkpoints { public: - - /** - * @brief default constructor - */ checkpoints(); - - /** - * @brief adds a checkpoint to the container - * - * @param height the height of the block the checkpoint is for - * @param hash_str the hash of the block, as a string - * - * @return false if parsing the hash fails, or if the height is a duplicate - * AND the existing checkpoint hash does not match the new one, - * otherwise returns true - */ bool add_checkpoint(uint64_t height, const std::string& hash_str); - - /** - * @brief checks if there is a checkpoint in the future - * - * This function checks if the height passed is lower than the highest - * checkpoint. - * - * @param height the height to check against - * - * @return false if no checkpoints, otherwise returns whether or not - * the height passed is lower than the highest checkpoint. - */ bool is_in_checkpoint_zone(uint64_t height) const; - - /** - * @brief checks if the given height and hash agree with the checkpoints - * - * This function checks if the given height and hash exist in the - * checkpoints container. If so, it returns whether or not the passed - * parameters match the stored values. - * - * @param height the height to be checked - * @param h the hash to be checked - * @param is_a_checkpoint return-by-reference if there is a checkpoint at the given height - * - * @return true if there is no checkpoint at the given height, - * true if the passed parameters match the stored checkpoint, - * false otherwise - */ - bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const; - - /** - * @overload - */ bool check_block(uint64_t height, const crypto::hash& h) const; - - /** - * @brief checks if alternate chain blocks should be kept for a given height - * - * this basically says if the blockchain is smaller than the first - * checkpoint then alternate blocks are allowed. Alternatively, if the - * last checkpoint *before* the end of the current chain is also before - * the block to be added, then this is fine. - * - * @param blockchain_height the current blockchain height - * @param block_height the height of the block to be added as alternate - * - * @return true if alternate blocks are allowed given the parameters, - * otherwise false - */ + bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const; bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const; - - /** - * @brief gets the highest checkpoint height - * - * @return the height of the highest checkpoint - */ uint64_t get_max_height() const; - - /** - * @brief gets the checkpoints container - * - * @return a const reference to the checkpoints container - */ const std::map& get_points() const; - - /** - * @brief checks if our checkpoints container conflicts with another - * - * A conflict refers to a case where both checkpoint sets have a checkpoint - * for a specific height but their hashes for that height do not match. - * - * @param other the other checkpoints instance to check against - * - * @return false if any conflict is found, otherwise true - */ bool check_for_conflicts(const checkpoints& other) const; - - /** - * @brief loads the default main chain checkpoints - * - * @return true unless adding a checkpoint fails - */ - bool init_default_checkpoints(); - - /** - * @brief load new checkpoints - * - * Loads new checkpoints from the specified json file, as well as - * (optionally) from DNS. - * - * @param json_hashfile_fullpath path to the json checkpoints file - * @param testnet whether to load testnet checkpoints or mainnet - * @param dns whether or not to load DNS checkpoints - * - * @return true if loading successful and no conflicts - */ - bool load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet=false, bool dns=true); - - /** - * @brief load new checkpoints from json - * - * @param json_hashfile_fullpath path to the json checkpoints file - * - * @return true if loading successful and no conflicts - */ - bool load_checkpoints_from_json(const std::string json_hashfile_fullpath); - - /** - * @brief load new checkpoints from DNS - * - * @param testnet whether to load testnet checkpoints or mainnet - * - * @return true if loading successful and no conflicts - */ - bool load_checkpoints_from_dns(bool testnet = false); - private: - - - /** - * @brief struct for loading a checkpoint from json - */ - struct t_hashline - { - uint64_t height; //!< the height of the checkpoint - std::string hash; //!< the hash for the checkpoint - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(height) - KV_SERIALIZE(hash) - END_KV_SERIALIZE_MAP() - }; - - /** - * @brief struct for loading many checkpoints from json - */ - struct t_hash_json { - std::vector hashlines; //!< the checkpoint lines from the file - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(hashlines) - END_KV_SERIALIZE_MAP() - }; - - std::map m_points; //!< the checkpoints container - + std::map m_points; }; } diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp new file mode 100644 index 000000000..41f2321d5 --- /dev/null +++ b/src/cryptonote_core/checkpoints_create.cpp @@ -0,0 +1,280 @@ +// Copyright (c) 2014-2016, 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "checkpoints_create.h" +#include "common/dns_utils.h" +#include "include_base_utils.h" +#include +#include +#include "storages/portable_storage_template_helper.h" // epee json include + +namespace +{ + bool dns_records_match(const std::vector& a, const std::vector& b) + { + if (a.size() != b.size()) return false; + + for (const auto& record_in_a : a) + { + bool ok = false; + for (const auto& record_in_b : b) + { + if (record_in_a == record_in_b) + { + ok = true; + break; + } + } + if (!ok) return false; + } + + return true; + } +} // anonymous namespace + +namespace cryptonote +{ + +struct t_hashline +{ + uint64_t height; + std::string hash; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(hash) + END_KV_SERIALIZE_MAP() +}; + +struct t_hash_json { + std::vector hashlines; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hashlines) + END_KV_SERIALIZE_MAP() +}; + +bool create_checkpoints(cryptonote::checkpoints& checkpoints) +{ + ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); + ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); + ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); + ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876"); + ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2"); + ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); + ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); + ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); + ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3"); + ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"); + ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); + ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); + ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); + ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553"); + ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61"); + ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf"); + ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131"); + ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8"); + ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d"); + ADD_CHECKPOINT(300000, "0c1cd46df6ccff90ec4ab493281f2583c344cd62216c427628990fe9db1bb8b6"); + ADD_CHECKPOINT(400000, "1b2b0e7a30e59691491529a3d506d1ba3d6052d0f6b52198b7330b28a6f1b6ac"); + ADD_CHECKPOINT(450000, "4d098b511ca97723e81737c448343cfd4e6dadb3d8a0e757c6e4d595e6e48357"); + ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831"); + ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02"); + ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5"); + ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd"); + ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60"); + ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337"); + ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f"); + + return true; +} + +bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath) +{ + boost::system::error_code errcode; + if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode))) + { + LOG_PRINT_L1("Blockchain checkpoints file not found"); + return true; + } + + LOG_PRINT_L1("Adding checkpoints from blockchain hashfile"); + + uint64_t prev_max_height = checkpoints.get_max_height(); + LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height); + t_hash_json hashes; + epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath); + for (std::vector::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); ) + { + uint64_t height; + height = it->height; + if (height <= prev_max_height) { + LOG_PRINT_L1("ignoring checkpoint height " << height); + } else { + std::string blockhash = it->hash; + LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash); + ADD_CHECKPOINT(height, blockhash); + } + ++it; + } + + return true; +} + +bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet) +{ + // All four MoneroPulse domains have DNSSEC on and valid + static const std::vector dns_urls = { "checkpoints.moneropulse.se" + , "checkpoints.moneropulse.org" + , "checkpoints.moneropulse.net" + , "checkpoints.moneropulse.co" + }; + + static const std::vector testnet_dns_urls = { "testpoints.moneropulse.se" + , "testpoints.moneropulse.org" + , "testpoints.moneropulse.net" + , "testpoints.moneropulse.co" + }; + + std::vector > records; + records.resize(dns_urls.size()); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, dns_urls.size() - 1); + size_t first_index = dis(gen); + + bool avail, valid; + size_t cur_index = first_index; + do + { + std::string url; + if (testnet) + { + url = testnet_dns_urls[cur_index]; + } + else + { + url = dns_urls[cur_index]; + } + + records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid); + if (!avail) + { + records[cur_index].clear(); + LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); + } + if (!valid) + { + records[cur_index].clear(); + LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); + } + + cur_index++; + if (cur_index == dns_urls.size()) + { + cur_index = 0; + } + records[cur_index].clear(); + } while (cur_index != first_index); + + size_t num_valid_records = 0; + + for( const auto& record_set : records) + { + if (record_set.size() != 0) + { + num_valid_records++; + } + } + + if (num_valid_records < 2) + { + LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received"); + return true; + } + + int good_records_index = -1; + for (size_t i = 0; i < records.size() - 1; ++i) + { + if (records[i].size() == 0) continue; + + for (size_t j = i + 1; j < records.size(); ++j) + { + if (dns_records_match(records[i], records[j])) + { + good_records_index = i; + break; + } + } + if (good_records_index >= 0) break; + } + + if (good_records_index < 0) + { + LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched"); + return true; + } + + for (auto& record : records[good_records_index]) + { + auto pos = record.find(":"); + if (pos != std::string::npos) + { + uint64_t height; + crypto::hash hash; + + // parse the first part as uint64_t, + // if this fails move on to the next record + std::stringstream ss(record.substr(0, pos)); + if (!(ss >> height)) + { + continue; + } + + // parse the second part as crypto::hash, + // if this fails move on to the next record + std::string hashStr = record.substr(pos + 1); + if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash)) + { + continue; + } + + ADD_CHECKPOINT(height, hashStr); + } + } + return true; +} + +bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath) +{ + // TODO: replace hard-coded url with const string or #define + return (load_checkpoints_from_json(checkpoints, json_hashfile_fullpath) && load_checkpoints_from_dns(checkpoints)); +} + +} // namespace cryptonote diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h new file mode 100644 index 000000000..83830f8a2 --- /dev/null +++ b/src/cryptonote_core/checkpoints_create.h @@ -0,0 +1,48 @@ +// Copyright (c) 2014-2016, 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include "checkpoints.h" +#include "misc_log_ex.h" + +#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false); +#define JSON_HASH_FILE_NAME "checkpoints.json" + +namespace cryptonote +{ + + bool create_checkpoints(cryptonote::checkpoints& checkpoints); + + bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath); + bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet = false); + bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath); + +} // namespace cryptonote diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index c31be5acf..6f0fe88a4 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -42,7 +42,7 @@ using namespace epee; #include "cryptonote_format_utils.h" #include "misc_language.h" #include -#include "cryptonote_core/checkpoints.h" +#include "cryptonote_core/checkpoints_create.h" #include "blockchain_db/blockchain_db.h" #include "blockchain_db/lmdb/db_lmdb.h" #if defined(BERKELEY_DB) @@ -159,7 +159,7 @@ namespace cryptonote if (!m_testnet && !m_fakechain) { cryptonote::checkpoints checkpoints; - if (!checkpoints.init_default_checkpoints()) + if (!cryptonote::create_checkpoints(checkpoints)) { throw std::runtime_error("Failed to initialize checkpoints"); } @@ -415,7 +415,7 @@ namespace cryptonote CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints."); r = m_miner.init(vm, m_testnet); - CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance"); + CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); return load_state_data(); } @@ -634,6 +634,11 @@ namespace cryptonote return m_blockchain_storage.get_total_transactions(); } //----------------------------------------------------------------------------------------------- + //bool core::get_outs(uint64_t amount, std::list& pkeys) + //{ + // return m_blockchain_storage.get_outs(amount, pkeys); + //} + //----------------------------------------------------------------------------------------------- bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed) { if(m_mempool.have_tx(tx_hash)) @@ -765,6 +770,10 @@ namespace cryptonote { m_miner.on_synchronized(); } + //bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count) + //{ + // return m_blockchain_storage.get_backward_blocks_sizes(from_height, sizes, count); + //} //----------------------------------------------------------------------------------------------- bool core::add_new_block(const block& b, block_verification_context& bvc) { @@ -885,6 +894,10 @@ namespace cryptonote return m_blockchain_storage.get_block_by_hash(h, blk); } //----------------------------------------------------------------------------------------------- + //void core::get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) { + // m_blockchain_storage.get_all_known_block_ids(main, alt, invalid); + //} + //----------------------------------------------------------------------------------------------- std::string core::print_pool(bool short_format) const { return m_mempool.print_pool(short_format); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 30384209f..32f0b2ad4 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -63,739 +63,157 @@ namespace cryptonote /************************************************************************/ /* */ /************************************************************************/ - - /** - * @brief handles core cryptonote functionality - * - * This class coordinates cryptonote functionality including, but not - * limited to, communication among the Blockchain, the transaction pool, - * any miners, and the network. - */ class core: public i_miner_handler { public: - - /** - * @brief constructor - * - * sets member variables into a usable state - * - * @param pprotocol pre-constructed protocol object to store and use - */ core(i_cryptonote_protocol* pprotocol); - - /** - * @copydoc Blockchain::handle_get_objects - * - * @note see Blockchain::handle_get_objects() - * @param context connection context associated with the request - */ bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote_connection_context& context); - - /** - * @brief calls various idle routines - * - * @note see miner::on_idle and tx_memory_pool::on_idle - * - * @return true - */ bool on_idle(); - - /** - * @brief handles an incoming transaction - * - * Parses an incoming transaction and, if nothing is obviously wrong, - * passes it along to the transaction pool - * - * @param tx_blob the tx to handle - * @param tvc metadata about the transaction's validity - * @param keeped_by_block if the transaction has been in a block - * @param relayed whether or not the transaction was relayed to us - * - * @return true if the transaction made it to the transaction pool, otherwise false - */ bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed); - - /** - * @brief handles an incoming block - * - * periodic update to checkpoints is triggered here - * Attempts to add the block to the Blockchain and, on success, - * optionally updates the miner's block template. - * - * @param block_blob the block to be added - * @param bvc return-by-reference metadata context about the block's validity - * @param update_miner_blocktemplate whether or not to update the miner's block template - * - * @return false if loading new checkpoints fails, or the block is not - * added, otherwise true - */ bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true); - - /** - * @copydoc Blockchain::prepare_handle_incoming_blocks - * - * @note see Blockchain::prepare_handle_incoming_blocks - */ bool prepare_handle_incoming_blocks(const std::list &blocks); - - /** - * @copydoc Blockchain::cleanup_handle_incoming_blocks - * - * @note see Blockchain::cleanup_handle_incoming_blocks - */ bool cleanup_handle_incoming_blocks(bool force_sync = false); - - /** - * @brief check the size of a block against the current maximum - * - * @param block_blob the block to check - * - * @return whether or not the block is too big - */ - bool check_incoming_block_size(const blobdata& block_blob) const; - /** - * @brief get the cryptonote protocol instance - * - * @return the instance - */ + bool check_incoming_block_size(const blobdata& block_blob) const; i_cryptonote_protocol* get_protocol(){return m_pprotocol;} //-------------------- i_miner_handler ----------------------- - - /** - * @brief stores and relays a block found by a miner - * - * Updates the miner's target block, attempts to store the found - * block in Blockchain, and -- on success -- relays that block to - * the network. - * - * @param b the block found - * - * @return true if the block was added to the main chain, otherwise false - */ virtual bool handle_block_found( block& b); - - /** - * @copydoc Blockchain::create_block_template - * - * @note see Blockchain::create_block_template - */ virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce); - /** - * @brief gets the miner instance - * - * @return a reference to the miner instance - */ miner& get_miner(){return m_miner;} - - /** - * @brief gets the miner instance (const) - * - * @return a const reference to the miner instance - */ const miner& get_miner()const{return m_miner;} - - /** - * @brief adds command line options to the given options set - * - * As of now, there are no command line options specific to core, - * so this function simply returns. - * - * @param desc return-by-reference the command line options set to add to - */ static void init_options(boost::program_options::options_description& desc); - - /** - * @brief initializes the core as needed - * - * This function initializes the transaction pool, the Blockchain, and - * a miner instance with parameters given on the command line (or defaults) - * - * @param vm command line parameters - * @param test_options configuration options for testing - * - * @return false if one of the init steps fails, otherwise true - */ bool init(const boost::program_options::variables_map& vm, const test_options *test_options = NULL); - - /** - * @copydoc Blockchain::reset_and_set_genesis_block - * - * @note see Blockchain::reset_and_set_genesis_block - */ bool set_genesis_block(const block& b); - - /** - * @brief performs safe shutdown steps for core and core components - * - * Uninitializes the miner instance, transaction pool, and Blockchain - * - * if m_fast_exit is set, the call to Blockchain::deinit() is not made. - * - * @return true - */ bool deinit(); - - /** - * @brief sets fast exit flag - * - * @note see deinit() - */ static void set_fast_exit(); - - /** - * @brief gets the current state of the fast exit flag - * - * @return the fast exit flag - * - * @note see deinit() - */ static bool get_fast_exit(); - - /** - * @brief sets to drop blocks downloaded (for testing) - */ void test_drop_download(); - - /** - * @brief sets to drop blocks downloaded below a certain height - * - * @param height height below which to drop blocks - */ void test_drop_download_height(uint64_t height); - - /** - * @brief gets whether or not to drop blocks (for testing) - * - * @return whether or not to drop blocks - */ bool get_test_drop_download() const; - - /** - * @brief gets whether or not to drop blocks - * - * If the current blockchain height <= our block drop threshold - * and test drop blocks is set, return true - * - * @return see above - */ bool get_test_drop_download_height() const; - - /** - * @copydoc Blockchain::get_current_blockchain_height - * - * @note see Blockchain::get_current_blockchain_height() - */ uint64_t get_current_blockchain_height() const; - - /** - * @brief get the hash and height of the most recent block - * - * @param height return-by-reference height of the block - * @param top_id return-by-reference hash of the block - * - * @return true - */ - bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) const; - - /** - * @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list&, std::list&) const - * - * @note see Blockchain::get_blocks(uint64_t, size_t, std::list&, std::list&) const - */ + bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const; bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const; - - /** - * @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list&) const - * - * @note see Blockchain::get_blocks(uint64_t, size_t, std::list&) const - */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const; - - /** - * @copydoc Blockchain::get_blocks(const t_ids_container&, t_blocks_container&, t_missed_container&) const - * - * @note see Blockchain::get_blocks(const t_ids_container&, t_blocks_container&, t_missed_container&) const - */ template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const { return m_blockchain_storage.get_blocks(block_ids, blocks, missed_bs); } - - /** - * @copydoc Blockchain::get_block_id_by_height - * - * @note see Blockchain::get_block_id_by_height - */ crypto::hash get_block_id_by_height(uint64_t height) const; - - /** - * @copydoc Blockchain::get_transactions - * - * @note see Blockchain::get_transactions - */ bool get_transactions(const std::vector& txs_ids, std::list& txs, std::list& missed_txs) const; - - /** - * @copydoc Blockchain::get_block_by_hash - * - * @note see Blockchain::get_block_by_hash - */ bool get_block_by_hash(const crypto::hash &h, block &blk) const; + //void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid); - /** - * @copydoc Blockchain::get_alternative_blocks - * - * @note see Blockchain::get_alternative_blocks(std::list&) const - */ bool get_alternative_blocks(std::list& blocks) const; - - /** - * @copydoc Blockchain::get_alternative_blocks_count - * - * @note see Blockchain::get_alternative_blocks_count() const - */ size_t get_alternative_blocks_count() const; - /** - * @brief set the pointer to the cryptonote protocol object to use - * - * @param pprotocol the pointer to set ours as - */ void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol); - - /** - * @copydoc Blockchain::set_checkpoints - * - * @note see Blockchain::set_checkpoints() - */ void set_checkpoints(checkpoints&& chk_pts); - - /** - * @brief set the file path to read from when loading checkpoints - * - * @param path the path to set ours as - */ void set_checkpoints_file_path(const std::string& path); - - /** - * @brief set whether or not we enforce DNS checkpoints - * - * @param enforce_dns enforce DNS checkpoints or not - */ void set_enforce_dns_checkpoints(bool enforce_dns); - /** - * @copydoc tx_memory_pool::get_transactions - * - * @note see tx_memory_pool::get_transactions - */ bool get_pool_transactions(std::list& txs) const; - - /** - * @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info - * - * @note see tx_memory_pool::get_pool_transactions_and_spent_keys_info - */ bool get_pool_transactions_and_spent_keys_info(std::vector& tx_infos, std::vector& key_image_infos) const; - - /** - * @copydoc tx_memory_pool::get_transactions_count - * - * @note see tx_memory_pool::get_transactions_count - */ size_t get_pool_transactions_count() const; - - /** - * @copydoc Blockchain::get_total_transactions - * - * @note see Blockchain::get_total_transactions - */ size_t get_blockchain_total_transactions() const; - - /** - * @copydoc Blockchain::have_block - * - * @note see Blockchain::have_block - */ + //bool get_outs(uint64_t amount, std::list& pkeys); bool have_block(const crypto::hash& id) const; - - /** - * @copydoc Blockchain::get_short_chain_history - * - * @note see Blockchain::get_short_chain_history - */ bool get_short_chain_history(std::list& ids) const; - - /** - * @copydoc Blockchain::find_blockchain_supplement(const std::list&, NOTIFY_RESPONSE_CHAIN_ENTRY::request&) const - * - * @note see Blockchain::find_blockchain_supplement(const std::list&, NOTIFY_RESPONSE_CHAIN_ENTRY::request&) const - */ bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const; - - /** - * @copydoc Blockchain::find_blockchain_supplement(const uint64_t, const std::list&, std::list > >&, uint64_t&, uint64_t&, size_t) const - * - * @note see Blockchain::find_blockchain_supplement(const uint64_t, const std::list&, std::list > >&, uint64_t&, uint64_t&, size_t) const - */ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const; - - /** - * @brief gets some stats about the daemon - * - * @param st_inf return-by-reference container for the stats requested - * - * @return true - */ bool get_stat_info(core_stat_info& st_inf) const; - - /** - * @copydoc Blockchain::get_tx_outputs_gindexs - * - * @note see Blockchain::get_tx_outputs_gindexs - */ + //bool get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count); bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; - - /** - * @copydoc Blockchain::get_tail_id - * - * @note see Blockchain::get_tail_id - */ crypto::hash get_tail_id() const; - - /** - * @copydoc Blockchain::get_random_outs_for_amounts - * - * @note see Blockchain::get_random_outs_for_amounts - */ bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const; - - - /** - * @copydoc miner::pause - * - * @note see miner::pause - */ void pause_mine(); - - /** - * @copydoc miner::resume - * - * @note see miner::resume - */ void resume_mine(); - #if BLOCKCHAIN_DB == DB_LMDB - /** - * @brief gets the Blockchain instance - * - * @return a reference to the Blockchain instance - */ Blockchain& get_blockchain_storage(){return m_blockchain_storage;} - - /** - * @brief gets the Blockchain instance (const) - * - * @return a const reference to the Blockchain instance - */ const Blockchain& get_blockchain_storage()const{return m_blockchain_storage;} #else blockchain_storage& get_blockchain_storage(){return m_blockchain_storage;} const blockchain_storage& get_blockchain_storage()const{return m_blockchain_storage;} #endif - - /** - * @copydoc Blockchain::print_blockchain - * - * @note see Blockchain::print_blockchain - */ + //debug functions void print_blockchain(uint64_t start_index, uint64_t end_index) const; - - /** - * @copydoc Blockchain::print_blockchain_index - * - * @note see Blockchain::print_blockchain_index - */ void print_blockchain_index() const; - - /** - * @copydoc tx_memory_pool::print_pool - * - * @note see tx_memory_pool::print_pool - */ std::string print_pool(bool short_format) const; - - /** - * @copydoc Blockchain::print_blockchain_outs - * - * @note see Blockchain::print_blockchain_outs - */ void print_blockchain_outs(const std::string& file); - - /** - * @copydoc miner::on_synchronized - * - * @note see miner::on_synchronized - */ void on_synchronized(); - /** - * @brief sets the target blockchain height - * - * @param target_blockchain_height the height to set - */ void set_target_blockchain_height(uint64_t target_blockchain_height); - - /** - * @brief gets the target blockchain height - * - * @param target_blockchain_height the target height - */ uint64_t get_target_blockchain_height() const; - /** - * @brief tells the Blockchain to update its checkpoints - * - * This function will check if enough time has passed since the last - * time checkpoints were updated and tell the Blockchain to update - * its checkpoints if it is time. If updating checkpoints fails, - * the daemon is told to shut down. - * - * @note see Blockchain::update_checkpoints() - */ bool update_checkpoints(); - /** - * @brief tells the daemon to wind down operations and stop running - * - * Currently this function raises SIGTERM, allowing the installed signal - * handlers to do the actual stopping. - */ - void graceful_exit(); - - /** - * @brief stops the daemon running - * - * @note see graceful_exit() - */ void stop(); - /** - * @copydoc Blockchain::have_tx_keyimg_as_spent - * - * @note see Blockchain::have_tx_keyimg_as_spent - */ bool is_key_image_spent(const crypto::key_image& key_im) const; - - /** - * @brief check if multiple key images are spent - * - * plural version of is_key_image_spent() - * - * @param key_im list of key images to check - * @param spent return-by-reference result for each image checked - * - * @return true - */ bool are_key_images_spent(const std::vector& key_im, std::vector &spent) const; private: - - /** - * @copydoc add_new_tx(const transaction&, tx_verification_context&, bool) - * - * @param tx_hash the transaction's hash - * @param tx_prefix_hash the transaction prefix' hash - * @param blob_size the size of the transaction - * @param relayed whether or not the transaction was relayed to us - * - */ bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed); - - /** - * @brief add a new transaction to the transaction pool - * - * Adds a new transaction to the transaction pool. - * - * @param tx the transaction to add - * @param tvc return-by-reference metadata about the transaction's verification process - * @param keeped_by_block whether or not the transaction has been in a block - * @param relayed whether or not the transaction was relayed to us - * - * @return true if the transaction is already in the transaction pool, - * is already in a block on the Blockchain, or is successfully added - * to the transaction pool - */ bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed); - - /** - * @copydoc Blockchain::add_new_block - * - * @note see Blockchain::add_new_block - */ bool add_new_block(const block& b, block_verification_context& bvc); - - /** - * @brief load any core state stored on disk - * - * currently does nothing, but may have state to load in the future. - * - * @return true - */ bool load_state_data(); - - /** - * @copydoc parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const - * - * @note see parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const - */ bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob) const; - /** - * @brief check a transaction's syntax - * - * For now this does nothing, but it may check something about the tx - * in the future. - * - * @param tx the transaction to check - * - * @return true - */ bool check_tx_syntax(const transaction& tx) const; - - /** - * @brief validates some simple properties of a transaction - * - * Currently checks: tx has inputs, - * tx inputs all of supported type(s), - * tx outputs valid (type, key, amount), - * input and output total amounts don't overflow, - * output amount <= input amount, - * tx not too large, - * each input has a different key image. - * - * @param tx the transaction to check - * @param keeped_by_block if the transaction has been in a block - * - * @return true if all the checks pass, otherwise false - */ + //check correct values, amounts and all lightweight checks not related with database bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const; + //check if tx already in memory pool or in main blockchain - /** - * @copydoc miner::on_block_chain_update - * - * @note see miner::on_block_chain_update - * - * @return true - */ + bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector& sig) const; + bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; bool update_miner_block_template(); - - /** - * @brief act on a set of command line options given - * - * @param vm the command line options - * - * @return true - */ bool handle_command_line(const boost::program_options::variables_map& vm); - - /** - * @brief verify that each input key image in a transaction is unique - * - * @param tx the transaction to check - * - * @return false if any key image is repeated, otherwise true - */ + bool on_update_blocktemplate_interval(); bool check_tx_inputs_keyimages_diff(const transaction& tx) const; - - /** - * @brief checks HardFork status and prints messages about it - * - * Checks the status of HardFork and logs/prints if an update to - * the daemon is necessary. - * - * @note see Blockchain::get_hard_fork_state and HardFork::State - * - * @return true - */ + void graceful_exit(); bool check_fork_time(); - - /** - * @brief attempts to relay any transactions in the mempool which need it - * - * @return true - */ bool relay_txpool_transactions(); - - /** - * @brief locks a file in the BlockchainDB directory - * - * @param path the directory in which to place the file - * - * @return true if lock acquired successfully, otherwise false - */ bool lock_db_directory(const boost::filesystem::path &path); - - /** - * @brief unlocks the db directory - * - * @note see lock_db_directory() - * - * @return true - */ bool unlock_db_directory(); - static std::atomic m_fast_exit; //!< whether or not to deinit Blockchain on exit - - bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing) + static std::atomic m_fast_exit; + bool m_test_drop_download = true; + uint64_t m_test_drop_download_height = 0; - uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so - - tx_memory_pool m_mempool; //!< transaction pool instance + tx_memory_pool m_mempool; #if BLOCKCHAIN_DB == DB_LMDB - Blockchain m_blockchain_storage; //!< Blockchain instance + Blockchain m_blockchain_storage; #else blockchain_storage m_blockchain_storage; #endif - - i_cryptonote_protocol* m_pprotocol; //!< cryptonote protocol instance - - epee::critical_section m_incoming_tx_lock; //!< incoming transaction lock - + i_cryptonote_protocol* m_pprotocol; + epee::critical_section m_incoming_tx_lock; //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 - - cryptonote_protocol_stub m_protocol_stub; //!< cryptonote protocol stub instance - - epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled - epee::math_helper::once_a_time_seconds<60*60*2, false> m_fork_moaner; //!< interval for checking HardFork status + miner m_miner; + account_public_address m_miner_address; + std::string m_config_folder; + cryptonote_protocol_stub m_protocol_stub; + epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; + epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions - friend class tx_validate_inputs; - std::atomic m_starter_message_showed; //!< has the "daemon will sync now" message been shown? - - uint64_t m_target_blockchain_height; //!< blockchain height target - - bool m_testnet; //!< are we on testnet? + std::atomic m_starter_message_showed; - bool m_fakechain; //!< are we using a fake chain (for testing purposes)? + uint64_t m_target_blockchain_height; - std::string m_checkpoints_path; //!< path to json checkpoints file - time_t m_last_dns_checkpoints_update; //!< time when dns checkpoints were last updated - time_t m_last_json_checkpoints_update; //!< time when json checkpoints were last updated + bool m_testnet; + bool m_fakechain; + std::string m_checkpoints_path; + time_t m_last_dns_checkpoints_update; + time_t m_last_json_checkpoints_update; - std::atomic_flag m_checkpoints_updating; //!< set if checkpoints are currently updating to avoid multiple threads attempting to update at once + std::atomic_flag m_checkpoints_updating; - boost::interprocess::file_lock db_lock; //!< a lock object for a file lock in the db directory + boost::interprocess::file_lock db_lock; }; } diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp index 54da77392..236e84481 100644 --- a/src/cryptonote_core/difficulty.cpp +++ b/src/cryptonote_core/difficulty.cpp @@ -116,8 +116,8 @@ namespace cryptonote { return !carry; } - difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { - + difficulty_type next_difficulty(vector timestamps, vector cumulative_difficulties, size_t target_seconds) { + //cutoff DIFFICULTY_LAG if(timestamps.size() > DIFFICULTY_WINDOW) { timestamps.resize(DIFFICULTY_WINDOW); @@ -151,8 +151,6 @@ namespace cryptonote { assert(total_work > 0); uint64_t low, high; mul(total_work, target_seconds, low, high); - // blockchain errors "difficulty overhead" if this function returns zero. - // TODO: consider throwing an exception instead if (high != 0 || low + time_span - 1 < low) { return 0; } diff --git a/src/cryptonote_core/difficulty.h b/src/cryptonote_core/difficulty.h index 910f97035..d49c2f3b8 100644 --- a/src/cryptonote_core/difficulty.h +++ b/src/cryptonote_core/difficulty.h @@ -39,18 +39,6 @@ namespace cryptonote { typedef std::uint64_t difficulty_type; - /** - * @brief checks if a hash fits the given difficulty - * - * The hash passes if (hash * difficulty) < 2^192. - * Phrased differently, if (hash * difficulty) fits without overflow into - * the least significant 192 bits of the 256 bit multiplication result. - * - * @param hash the hash to check - * @param difficulty the difficulty to check against - * - * @return true if valid, else false - */ bool check_hash(const crypto::hash &hash, difficulty_type difficulty); difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); } diff --git a/src/daemon/core.h b/src/daemon/core.h index 2b7f0d177..2208ef25a 100644 --- a/src/daemon/core.h +++ b/src/daemon/core.h @@ -28,6 +28,7 @@ #pragma once +#include "cryptonote_core/checkpoints_create.h" #include "cryptonote_core/cryptonote_core.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "misc_log_ex.h" -- cgit v1.2.3 From 0d30b657859d6ebd3188bd16dfaa9c79c3dfcaa7 Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Fri, 25 Mar 2016 08:22:06 +0200 Subject: Merge pull request #749 bfd4a28 Update BlockchainDB documentation (Thomas Winget) 797357e Change Doxyfile, Blockchain not blockchain_storage (Thomas Winget) c835215 remove defunct code from cryptonote::core (Thomas Winget) 50dba6d cryptonote::core doxygen documentation (Thomas Winget) 8ac329d doxygen documentation for difficulty functions (Thomas Winget) 540a76c Move checkpoint functions into checkpoints class (Thomas Winget) 1b0c98e doxygen documentation for checkpoints.{h,cpp} (Thomas Winget) 89c24ac Remove unnecessary or defunct code (Thomas Winget) ab0ed14 doxygen include private and static members (Thomas Winget) 3a48449 Updated documentation for blockchain.* (Thomas Winget) --- Doxyfile | 14 +- src/blockchain_db/blockchain_db.h | 1092 ++++++++++++++++++++++++---- src/cryptonote_core/CMakeLists.txt | 2 - src/cryptonote_core/blockchain.cpp | 49 +- src/cryptonote_core/blockchain.h | 890 ++++++++++++++++++++++- src/cryptonote_core/blockchain_storage.cpp | 8 +- src/cryptonote_core/checkpoints.cpp | 251 ++++++- src/cryptonote_core/checkpoints.h | 181 ++++- src/cryptonote_core/checkpoints_create.cpp | 280 ------- src/cryptonote_core/checkpoints_create.h | 48 -- src/cryptonote_core/cryptonote_core.cpp | 19 +- src/cryptonote_core/cryptonote_core.h | 650 ++++++++++++++++- src/cryptonote_core/difficulty.cpp | 6 +- src/cryptonote_core/difficulty.h | 12 + src/daemon/core.h | 1 - 15 files changed, 2909 insertions(+), 594 deletions(-) delete mode 100644 src/cryptonote_core/checkpoints_create.cpp delete mode 100644 src/cryptonote_core/checkpoints_create.h (limited to 'src') diff --git a/Doxyfile b/Doxyfile index a70ef812b..93a5c6e76 100644 --- a/Doxyfile +++ b/Doxyfile @@ -409,13 +409,13 @@ LOOKUP_CACHE_SIZE = 0 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = NO +EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. -EXTRACT_PRIVATE = NO +EXTRACT_PRIVATE = YES # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. @@ -427,7 +427,7 @@ EXTRACT_PACKAGE = NO # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO @@ -452,7 +452,7 @@ EXTRACT_LOCAL_METHODS = NO # are hidden. # The default value is: NO. -EXTRACT_ANON_NSPACES = NO +EXTRACT_ANON_NSPACES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these @@ -1902,7 +1902,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -1910,7 +1910,7 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES the includes files in the # INCLUDE_PATH will be searched if a #include is found. @@ -1942,7 +1942,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = "BLOCKCHAIN_DB=2" \ # DB_LMDB # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 3396b8c20..3e0ca141e 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -38,18 +38,20 @@ #include "cryptonote_core/difficulty.h" #include "cryptonote_core/hardfork.h" -/* DB Driver Interface +/** \file + * Cryptonote Blockchain Database Interface * * The DB interface is a store for the canonical block chain. * It serves as a persistent storage for the blockchain. * - * For the sake of efficiency, the reference implementation will also + * For the sake of efficiency, a concrete implementation may also * store some blockchain data outside of the blocks, such as spent * transfer key images, unspent transaction outputs, etc. * + * Examples are as follows: + * * Transactions are duplicated so that we don't have to fetch a whole block - * in order to fetch a transaction from that block. If this is deemed - * unnecessary later, this can change. + * in order to fetch a transaction from that block. * * Spent key images are duplicated outside of the blocks so it is quick * to verify an output hasn't already been spent @@ -57,100 +59,34 @@ * Unspent transaction outputs are duplicated to quickly gather random * outputs to use for mixins * - * IMPORTANT: - * A concrete implementation of this interface should populate these - * duplicated members! It is possible to have a partial implementation - * of this interface call to private members of the interface to be added - * later that will then populate as needed. - * - * General: - * open() - * is_open() - * close() - * sync() - * reset() - * - * Lock and unlock provided for reorg externally, and for block - * additions internally, this way threaded reads are completely fine - * unless the blockchain is changing. - * bool lock() - * unlock() - * - * vector get_filenames() - * - * Blocks: - * bool block_exists(hash) - * height add_block(block, block_size, cumulative_difficulty, coins_generated, transactions) - * block get_block(hash) - * height get_block_height(hash) - * header get_block_header(hash) - * block get_block_from_height(height) - * size_t get_block_size(height) - * difficulty get_block_cumulative_difficulty(height) - * uint64_t get_block_already_generated_coins(height) - * uint64_t get_block_timestamp(height) - * uint64_t get_top_block_timestamp() - * hash get_block_hash_from_height(height) - * blocks get_blocks_range(height1, height2) - * hashes get_hashes_range(height1, height2) - * hash top_block_hash() - * block get_top_block() - * height height() - * void pop_block(block&, tx_list&) - * - * Transactions: - * bool tx_exists(hash) - * uint64_t get_tx_unlock_time(hash) - * tx get_tx(hash) - * uint64_t get_tx_count() - * tx_list get_tx_list(hash_list) - * height get_tx_block_height(hash) - * - * Outputs: - * uint64_t get_num_outputs(amount) - * pub_key get_output_key(amount, index) - * hash,index get_output_tx_and_index_from_global(index) - * hash,index get_output_tx_and_index(amount, index) - * vec get_tx_output_indices(tx_hash) - * - * - * Spent Output Key Images: - * bool has_key_image(key_image) - * - * Exceptions: - * DB_ERROR -- generic - * DB_OPEN_FAILURE - * DB_CREATE_FAILURE - * DB_SYNC_FAILURE - * BLOCK_DNE - * BLOCK_PARENT_DNE - * BLOCK_EXISTS - * BLOCK_INVALID -- considering making this multiple errors - * TX_DNE - * TX_EXISTS - * OUTPUT_DNE - * OUTPUT_EXISTS - * KEY_IMAGE_EXISTS */ namespace cryptonote { -// typedef for convenience +/** a pair of , typedef for convenience */ typedef std::pair tx_out_index; #pragma pack(push, 1) + +/** + * @brief a struct containing output metadata + */ struct output_data_t { - crypto::public_key pubkey; - uint64_t unlock_time; - uint64_t height; + crypto::public_key pubkey; //!< the output's public key (for spend verification) + uint64_t unlock_time; //!< the output's unlock time (or height) + uint64_t height; //!< the height of the block which created the output }; #pragma pack(pop) /*********************************** * Exception Definitions ***********************************/ + +/** + * @brief A base class for BlockchainDB exceptions + */ class DB_EXCEPTION : public std::exception { private: @@ -168,6 +104,9 @@ class DB_EXCEPTION : public std::exception } }; +/** + * @brief A generic BlockchainDB exception + */ class DB_ERROR : public DB_EXCEPTION { public: @@ -175,7 +114,9 @@ class DB_ERROR : public DB_EXCEPTION DB_ERROR(const char* s) : DB_EXCEPTION(s) { } }; -// For distinguishing errors trying to set up a DB txn from other errors +/** + * @brief thrown when there is an error starting a DB transaction + */ class DB_ERROR_TXN_START : public DB_EXCEPTION { public: @@ -183,6 +124,9 @@ class DB_ERROR_TXN_START : public DB_EXCEPTION DB_ERROR_TXN_START(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when opening the BlockchainDB fails + */ class DB_OPEN_FAILURE : public DB_EXCEPTION { public: @@ -190,6 +134,9 @@ class DB_OPEN_FAILURE : public DB_EXCEPTION DB_OPEN_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when creating the BlockchainDB fails + */ class DB_CREATE_FAILURE : public DB_EXCEPTION { public: @@ -197,6 +144,9 @@ class DB_CREATE_FAILURE : public DB_EXCEPTION DB_CREATE_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when synchronizing the BlockchainDB to disk fails + */ class DB_SYNC_FAILURE : public DB_EXCEPTION { public: @@ -204,6 +154,9 @@ class DB_SYNC_FAILURE : public DB_EXCEPTION DB_SYNC_FAILURE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a requested block does not exist + */ class BLOCK_DNE : public DB_EXCEPTION { public: @@ -211,6 +164,9 @@ class BLOCK_DNE : public DB_EXCEPTION BLOCK_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a block's parent does not exist (and it needed to) + */ class BLOCK_PARENT_DNE : public DB_EXCEPTION { public: @@ -218,6 +174,9 @@ class BLOCK_PARENT_DNE : public DB_EXCEPTION BLOCK_PARENT_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a block exists, but shouldn't, namely when adding a block + */ class BLOCK_EXISTS : public DB_EXCEPTION { public: @@ -225,6 +184,9 @@ class BLOCK_EXISTS : public DB_EXCEPTION BLOCK_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when something is wrong with the block to be added + */ class BLOCK_INVALID : public DB_EXCEPTION { public: @@ -232,6 +194,9 @@ class BLOCK_INVALID : public DB_EXCEPTION BLOCK_INVALID(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a requested transaction does not exist + */ class TX_DNE : public DB_EXCEPTION { public: @@ -239,6 +204,9 @@ class TX_DNE : public DB_EXCEPTION TX_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a transaction exists, but shouldn't, namely when adding a block + */ class TX_EXISTS : public DB_EXCEPTION { public: @@ -246,6 +214,9 @@ class TX_EXISTS : public DB_EXCEPTION TX_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a requested output does not exist + */ class OUTPUT_DNE : public DB_EXCEPTION { public: @@ -253,6 +224,9 @@ class OUTPUT_DNE : public DB_EXCEPTION OUTPUT_DNE(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when an output exists, but shouldn't, namely when adding a block + */ class OUTPUT_EXISTS : public DB_EXCEPTION { public: @@ -260,6 +234,9 @@ class OUTPUT_EXISTS : public DB_EXCEPTION OUTPUT_EXISTS(const char* s) : DB_EXCEPTION(s) { } }; +/** + * @brief thrown when a spent key image exists, but shouldn't, namely when adding a block + */ class KEY_IMAGE_EXISTS : public DB_EXCEPTION { public: @@ -272,6 +249,18 @@ class KEY_IMAGE_EXISTS : public DB_EXCEPTION ***********************************/ +/** + * @brief The BlockchainDB backing store interface declaration/contract + * + * This class provides a uniform interface for using BlockchainDB to store + * a blockchain. Any implementation of this class will also implement all + * functions exposed here, so one can use this class without knowing what + * implementation is being used. Refer to each pure virtual function's + * documentation here when implementing a BlockchainDB subclass. + * + * A subclass which encounters an issue should report that issue by throwing + * a DB_EXCEPTION which adequately conveys the issue. + */ class BlockchainDB { private: @@ -279,7 +268,22 @@ private: * private virtual members *********************************************************************/ - // tells the subclass to add the block and metadata to storage + /** + * @brief add the block and metadata to the db + * + * The subclass implementing this will add the specified block and + * block metadata to its backing store. This does not include its + * transactions, those are added in a separate step. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk the block to be added + * @param block_size the size of the block (transactions and all) + * @param cumulative_difficulty the accumulated difficulty after this block + * @param coins_generated the number of coins generated total after this block + * @param blk_hash the hash of the block + */ virtual void add_block( const block& blk , const size_t& block_size , const difficulty_type& cumulative_difficulty @@ -287,84 +291,274 @@ private: , const crypto::hash& blk_hash ) = 0; - // tells the subclass to remove data about the top block + /** + * @brief remove data about the top block + * + * The subclass implementing this will remove the block data from the top + * block in the chain. The data to be removed is that which was added in + * BlockchainDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash) + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void remove_block() = 0; - // tells the subclass to store the transaction and its metadata + /** + * @brief store the transaction and its metadata + * + * The subclass implementing this will add the specified transaction data + * to its backing store. This includes only the transaction blob itself + * and the other data passed here, not the separate outputs of the + * transaction. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk_hash the hash of the block containing the transaction + * @param tx the transaction to be added + * @param tx_hash the hash of the transaction + */ virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0; - // tells the subclass to remove data about a transaction + /** + * @brief remove data about a transaction + * + * The subclass implementing this will remove the transaction data + * for the passed transaction. The data to be removed was added in + * add_transaction_data(). Additionally, current subclasses have behavior + * which requires the transaction itself as a parameter here. Future + * implementations should note that this parameter is subject to be removed + * at a later time. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_hash the hash of the transaction to be removed + * @param tx the transaction + */ virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0; - // tells the subclass to store an output + /** + * @brief store an output + * + * The subclass implementing this will add the output data passed to its + * backing store in a suitable manner. In addition, the subclass is responsible + * for keeping track of the global output count in some manner, so that + * outputs may be indexed by the order in which they were created. In the + * future, this tracking (of the number, at least) should be moved to + * this class, as it is necessary and the same among all BlockchainDB. + * + * This data should be stored in such a manner that the only thing needed to + * reverse the process is the tx_out. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_hash hash of the transaction the output was created by + * @param tx_output the output + * @param local_index index of the output in its transaction + * @param unlock_time unlock time/height of the output + */ virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) = 0; - // tells the subclass to remove an output + /** + * @brief remove an output + * + * The subclass implementing this will remove all output data it stored + * in add_output(). + * + * In addition, the subclass is responsible for correctly decrementing + * its global output counter (this may be automatic for some, such as using + * a database backend "count" feature). + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_output the output to be removed + */ virtual void remove_output(const tx_out& tx_output) = 0; - // tells the subclass to store a spent key + /** + * @brief store a spent key + * + * The subclass implementing this will store the spent key image. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param k_image the spent key image to store + */ virtual void add_spent_key(const crypto::key_image& k_image) = 0; - // tells the subclass to remove a spent key + /** + * @brief remove a spent key + * + * The subclass implementing this will remove the key image. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param k_image the spent key image to remove + */ virtual void remove_spent_key(const crypto::key_image& k_image) = 0; /********************************************************************* * private concrete members *********************************************************************/ - // private version of pop_block, for undoing if an add_block goes tits up + /** + * @brief private version of pop_block, for undoing if an add_block fails + * + * This function simply calls pop_block(block& blk, std::vector& txs) + * with dummy parameters, as the returns-by-reference can be discarded. + */ void pop_block(); - // helper function for add_transactions, to add each individual tx + /** + * @brief helper function for add_transactions, to add each individual transaction + * + * This function is called by add_transactions() for each transaction to be + * added. + * + * @param blk_hash hash of the block which has the transaction + * @param tx the transaction to add + * @param tx_hash_ptr the hash of the transaction, if already calculated + */ void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL); // helper function to remove transaction from blockchain + /** + * @brief helper function to remove transaction from the blockchain + * + * This function encapsulates aspects of removing a transaction. + * + * @param tx_hash the hash of the transaction to be removed + */ void remove_transaction(const crypto::hash& tx_hash); - uint64_t num_calls = 0; - uint64_t time_blk_hash = 0; - uint64_t time_add_block1 = 0; - uint64_t time_add_transaction = 0; + uint64_t num_calls = 0; //!< a performance metric + uint64_t time_blk_hash = 0; //!< a performance metric + uint64_t time_add_block1 = 0; //!< a performance metric + uint64_t time_add_transaction = 0; //!< a performance metric protected: - mutable uint64_t time_tx_exists = 0; - uint64_t time_commit1 = 0; - bool m_auto_remove_logs = true; + mutable uint64_t time_tx_exists = 0; //!< a performance metric + uint64_t time_commit1 = 0; //!< a performance metric + bool m_auto_remove_logs = true; //!< whether or not to automatically remove old logs HardFork* m_hardfork; public: - // virtual dtor + /** + * @brief An empty destructor. + */ virtual ~BlockchainDB() { }; - // reset profiling stats + /** + * @brief reset profiling stats + */ void reset_stats(); - // show profiling stats + /** + * @brief show profiling stats + * + * This function prints current performance/profiling data to whichever + * log file(s) are set up (possibly including stdout or stderr) + */ void show_stats(); - // open the db at location , or create it if there isn't one. + /** + * @brief open a db, or create it if necessary. + * + * This function opens an existing database or creates it if it + * does not exist. + * + * The subclass implementing this will handle all file opening/creation, + * and is responsible for maintaining its state. + * + * The parameter may not refer to a file name, necessarily, but + * could be an IP:PORT for a database which needs it, and so on. Calling it + * is convenient and should be descriptive enough, however. + * + * For now, db_flags are + * specific to the subclass being instantiated. This is subject to change, + * and the db_flags parameter may be deprecated. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param filename a string referring to the BlockchainDB to open + * @param db_flags flags relevant to how to open/use the BlockchainDB + */ virtual void open(const std::string& filename, const int db_flags = 0) = 0; - // returns true of the db is open/ready, else false + /** + * @brief Gets the current open/ready state of the BlockchainDB + * + * @return true if open/ready, otherwise false + */ bool is_open() const; - // close and sync the db + /** + * @brief close the BlockchainDB + * + * At minimum, this call ensures that further use of the BlockchainDB + * instance will not have effect. In any case where it is necessary + * to do so, a subclass implementing this will sync with disk. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void close() = 0; - // sync the db + /** + * @brief sync the BlockchainDB with disk + * + * This function should write any changes to whatever permanent backing + * store the subclass uses. Example: a BlockchainDB instance which + * keeps the whole blockchain in RAM won't need to regularly access a + * disk, but should write out its state when this is called. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void sync() = 0; - // reset the db -- USE WITH CARE + /** + * @brief Remove everything from the BlockchainDB + * + * This function should completely remove all data from a BlockchainDB. + * + * Use with caution! + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void reset() = 0; - // get all files used by this db (if any) + /** + * @brief get all files used by the BlockchainDB (if any) + * + * This function is largely for ease of automation, namely for unit tests. + * + * The subclass implementation should return all filenames it uses. + * + * @return a list of filenames + */ virtual std::vector get_filenames() const = 0; // return the name of the folder the db's file(s) should reside in + /** + * @brief gets the name of the folder the BlockchainDB's file(s) should be in + * + * The subclass implementation should return the name of the folder in which + * it stores files, or an empty string if there is none. + * + * @return the name of the folder with the BlockchainDB's files, if any. + */ virtual std::string get_db_name() const = 0; @@ -372,13 +566,86 @@ public: // RAII-friendly and multi-read one-write friendly locking mechanism // // acquire db lock + /** + * @brief acquires the BlockchainDB lock + * + * This function is a stub until such a time as locking is implemented at + * this level. + * + * The subclass implementation should return true unless implementing a + * locking scheme of some sort, in which case it should return true upon + * acquisition of the lock and block until then. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @return true, unless at a future time false makes sense (timeout, etc) + */ virtual bool lock() = 0; // release db lock + /** + * @brief This function releases the BlockchainDB lock + * + * The subclass, should it have implemented lock(), will release any lock + * held by the calling thread. In the case of recursive locking, it should + * release one instance of a lock. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ virtual void unlock() = 0; + /** + * @brief tells the BlockchainDB to start a new "batch" of blocks + * + * If the subclass implements a batching method of caching blocks in RAM to + * be added to a backing store in groups, it should start a batch which will + * end either when has been added or batch_stop() has + * been called. In either case, it should end the batch and write to its + * backing store. + * + * If a batch is already in-progress, this function should throw a DB_ERROR. + * This exception may change in the future if it is deemed necessary to + * have a more granular exception type for this scenario. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param batch_num_blocks number of blocks to batch together + */ virtual void batch_start(uint64_t batch_num_blocks=0) = 0; + + /** + * @brief ends a batch transaction + * + * If the subclass implements batching, this function should store the + * batch it is currently on and mark it finished. + * + * 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_stop() = 0; + + /** + * @brief sets whether or not to batch transactions + * + * If the subclass implements batching, this function tells it to begin + * batching automatically. + * + * If the subclass implements batching and has a batch in-progress, a + * parameter of false should disable batching and call batch_stop() to + * store the current batch. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param bool batch whether or not to use batch transactions. + */ virtual void set_batch_transactions(bool) = 0; virtual void block_txn_start(bool readonly=false) = 0; @@ -388,8 +655,26 @@ public: virtual void set_hard_fork(HardFork* hf); // adds a block with the given metadata to the top of the blockchain, returns the new height - // NOTE: subclass implementations of this (or the functions it calls) need - // to handle undoing any partially-added blocks in the event of a failure. + /** + * @brief handles the addition of a new block to BlockchainDB + * + * This function organizes block addition and calls various functions as + * necessary. + * + * NOTE: subclass implementations of this (or the functions it calls) need + * to handle undoing any partially-added blocks in the event of a failure. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk the block to be added + * @param block_size the size of the block (transactions and all) + * @param cumulative_difficulty the accumulated difficulty after this block + * @param coins_generated the number of coins generated total after this block + * @param txs the transactions in the block + * + * @return the height of the chain post-addition + */ virtual uint64_t add_block( const block& blk , const size_t& block_size , const difficulty_type& cumulative_difficulty @@ -397,142 +682,639 @@ public: , const std::vector& txs ); - // return true if a block with hash exists in the blockchain + /** + * @brief checks if a block exists + * + * @param h the hash of the requested block + * + * @return true of the block exists, otherwise false + */ virtual bool block_exists(const crypto::hash& h) const = 0; - // return block with hash + /** + * @brief fetches the block with the given hash + * + * The subclass should return the requested block. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the block requested + */ virtual block get_block(const crypto::hash& h) const = 0; - // return the height of the block with hash on the blockchain, - // throw if it doesn't exist + /** + * @brief gets the height of the block with a given hash + * + * The subclass should return the requested height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the height + */ virtual uint64_t get_block_height(const crypto::hash& h) const = 0; - // return header for block with hash + /** + * @brief fetch a block header + * + * The subclass should return the block header from the block with + * the given hash. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the block header + */ virtual block_header get_block_header(const crypto::hash& h) const = 0; - // return block at height + /** + * @brief fetch a block by height + * + * The subclass should return the block at the given height. + * + * If the block does not exist, that is to say if the blockchain is not + * that high, then the subclass should throw BLOCK_DNE + * + * @param height the height to look for + * + * @return the block + */ virtual block get_block_from_height(const uint64_t& height) const = 0; - // return timestamp of block at height + /** + * @brief fetch a block's timestamp + * + * The subclass should return the timestamp of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the timestamp + */ virtual uint64_t get_block_timestamp(const uint64_t& height) const = 0; - // return timestamp of most recent block + /** + * @brief fetch the top block's timestamp + * + * The subclass should return the timestamp of the most recent block. + * + * @return the top block's timestamp + */ virtual uint64_t get_top_block_timestamp() const = 0; - // return block size of block at height + /** + * @brief fetch a block's size + * + * The subclass should return the size of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the size + */ virtual size_t get_block_size(const uint64_t& height) const = 0; - // return cumulative difficulty up to and including block at height + /** + * @brief fetch a block's cumulative difficulty + * + * The subclass should return the cumulative difficulty of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the cumulative difficulty + */ virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const = 0; - // return difficulty of block at height + /** + * @brief fetch a block's difficulty + * + * The subclass should return the difficulty of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the difficulty + */ virtual difficulty_type get_block_difficulty(const uint64_t& height) const = 0; - // return number of coins generated up to and including block at height + /** + * @brief fetch a block's already generated coins + * + * The subclass should return the total coins generated as of the block + * with the given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the already generated coins + */ virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const = 0; - // return hash of block at height + /** + * @brief fetch a block's hash + * + * The subclass should return hash of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the hash + */ virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const = 0; - // return vector of blocks in range of height (inclusively) + /** + * @brief fetch a list of blocks + * + * The subclass should return a vector of blocks with heights starting at + * h1 and ending at h2, inclusively. + * + * If the height range requested goes past the end of the blockchain, + * the subclass should throw BLOCK_DNE. (current implementations simply + * don't catch this exception as thrown by methods called within) + * + * @param h1 the start height + * @param h2 the end height + * + * @return a vector of blocks + */ virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const = 0; - // return vector of block hashes in range of height (inclusively) + /** + * @brief fetch a list of block hashes + * + * The subclass should return a vector of block hashes from blocks with + * heights starting at h1 and ending at h2, inclusively. + * + * If the height range requested goes past the end of the blockchain, + * the subclass should throw BLOCK_DNE. (current implementations simply + * don't catch this exception as thrown by methods called within) + * + * @param h1 the start height + * @param h2 the end height + * + * @return a vector of block hashes + */ virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const = 0; - // return the hash of the top block on the chain + /** + * @brief fetch the top block's hash + * + * The subclass should return the hash of the most recent block + * + * @return the top block's hash + */ virtual crypto::hash top_block_hash() const = 0; - // return the block at the top of the blockchain + /** + * @brief fetch the top block + * + * The subclass should return most recent block + * + * @return the top block + */ virtual block get_top_block() const = 0; - // return the height of the chain + /** + * @brief fetch the current blockchain height + * + * The subclass should return the current blockchain height + * + * @return the current blockchain height + */ virtual uint64_t height() const = 0; - // pops the top block off the blockchain. - // Returns by reference the popped block and its associated transactions - // - // IMPORTANT: - // When a block is popped, the transactions associated with it need to be - // removed, as well as outputs and spent key images associated with - // those transactions. + + /** + * + * + * @brief pops the top block off the blockchain + * + * The subclass should remove the most recent block from the blockchain, + * along with all transactions, outputs, and other metadata created as + * a result of its addition to the blockchain. Most of this is handled + * by the concrete members of the base class provided the subclass correctly + * implements remove_* functions. + * + * The subclass should return by reference the popped block and + * its associated transactions + * + * @param blk return-by-reference the block which was popped + * @param txs return-by-reference the transactions from the popped block + */ virtual void pop_block(block& blk, std::vector& txs); - // return true if a transaction with hash exists + /** + * @brief check if a transaction with a given hash exists + * + * The subclass should check if a transaction is stored which has the + * given hash and return true if so, false otherwise. + * + * @param h the hash to check against + * + * @return true if the transaction exists, otherwise false + */ virtual bool tx_exists(const crypto::hash& h) const = 0; // return unlock time of tx with hash + /** + * @brief fetch a transaction's unlock time/height + * + * The subclass should return the stored unlock time for the transaction + * with the given hash. + * + * If no such transaction exists, the subclass should throw TX_DNE. + * + * @param h the hash of the requested transaction + * + * @return the unlock time/height + */ virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const = 0; // return tx with hash // throw if no such tx exists + /** + * @brief fetches the transaction with the given hash + * + * The subclass should return the transaction stored which has the given + * hash. + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * @param h the hash to look for + * + * @return the transaction with the given hash + */ virtual transaction get_tx(const crypto::hash& h) const = 0; - // returns the total number of transactions in all blocks + /** + * @brief fetches the total number of transactions ever + * + * The subclass should return a count of all the transactions from + * all blocks. + * + * @return the number of transactions in the blockchain + */ virtual uint64_t get_tx_count() const = 0; - // return list of tx with hashes . - // TODO: decide if a missing hash means return empty list - // or just skip that hash + /** + * @brief fetches a list of transactions based on their hashes + * + * The subclass should attempt to fetch each transaction referred to by + * the hashes passed. + * + * Currently, if any of the transactions is not in BlockchainDB, the call + * to get_tx in the implementation will throw TX_DNE. + * + * + * + * @param hlist a list of hashes + * + * @return the list of transactions + */ virtual std::vector get_tx_list(const std::vector& hlist) const = 0; // returns height of block that contains transaction with hash + /** + * @brief fetches the height of a transaction's block + * + * The subclass should attempt to return the height of the block containing + * the transaction with the given hash. + * + * If the transaction cannot be found, the subclass should throw TX_DNE. + * + * @param h the hash of the transaction + * + * @return the height of the transaction's block + */ virtual uint64_t get_tx_block_height(const crypto::hash& h) const = 0; // returns the total number of outputs of amount + /** + * @brief fetches the number of outputs of a given amount + * + * The subclass should return a count of outputs of the given amount, + * or zero if there are none. + * + * + * + * @param amount the output amount being looked up + * + * @return the number of outputs of the given amount + */ virtual uint64_t get_num_outputs(const uint64_t& amount) const = 0; - // return index of the first element (should be hidden, but isn't) + /** + * @brief return index of the first element (should be hidden, but isn't) + * + * @return the index + */ virtual uint64_t get_indexing_base() const { return 0; } - // return public key for output with global output amount and index + /** + * @brief get some of an output's data + * + * The subclass should return the public key, unlock time, and block height + * for the output with the given amount and index, collected in a struct. + * + * If the output cannot be found, the subclass should throw OUTPUT_DNE. + * + * If any of these parts cannot be found, but some are, the subclass + * should throw DB_ERROR with a message stating as much. + * + * @param amount the output amount + * @param index the output's index (indexed by amount) + * + * @return the requested output data + */ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0; + + /** + * @brief get some of an output's data + * + * The subclass should return the public key, unlock time, and block height + * for the output with the given global index, collected in a struct. + * + * If the output cannot be found, the subclass should throw OUTPUT_DNE. + * + * If any of these parts cannot be found, but some are, the subclass + * should throw DB_ERROR with a message stating as much. + * + * @param global_index the output's index (global) + * + * @return the requested output data + */ virtual output_data_t get_output_key(const uint64_t& global_index) const = 0; - // returns the tx hash associated with an output, referenced by global output index + /** + * @brief gets an output's tx hash and index + * + * The subclass should return the hash of the transaction which created the + * output with the global index given, as well as its index in that transaction. + * + * @param index an output's global index + * + * @return the tx hash and output index + */ virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const = 0; - // returns the transaction-local reference for the output with at - // return type is pair of tx hash and index + /** + * @brief gets an output's tx hash and index + * + * The subclass should return the hash of the transaction which created the + * output with the amount and index given, as well as its index in that + * transaction. + * + * @param amount an output amount + * @param index an output's amount-specific index + * + * @return the tx hash and output index + */ virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) = 0; + + /** + * @brief gets some outputs' tx hashes and indices + * + * This function is a mirror of + * get_output_tx_and_index(const uint64_t& amount, const uint64_t& index), + * but for a list of outputs rather than just one. + * + * @param amount an output amount + * @param offsets a list of amount-specific output indices + * @param indices return-by-reference a list of tx hashes and output indices (as pairs) + */ virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) = 0; - virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) = 0; + /** + * @brief gets outputs' data + * + * This function is a mirror of + * get_output_data(const uint64_t& amount, const uint64_t& index) + * but for a list of outputs rather than just one. + * + * @param amount an output amount + * @param offsets a list of amount-specific output indices + * @param outputs return-by-reference a list of outputs' metadata + */ + virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) = 0; + + /* + * FIXME: Need to check with git blame and ask what this does to + * document it + */ virtual bool can_thread_bulk_indices() const = 0; - // return a vector of indices corresponding to the global output index for - // each output in the transaction with hash + /** + * @brief gets output indices (global) for a transaction's outputs + * + * The subclass should fetch the global output indices for each output + * in the transaction with the given hash. + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * If an output cannot be found, the subclass should throw OUTPUT_DNE. + * + * @param h a transaction hash + * + * @return a list of global output indices + */ virtual std::vector get_tx_output_indices(const crypto::hash& h) const = 0; - // return a vector of indices corresponding to the amount output index for - // each output in the transaction with hash + + /** + * @brief gets output indices (amount-specific) for a transaction's outputs + * + * The subclass should fetch the amount-specific output indices for each + * output in the transaction with the given hash. + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * If an output cannot be found, the subclass should throw OUTPUT_DNE. + * + * @param h a transaction hash + * + * @return a list of amount-specific output indices + */ virtual std::vector get_tx_amount_output_indices(const crypto::hash& h) const = 0; - // returns true if key image is present in spent key images storage + /** + * @brief check if a key image is stored as spent + * + * @param img the key image to check for + * + * @return true if the image is present, otherwise false + */ virtual bool has_key_image(const crypto::key_image& img) const = 0; + /** + * @brief runs a function over all key images stored + * + * The subclass should run the passed function for each key image it has + * stored, passing the key image as its parameter. + * + * If any call to the function returns false, the subclass should return + * false. Otherwise, the subclass returns true. + * + * @param std::function fn the function to run + * + * @return false if the function returns false for any key image, otherwise true + */ virtual bool for_all_key_images(std::function) const = 0; + + /** + * @brief runs a function over all blocks stored + * + * The subclass should run the passed function for each block it has + * stored, passing (block_height, block_hash, block) 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 fn the function to run + * + * @return false if the function returns false for any block, otherwise true + */ virtual bool for_all_blocks(std::function) const = 0; + + /** + * @brief runs a function over all transactions stored + * + * The subclass should run the passed function for each transaction it has + * stored, passing (transaction_hash, transaction) 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 fn the function to run + * + * @return false if the function returns false for any transaction, otherwise true + */ virtual bool for_all_transactions(std::function) const = 0; + + /** + * @brief runs a function over all outputs stored + * + * The subclass should run the passed function for each output it has + * stored, passing (amount, transaction_hash, tx_local_output_index) + * 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_outputs(std::function f) const = 0; + + // // Hard fork related storage + // + + // FIXME: verify that this is all correct + // - TW + /** + * @brief sets the height at which a hard fork has been voted to happen + * + * + * @param version the version voted to fork to + * @param height the height of the first block on the new fork + */ virtual void set_hard_fork_starting_height(uint8_t version, uint64_t height) = 0; + + /** + * @brief gets the height at which a hard fork has been voted to happen + * + * @param version the version to check + * + * @return the height at which the hard fork was accepted, if it has been, + * otherwise max(uint64_t) + */ virtual uint64_t get_hard_fork_starting_height(uint8_t version) const = 0; + + /** + * @brief sets which hardfork version a height is on + * + * @param height the height + * @param version the version + */ virtual void set_hard_fork_version(uint64_t height, uint8_t version) = 0; + + /** + * @brief checks which hardfork version a height is on + * + * @param height the height + * + * @return the version + */ virtual uint8_t get_hard_fork_version(uint64_t height) const = 0; + + /** + * @brief verify hard fork info in database + */ virtual void check_hard_fork_info() = 0; + + /** + * @brief delete hard fork info from database + */ virtual void drop_hard_fork_info() = 0; + /** + * @brief is BlockchainDB in read-only mode? + * + * @return true if in read-only mode, otherwise false + */ virtual bool is_read_only() const = 0; - // fix up anything that may be wrong due to past bugs + // TODO: this should perhaps be (or call) a series of functions which + // progressively update through version updates + /** + * @brief fix up anything that may be wrong due to past bugs + */ virtual void fixup(); + /** + * @brief set whether or not to automatically remove logs + * + * This function is only relevant for one implementation (BlockchainBDB), but + * is here to keep BlockchainDB users implementation-agnostic. + * + * @param auto_remove whether or not to auto-remove logs + */ void set_auto_remove_logs(bool auto_remove) { m_auto_remove_logs = auto_remove; } - bool m_open; - mutable epee::critical_section m_synchronization_lock; + bool m_open; //!< Whether or not the BlockchainDB is open/ready for use + mutable epee::critical_section m_synchronization_lock; //!< A lock, currently for when BlockchainLMDB needs to resize the backing db file + }; // class BlockchainDB diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 88eea1d7e..205356797 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -31,7 +31,6 @@ set(cryptonote_core_sources blockchain_storage.cpp blockchain.cpp checkpoints.cpp - checkpoints_create.cpp cryptonote_basic_impl.cpp cryptonote_core.cpp cryptonote_format_utils.cpp @@ -49,7 +48,6 @@ set(cryptonote_core_private_headers blockchain_storage_boost_serialization.h blockchain.h checkpoints.h - checkpoints_create.h connection_context.h cryptonote_basic.h cryptonote_basic_impl.h diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 131f56a4d..2f42e1db5 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -49,7 +49,7 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/checkpoints.h" #include "cryptonote_core/cryptonote_core.h" #if defined(PER_BLOCK_CHECKPOINT) #include "blocks/blocks.h" @@ -840,7 +840,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list blocks, starting at -// and return by reference . +// get the block sizes of the last blocks, and return by reference . void Blockchain::get_last_n_blocks_sizes(std::vector& sz, size_t count) const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -1408,6 +1407,10 @@ bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::list missed_tx_ids; std::list txs; + + // FIXME: s/rsp.missed_ids/missed_tx_id/ ? Seems like rsp.missed_ids + // is for missed blocks, not missed transactions as well. get_transactions(bl.tx_hashes, txs, missed_tx_ids); if (missed_tx_ids.size() != 0) @@ -1668,6 +1674,8 @@ uint64_t Blockchain::block_difficulty(uint64_t i) const return 0; } //------------------------------------------------------------------ +//TODO: return type should be void, throw on exception +// alternatively, return true only if no blocks missed template bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const { @@ -1692,6 +1700,8 @@ bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container return true; } //------------------------------------------------------------------ +//TODO: return type should be void, throw on exception +// alternatively, return true only if no transactions missed template bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const { @@ -1708,7 +1718,6 @@ bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container { missed_txs.push_back(tx_hash); } - //FIXME: is this the correct way to handle this? catch (const std::exception& e) { return false; @@ -1965,6 +1974,11 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vectorheight() < m_blocks_hash_check.size() && kept_by_block) { TIME_MEASURE_START(a); @@ -2038,6 +2053,10 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const } //------------------------------------------------------------------ // This function validates transaction inputs and their keys. +// FIXME: consider moving functionality specific to one input into +// check_tx_input() rather than here, and use this function simply +// to iterate the inputs as necessary (splitting the task +// using threads, etc.) bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height) { LOG_PRINT_L3("Blockchain::" << __func__); @@ -2320,7 +2339,7 @@ bool Blockchain::check_tx_input(const txin_to_key& txin, const crypto::hash& tx_ output_keys.clear(); - //check ring signature + // collect output keys outputs_visitor vi(output_keys, *this); if (!scan_outputkeys_for_indexes(txin, vi, tx_prefix_hash, pmax_related_block_height)) { @@ -2617,6 +2636,11 @@ leave: txs.push_back(tx); TIME_MEASURE_START(dd); + // FIXME: the storage should not be responsible for validation. + // If it does any, it is merely a sanity check. + // Validation is the purview of the Blockchain class + // - TW + // // ND: this is not needed, db->add_block() checks for duplicate k_images and fails accordingly. // if (!check_for_double_spend(tx, keys)) // { @@ -2797,6 +2821,8 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc return handle_block_to_main_chain(bl, id, bvc); } //------------------------------------------------------------------ +//TODO: Refactor, consider returning a failure height and letting +// caller decide course of action. void Blockchain::check_against_checkpoints(const checkpoints& points, bool enforce) { const auto& pts = points.get_points(); @@ -2834,16 +2860,16 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor // with an existing checkpoint. bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns) { - if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) + if (!m_checkpoints.load_checkpoints_from_json(file_path)) { - return false; + return false; } // if we're checking both dns and json, load checkpoints from dns. // if we're not hard-enforcing dns checkpoints, handle accordingly if (m_enforce_dns_checkpoints && check_dns) { - if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) + if (!m_checkpoints.load_checkpoints_from_dns()) { return false; } @@ -2851,7 +2877,7 @@ bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns else if (check_dns) { checkpoints dns_points; - cryptonote::load_checkpoints_from_dns(dns_points); + dns_points.load_checkpoints_from_dns(); if (m_checkpoints.check_for_conflicts(dns_points)) { check_against_checkpoints(dns_points, false); @@ -2878,6 +2904,8 @@ void Blockchain::block_longhash_worker(const uint64_t height, const std::vector< TIME_MEASURE_START(t); slow_hash_allocate_state(); + //FIXME: height should be changing here, as get_block_longhash expects + // the height of the block passed to it for (const auto & block : blocks) { crypto::hash id = get_block_hash(block); @@ -2933,6 +2961,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) } //------------------------------------------------------------------ +//FIXME: unused parameter txs void Blockchain::output_scan_worker(const uint64_t amount, const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const { try diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index ab2c8f9e8..94def1aa9 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -60,11 +60,14 @@ namespace cryptonote class tx_memory_pool; struct test_options; + /** Declares ways in which the BlockchainDB backend should be told to sync + * + */ enum blockchain_db_sync_mode { - db_sync, - db_async, - db_nosync + db_sync, //!< handle syncing calls instead of the backing db, synchronously + db_async, //!< handle syncing calls instead of the backing db, asynchronously + db_nosync //!< Leave syncing up to the backing db (safest, but slowest because of disk I/O) }; /************************************************************************/ @@ -73,6 +76,9 @@ namespace cryptonote class Blockchain { public: + /** + * @brief Now-defunct (TODO: remove) struct from in-memory blockchain + */ struct transaction_chain_entry { transaction tx; @@ -81,127 +87,697 @@ namespace cryptonote std::vector m_global_output_indexes; }; + /** + * @brief container for passing a block and metadata about it on the blockchain + */ struct block_extended_info { - block bl; - uint64_t height; - size_t block_cumulative_size; - difficulty_type cumulative_difficulty; - uint64_t already_generated_coins; + block bl; //!< the block + uint64_t height; //!< the height of the block in the blockchain + size_t block_cumulative_size; //!< the size (in bytes) 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 }; + /** + * @brief Blockchain constructor + * + * @param tx_pool a reference to the transaction pool to be kept by the Blockchain + */ Blockchain(tx_memory_pool& tx_pool); + /** + * @brief Initialize the Blockchain state + * + * @param db a pointer to the backing store to use for the blockchain + * @param testnet true if on testnet, else false + * @param test_options test parameters + * + * @return true on success, false if any initialization steps fail + */ bool init(BlockchainDB* db, const bool testnet = false, const cryptonote::test_options *test_options = NULL); + + /** + * @brief Initialize the Blockchain state + * + * @param db a pointer to the backing store to use for the blockchain + * @param hf a structure containing hardfork information + * @param testnet true if on testnet, else false + * + * @return true on success, false if any initialization steps fail + */ bool init(BlockchainDB* db, HardFork*& hf, const bool testnet = false); + + /** + * @brief Uninitializes the blockchain state + * + * Saves to disk any state that needs to be maintained + * + * @return true on success, false if any uninitialization steps fail + */ bool deinit(); + /** + * @brief assign a set of blockchain checkpoint hashes + * + * @param chk_pts the set of checkpoints to assign + */ void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; } - //bool push_new_block(); + /** + * @brief get blocks and transactions from blocks based on start height and count + * + * @param start_offset the height on the blockchain to start at + * @param count the number of blocks to get, if there are as many after start_offset + * @param blocks return-by-reference container to put result blocks in + * @param txs return-by-reference container to put result transactions in + * + * @return false if start_offset > blockchain height, else true + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const; + + /** + * @brief get blocks from blocks based on start height and count + * + * @param start_offset the height on the blockchain to start at + * @param count the number of blocks to get, if there are as many after start_offset + * @param blocks return-by-reference container to put result blocks in + * + * @return false if start_offset > blockchain height, else true + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const; + + /** + * @brief compiles a list of all blocks stored as alternative chains + * + * @param blocks return-by-reference container to put result blocks in + * + * @return true + */ bool get_alternative_blocks(std::list& blocks) const; + + /** + * @brief returns the number of alternative blocks stored + * + * @return the number of alternative blocks stored + */ size_t get_alternative_blocks_count() const; + + /** + * @brief gets a block's hash given a height + * + * @param height the height of the block + * + * @return the hash of the block at the requested height, or a zeroed hash if there is no such block + */ crypto::hash get_block_id_by_height(uint64_t height) const; + + /** + * @brief gets the block with a given hash + * + * @param h the hash to look for + * @param blk return-by-reference variable to put result block in + * + * @return true if the block was found, else false + */ bool get_block_by_hash(const crypto::hash &h, block &blk) const; + + /** + * @brief get all block hashes (main chain, alt chains, and invalid blocks) + * + * @param main return-by-reference container to put result main chain blocks' hashes in + * @param alt return-by-reference container to put result alt chain blocks' hashes in + * @param invalid return-by-reference container to put result invalid blocks' hashes in + */ void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) const; + + /** + * @brief performs some preprocessing on a group of incoming blocks to speed up verification + * + * @param blocks a list of incoming blocks + * + * @return false on erroneous blocks, else true + */ bool prepare_handle_incoming_blocks(const std::list &blocks); + + /** + * @brief incoming blocks post-processing, cleanup, and disk sync + * + * @param force_sync if true, and Blockchain is handling syncing to disk, always sync + * + * @return true + */ bool cleanup_handle_incoming_blocks(bool force_sync = false); + /** + * @brief search the blockchain for a transaction by hash + * + * @param id the hash to search for + * + * @return true if the tx exists, else false + */ bool have_tx(const crypto::hash &id) const; + + /** + * @brief check if any key image in a transaction has already been spent + * + * @param tx the transaction to check + * + * @return true if any key image is already spent in the blockchain, else false + */ bool have_tx_keyimges_as_spent(const transaction &tx) const; + + /** + * @brief check if a key image is already spent on the blockchain + * + * Whenever a transaction output is used as an input for another transaction + * (a true input, not just one of a mixing set), a key image is generated + * and stored in the transaction in order to prevent double spending. If + * this key image is seen again, the transaction using it is rejected. + * + * @param key_im the key image to search for + * + * @return true if the key image is already spent in the blockchain, else false + */ bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const; + /** + * @brief get the current height of the blockchain + * + * @return the height + */ uint64_t get_current_blockchain_height() const; + + /** + * @brief get the hash of the most recent block on the blockchain + * + * @return the hash + */ crypto::hash get_tail_id() const; + + /** + * @brief get the height and hash of the most recent block on the blockchain + * + * @param height return-by-reference variable to store the height in + * + * @return the hash + */ crypto::hash get_tail_id(uint64_t& height) const; + + /** + * @brief returns the difficulty target the next block to be added must meet + * + * @return the target + */ difficulty_type get_difficulty_for_next_block(); + + /** + * @brief adds a block to the blockchain + * + * Adds a new block to the blockchain. If the block's parent is not the + * current top of the blockchain, the block may be added to an alternate + * chain. If the block does not belong, is already in the blockchain + * or an alternate chain, or is invalid, return false. + * + * @param bl_ the block to be added + * @param bvc metadata about the block addition's success/failure + * + * @return true on successful addition to the blockchain, else false + */ bool add_new_block(const block& bl_, block_verification_context& bvc); + + /** + * @brief clears the blockchain and starts a new one + * + * @param b the first block in the new chain (the genesis block) + * + * @return true on success, else false + */ bool reset_and_set_genesis_block(const block& b); + + /** + * @brief creates a new block to mine against + * + * @param b return-by-reference block to be filled in + * @param miner_address address new coins for the block will go to + * @param di return-by-reference tells the miner what the difficulty target is + * @param height return-by-reference tells the miner what height it's mining against + * @param ex_nonce extra data to be added to the miner transaction's extra + * + * @return true if block template filled in successfully, else false + */ bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce); + + /** + * @brief checks if a block is known about with a given hash + * + * This function checks the main chain, alternate chains, and invalid blocks + * for a block with the given hash + * + * @param id the hash to search for + * + * @return true if the block is known, else false + */ bool have_block(const crypto::hash& id) const; + + /** + * @brief gets the total number of transactions on the main chain + * + * @return the number of transactions on the main chain + */ size_t get_total_transactions() const; + + /** + * @brief gets the hashes for a subset of the blockchain + * + * puts into list a list of hashes representing certain blocks + * from the blockchain in reverse chronological order + * + * the blocks chosen, at the time of this writing, are: + * the most recent 11 + * powers of 2 less recent from there, so 13, 17, 25, etc... + * + * @param ids return-by-reference list to put the resulting hashes in + * + * @return true + */ bool get_short_chain_history(std::list& ids) const; + + /** + * @brief get recent block hashes for a foreign chain + * + * Find the split point between us and foreign blockchain and return + * (by reference) the most recent common block hash along with up to + * BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes. + * + * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) + * @param resp return-by-reference the split height and subsequent blocks' hashes + * + * @return true if a block found in common, else false + */ bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const; + + /** + * @brief find the most recent common point between ours and a foreign chain + * + * This function takes a list of block hashes from another node + * on the network to find where the split point is between us and them. + * This is used to see what to send another node that needs to sync. + * + * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) + * @param starter_offset return-by-reference the most recent common block's height + * + * @return true if a block found in common, else false + */ bool find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset) const; + + /** + * @brief get recent blocks for a foreign chain + * + * This function gets recent blocks relative to a foreign chain, starting either at + * a requested height or whatever height is the most recent ours and the foreign + * chain have in common. + * + * @param req_start_block if non-zero, specifies a start point (otherwise find most recent commonality) + * @param qblock_ids the foreign chain's "short history" (see get_short_chain_history) + * @param blocks return-by-reference the blocks and their transactions + * @param total_height return-by-reference our current blockchain height + * @param start_height return-by-reference the height of the first block returned + * @param max_count the max number of blocks to get + * + * @return true if a block found in common or req_start_block specified, else false + */ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const; + + /** + * @brief retrieves a set of blocks and their transactions, and possibly other transactions + * + * the request object encapsulates a list of block hashes and a (possibly empty) list of + * transaction hashes. for each block hash, the block is fetched along with all of that + * block's transactions. Any transactions requested separately are fetched afterwards. + * + * @param arg the request + * @param rsp return-by-reference the response to fill in + * + * @return true unless any blocks or transactions are missing + */ bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp); - bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res); + + /** + * @brief gets random outputs to mix with + * + * This function takes an RPC request for outputs to mix with + * and creates an RPC response with the resultant output indices. + * + * Outputs to mix with are randomly selected from the utxo set + * for each output amount in the request. + * + * @param req the output amounts and number of mixins to select + * @param res return-by-reference the resultant output indices + * + * @return true + */ bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const; + + /** + * @brief gets the global indices for outputs from a given transaction + * + * This function gets the global indices for all outputs belonging + * to a specific transaction. + * + * @param tx_id the hash of the transaction to fetch indices for + * @param indexs return-by-reference the global indices for the transaction's outputs + * + * @return false if the transaction does not exist, or if no indices are found, otherwise true + */ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; + + /** + * @brief stores the blockchain + * + * If Blockchain is handling storing of the blockchain (rather than BlockchainDB), + * this initiates a blockchain save. + * + * @return true unless saving the blockchain fails + */ bool store_blockchain(); + /** + * @brief validates a transaction's inputs + * + * validates a transaction's inputs as correctly used and not previously + * spent. also returns the hash and height of the most recent block + * which contains an output that was used as an input to the transaction. + * + * @param tx the transaction to validate + * @param pmax_used_block_height return-by-reference block height of most recent input + * @param max_used_block_id return-by-reference block hash of most recent input + * @param kept_by_block whether or not the transaction is from a previously-verified block + * + * @return false if any input is invalid, otherwise true + */ bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, bool kept_by_block = false); + + /** + * @brief check that a transaction's outputs conform to current standards + * + * This function checks, for example at the time of this writing, that + * each output is of the form a * 10^b (phrased differently, that if + * written out would have only one non-zero digit in base 10). + * + * @param tx the transaction to check the outputs of + * + * @return false if any outputs do not conform, otherwise true + */ bool check_tx_outputs(const transaction& tx); + + /** + * @brief gets the blocksize limit based on recent blocks + * + * @return the limit + */ uint64_t get_current_cumulative_blocksize_limit() const; + + /** + * @brief checks if the blockchain is currently being stored + * + * Note: this should be meaningless in cases where Blockchain is not + * directly managing saving the blockchain to disk. + * + * @return true if Blockchain is having the chain stored currently, else false + */ bool is_storing_blockchain()const{return m_is_blockchain_storing;} + + /** + * @brief gets the difficulty of the block with a given height + * + * @param i the height + * + * @return the difficulty + */ uint64_t block_difficulty(uint64_t i) const; + /** + * @brief gets blocks based on a list of block hashes + * + * @tparam t_ids_container a standard-iterable container + * @tparam t_blocks_container a standard-iterable container + * @tparam t_missed_container a standard-iterable container + * @param block_ids a container of block hashes for which to get the corresponding blocks + * @param blocks return-by-reference a container to store result blocks in + * @param missed_bs return-by-reference a container to store missed blocks in + * + * @return false if an unexpected exception occurs, else true + */ template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const; + /** + * @brief gets transactions based on a list of transaction hashes + * + * @tparam t_ids_container a standard-iterable container + * @tparam t_tx_container a standard-iterable container + * @tparam t_missed_container a standard-iterable container + * @param txs_ids a container of hashes for which to get the corresponding transactions + * @param txs return-by-reference a container to store result transactions in + * @param missed_txs return-by-reference a container to store missed transactions in + * + * @return false if an unexpected exception occurs, else true + */ template bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const; + //debug functions + + /** + * @brief prints data about a snippet of the blockchain + * + * if start_index is greater than the blockchain height, do nothing + * + * @param start_index height on chain to start at + * @param end_index height on chain to end at + */ void print_blockchain(uint64_t start_index, uint64_t end_index) const; + + /** + * @brief prints every block's hash + * + * WARNING: This function will absolutely crush a terminal in prints, so + * it is recommended to redirect this output to a log file (or null sink + * if a log file is already set up, as should be the default) + */ void print_blockchain_index() const; + + /** + * @brief currently does nothing, candidate for removal + * + * @param file + */ void print_blockchain_outs(const std::string& file) const; + /** + * @brief check the blockchain against a set of checkpoints + * + * If a block fails a checkpoint and enforce is enabled, the blockchain + * will be rolled back to two blocks prior to that block. If enforce + * is disabled, as is currently the default case with DNS-based checkpoints, + * an error will be printed to the user but no other action will be taken. + * + * @param points the checkpoints to check against + * @param enforce whether or not to take action on failure + */ void check_against_checkpoints(const checkpoints& points, bool enforce); + + /** + * @brief configure whether or not to enforce DNS-based checkpoints + * + * @param enforce the new enforcement setting + */ void set_enforce_dns_checkpoints(bool enforce); + + /** + * @brief loads new checkpoints from a file and optionally from DNS + * + * @param file_path the path of the file to look for and load checkpoints from + * @param check_dns whether or not to check for new DNS-based checkpoints + * + * @return false if any enforced checkpoint type fails to load, otherwise true + */ bool update_checkpoints(const std::string& file_path, bool check_dns); + // user options, must be called before calling init() + + //FIXME: parameter names don't match function definition in .cpp file + /** + * @brief sets various performance options + * + * @param block_threads max number of threads when preparing blocks for addition + * @param blocks_per_sync number of blocks to cache before syncing to database + * @param sync_mode the ::blockchain_db_sync_mode to use + * @param fast_sync sync using built-in block hashes as trusted + */ void set_user_options(uint64_t block_threads, uint64_t blocks_per_sync, blockchain_db_sync_mode sync_mode, bool fast_sync); + /** + * @brief set whether or not to show/print time statistics + * + * @param stats the new time stats setting + */ void set_show_time_stats(bool stats) { m_show_time_stats = stats; } + /** + * @brief gets the hardfork voting state object + * + * @return the HardFork object + */ HardFork::State get_hard_fork_state() const; + + /** + * @brief gets the current hardfork version in use/voted for + * + * @return the version + */ uint8_t get_current_hard_fork_version() const { return m_hardfork->get_current_version(); } + + /** + * @brief returns the newest hardfork version known to the blockchain + * + * @return the version + */ uint8_t get_ideal_hard_fork_version() const { return m_hardfork->get_ideal_version(); } + + /** + * @brief returns the newest hardfork version voted to be enabled + * as of a certain height + * + * @param height the height for which to check version info + * + * @return the version + */ uint8_t get_ideal_hard_fork_version(uint64_t height) const { return m_hardfork->get_ideal_version(height); } + /** + * @brief get information about hardfork voting for a version + * + * @param version the version in question + * @param window the size of the voting window + * @param votes the number of votes to enable + * @param threshold the number of votes required to enable + * @param earliest_height the earliest height at which is allowed + * @param voting which version this node is voting for/using + * + * @return whether the version queried is enabled + */ bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const; + /** + * @brief remove transactions from the transaction pool (if present) + * + * @param txids a list of hashes of transactions to be removed + * + * @return false if any removals fail, otherwise true + */ bool flush_txes_from_pool(const std::list &txids); + /** + * @brief perform a check on all key images in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any key image fails the check, otherwise true + */ bool for_all_key_images(std::function) const; + + /** + * @brief perform a check on all blocks in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any block fails the check, otherwise true + */ bool for_all_blocks(std::function) const; + + /** + * @brief perform a check on all transactions in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any transaction fails the check, otherwise true + */ bool for_all_transactions(std::function) const; + + /** + * @brief perform a check on all outputs in the blockchain + * + * @param std::function the check to perform, pass/fail + * + * @return false if any output fails the check, otherwise true + */ bool for_all_outputs(std::function) const; + /** + * @brief get a reference to the BlockchainDB in use by Blockchain + * + * @return a reference to the BlockchainDB instance + */ BlockchainDB& get_db() { return *m_db; } + /** + * @brief get a number of outputs of a specific amount + * + * @param amount the amount + * @param offsets the indices (indexed to the amount) of the outputs + * @param outputs return-by-reference the outputs collected + * @param txs unused, candidate for removal + */ void output_scan_worker(const uint64_t amount,const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const; + /** + * @brief computes the "short" and "long" hashes for a set of blocks + * + * @param height the height of the first block + * @param blocks the blocks to be hashed + * @param map return-by-reference the hashes for each block + */ void block_longhash_worker(const uint64_t height, const std::vector &blocks, std::unordered_map &map) const; private: + + // TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage typedef std::unordered_map blocks_by_id_index; + typedef std::unordered_map transactions_container; + typedef std::unordered_set key_images_container; + typedef std::vector blocks_container; + typedef std::unordered_map blocks_ext_by_hash; + typedef std::unordered_map blocks_by_hash; + typedef std::map>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction + BlockchainDB* m_db; tx_memory_pool& m_tx_pool; + 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_sz_limit; + // metadata containers std::unordered_map>> m_scan_table; std::unordered_map> m_check_tx_inputs_table; std::unordered_map m_blocks_longhash_table; @@ -243,39 +819,323 @@ namespace cryptonote bool m_testnet; + /** + * @brief collects the keys for all outputs being "spent" as an input + * + * This function makes sure that each "input" in an input (mixins) exists + * and collects the public key for each from the transaction it was included in + * via the visitor passed to it. + * + * If pmax_related_block_height is not NULL, its value is set to the height + * of the most recent block which contains an output used in the input set + * + * @tparam visitor_t a class encapsulating tx is unlocked and collect tx key + * @param tx_in_to_key a transaction input instance + * @param vis an instance of the visitor to use + * @param tx_prefix_hash the hash of the associated transaction_prefix + * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set + * + * @return false if any keys are not found or any inputs are not unlocked, otherwise true + */ template inline bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t &vis, const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height = NULL) const; + + /** + * @brief collect output public keys of a transaction input set + * + * This function locates all outputs associated with a given input set (mixins) + * and validates that they exist and are usable + * (unlocked, unspent is checked elsewhere). + * + * If pmax_related_block_height is not NULL, its value is set to the height + * of the most recent block which contains an output used in the input set + * + * @param txin the transaction input + * @param tx_prefix_hash the transaction prefix hash, for caching organization + * @param sig the input signature + * @param output_keys return-by-reference the public keys of the outputs in the input set + * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set + * + * @return false if any output is not yet unlocked, or is missing, otherwise true + */ bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); + + /** + * @brief validate a transaction's inputs and their keys + * + * This function validates transaction inputs and their keys. Previously + * it also performed double spend checking, but that has been moved to its + * own function. + * + * If pmax_related_block_height is not NULL, its value is set to the height + * of the most recent block which contains an output used in any input set + * + * Currently this function calls ring signature validation for each + * transaction. + * + * @param tx the transaction to validate + * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set + * + * @return false if any validation step fails, otherwise true + */ bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL); + /** + * @brief performs a blockchain reorganization according to the longest chain rule + * + * This function aggregates all the actions necessary to switch to a + * newly-longer chain. If any step in the reorganization process fails, + * the blockchain is reverted to its previous state. + * + * @param alt_chain the chain to switch to + * @param discard_disconnected_chain whether or not to keep the old chain as an alternate + * + * @return false if the reorganization fails, otherwise true + */ bool switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain); + + /** + * @brief removes the most recent block from the blockchain + * + * @return the block removed + */ block pop_block_from_blockchain(); + /** + * @brief validate and add a new block to the end of the blockchain + * + * This function is merely a convenience wrapper around the other + * of the same name. This one passes the block's hash to the other + * as well as the block and verification context. + * + * @param bl the block to be added + * @param bvc metadata concerning the block's validity + * + * @return true if the block was added successfully, otherwise false + */ bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc); + + /** + * @brief validate and add a new block to the end of the blockchain + * + * When a block is given to Blockchain to be added to the blockchain, it + * is passed here if it is determined to belong at the end of the current + * chain. + * + * @param bl the block to be added + * @param id the hash of the block + * @param bvc metadata concerning the block's validity + * + * @return true if the block was added successfully, otherwise false + */ bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc); + + /** + * @brief validate and add a new block to an alternate blockchain + * + * If a block to be added does not belong to the main chain, but there + * is an alternate chain to which it should be added, that is handled + * here. + * + * @param b the block to be added + * @param id the hash of the block + * @param bvc metadata concerning the block's validity + * + * @return true if the block was added successfully, otherwise false + */ bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc); + + /** + * @brief gets the difficulty requirement for a new block on an alternate chain + * + * @param alt_chain the chain to be added to + * @param bei the block being added (and metadata, see ::block_extended_info) + * + * @return the difficulty requirement + */ difficulty_type get_next_difficulty_for_alternative_chain(const std::list& alt_chain, block_extended_info& bei) const; + + /** + * @brief sanity checks a miner transaction before validating an entire block + * + * This function merely checks basic things like the structure of the miner + * transaction, the unlock time, and that the amount doesn't overflow. + * + * @param b the block containing the miner transaction + * @param height the height at which the block will be added + * + * @return false if anything is found wrong with the miner transaction, otherwise true + */ bool prevalidate_miner_transaction(const block& b, uint64_t height); + + /** + * @brief validates a miner (coinbase) transaction + * + * This function makes sure that the miner calculated his reward correctly + * and that his miner transaction totals reward + fee. + * + * @param b the block containing the miner transaction to be validated + * @param cumulative_block_size the block's size + * @param fee the total fees collected in the block + * @param base_reward return-by-reference the new block's generated coins + * @param already_generated_coins the amount of currency generated prior to this block + * @param partial_block_reward return-by-reference true if miner accepted only partial reward + * + * @return false if anything is found wrong with the miner transaction, otherwise true + */ bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward); - bool validate_transaction(const block& b, uint64_t height, const transaction& tx); + + /** + * @brief reverts the blockchain to its previous state following a failed switch + * + * If Blockchain fails to switch to an alternate chain when it means + * to do so, this function reverts the blockchain to how it was before + * the attempted switch. + * + * @param original_chain the chain to switch back to + * @param rollback_height the height to revert to before appending the original chain + * + * @return false if something goes wrong with reverting (very bad), otherwise true + */ bool rollback_blockchain_switching(std::list& original_chain, uint64_t rollback_height); - bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height); - bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); - bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); + + /** + * @brief gets recent block sizes for median calculation + * + * get the block sizes of the last blocks, and return by reference . + * + * @param sz return-by-reference the list of sizes + * @param count the number of blocks to get sizes for + */ void get_last_n_blocks_sizes(std::vector& sz, size_t count) const; + + /** + * @brief adds the given output to the requested set of random outputs + * + * @param result_outs return-by-reference the set the output is to be added to + * @param amount the output amount + * @param i the output index (indexed to amount) + */ void add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i) const; + + /** + * @brief checks if a transaction is unlocked (its outputs spendable) + * + * This function checks to see if a transaction is unlocked. + * unlock_time is either a block index or a unix time. + * + * @param unlock_time the unlock parameter (height or time) + * + * @return true if spendable, otherwise false + */ bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; + + /** + * @brief stores an invalid block in a separate container + * + * Storing invalid blocks allows quick dismissal of the same block + * if it is seen again. + * + * @param bl the invalid block + * @param h the block's hash + * + * @return false if the block cannot be stored for some reason, otherwise true + */ bool add_block_as_invalid(const block& bl, const crypto::hash& h); + + /** + * @brief stores an invalid block in a separate container + * + * Storing invalid blocks allows quick dismissal of the same block + * if it is seen again. + * + * @param bei the invalid block (see ::block_extended_info) + * @param h the block's hash + * + * @return false if the block cannot be stored for some reason, otherwise true + */ bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); + + /** + * @brief checks a block's timestamp + * + * This function grabs the timestamps from the most recent blocks, + * where n = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. If there are not those many + * blocks in the blockchain, the timestap is assumed to be valid. If there + * are, this function returns: + * true if the block's timestamp is not less than the timestamp of the + * median of the selected blocks + * false otherwise + * + * @param b the block to be checked + * + * @return true if the block's timestamp is valid, otherwise false + */ bool check_block_timestamp(const block& b) const; + + /** + * @brief checks a block's timestamp + * + * If the block is not more recent than the median of the recent + * timestamps passed here, it is considered invalid. + * + * @param timestamps a list of the most recent timestamps to check against + * @param b the block to be checked + * + * @return true if the block's timestamp is valid, otherwise false + */ bool check_block_timestamp(std::vector& timestamps, const block& b) const; + + /** + * @brief get the "adjusted time" + * + * Currently this simply returns the current time according to the + * user's machine. + * + * @return the current time + */ uint64_t get_adjusted_time() const; + + /** + * @brief finish an alternate chain's timestamp window from the main chain + * + * for an alternate chain, get the timestamps from the main chain to complete + * the needed number of timestamps for the BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. + * + * @param start_height the alternate chain's attachment height to the main chain + * @param timestamps return-by-value the timestamps set to be populated + * + * @return true unless start_height is greater than the current blockchain height + */ bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); + + /** + * @brief calculate the block size limit for the next block to be added + * + * @return true + */ bool update_next_cumulative_size_limit(); void return_tx_to_pool(const std::vector &txs); + /** + * @brief make sure a transaction isn't attempting a double-spend + * + * @param tx the transaction to check + * @param keys_this_block a cumulative list of spent keys for the current block + * + * @return false if a double spend was detected, otherwise true + */ bool check_for_double_spend(const transaction& tx, key_images_container& keys_this_block) const; - void get_timestamp_and_difficulty(uint64_t ×tamp, difficulty_type &difficulty, const int offset) const; + + /** + * @brief validates a transaction input's ring signature + * + * @param tx_prefix_hash the transaction prefix' hash + * @param key_image the key image generated from the true input + * @param pubkeys the public keys for each input in the ring signature + * @param sig the signature generated for each input in the ring signature + * @param result false if the ring signature is invalid, otherwise true + */ void check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector &pubkeys, const std::vector &sig, uint64_t &result); diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index e1b89f887..a829b7cbe 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -48,7 +48,7 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/checkpoints.h" //#include "serialization/json_archive.h" #include "../../contrib/otshell_utils/utils.hpp" #include "../../src/p2p/data_logger.hpp" @@ -1854,7 +1854,7 @@ void blockchain_storage::check_against_checkpoints(const checkpoints& points, bo // with an existing checkpoint. bool blockchain_storage::update_checkpoints(const std::string& file_path, bool check_dns) { - if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) + if (!m_checkpoints.load_checkpoints_from_json(file_path)) { return false; } @@ -1863,7 +1863,7 @@ bool blockchain_storage::update_checkpoints(const std::string& file_path, bool c // if we're not hard-enforcing dns checkpoints, handle accordingly if (m_enforce_dns_checkpoints && check_dns) { - if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) + if (!m_checkpoints.load_checkpoints_from_dns()) { return false; } @@ -1871,7 +1871,7 @@ bool blockchain_storage::update_checkpoints(const std::string& file_path, bool c else if (check_dns) { checkpoints dns_points; - cryptonote::load_checkpoints_from_dns(dns_points, m_testnet); + dns_points.load_checkpoints_from_dns(m_testnet); if (m_checkpoints.check_for_conflicts(dns_points)) { check_against_checkpoints(dns_points, false); diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index 24d066dae..c038a4802 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -1,21 +1,21 @@ // Copyright (c) 2014-2016, 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 @@ -25,14 +25,44 @@ // 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. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include "include_base_utils.h" + using namespace epee; #include "checkpoints.h" +#include "common/dns_utils.h" +#include "include_base_utils.h" +#include +#include + +namespace +{ + bool dns_records_match(const std::vector& a, const std::vector& b) + { + if (a.size() != b.size()) return false; + + for (const auto& record_in_a : a) + { + bool ok = false; + for (const auto& record_in_b : b) + { + if (record_in_a == record_in_b) + { + ok = true; + break; + } + } + if (!ok) return false; + } + + return true; + } +} // anonymous namespace + namespace cryptonote { //--------------------------------------------------------------------------- @@ -84,10 +114,7 @@ namespace cryptonote return check_block(height, h, ignored); } //--------------------------------------------------------------------------- - // this basically says if the blockchain is smaller than the first - // checkpoint then alternate blocks are allowed. Alternatively, if the - // last checkpoint *before* the end of the current chain is also before - // the block to be added, then this is fine. + //FIXME: is this the desired behavior? bool checkpoints::is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const { if (0 == block_height) @@ -128,4 +155,206 @@ namespace cryptonote } return true; } + + bool checkpoints::init_default_checkpoints() + { + ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); + ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); + ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); + ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876"); + ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2"); + ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); + ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); + ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); + ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3"); + ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"); + ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); + ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); + ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); + ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553"); + ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61"); + ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf"); + ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131"); + ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8"); + ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d"); + ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831"); + ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02"); + ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5"); + ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd"); + ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60"); + ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337"); + ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f"); + + return true; + } + + bool checkpoints::load_checkpoints_from_json(const std::string json_hashfile_fullpath) + { + boost::system::error_code errcode; + if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode))) + { + LOG_PRINT_L1("Blockchain checkpoints file not found"); + return true; + } + + LOG_PRINT_L1("Adding checkpoints from blockchain hashfile"); + + uint64_t prev_max_height = get_max_height(); + LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height); + t_hash_json hashes; + epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath); + for (std::vector::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); ) + { + uint64_t height; + height = it->height; + if (height <= prev_max_height) { + LOG_PRINT_L1("ignoring checkpoint height " << height); + } else { + std::string blockhash = it->hash; + LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash); + ADD_CHECKPOINT(height, blockhash); + } + ++it; + } + + return true; + } + + bool checkpoints::load_checkpoints_from_dns(bool testnet) + { + // All four MoneroPulse domains have DNSSEC on and valid + static const std::vector dns_urls = { "checkpoints.moneropulse.se" + , "checkpoints.moneropulse.org" + , "checkpoints.moneropulse.net" + , "checkpoints.moneropulse.co" + }; + + static const std::vector testnet_dns_urls = { "testpoints.moneropulse.se" + , "testpoints.moneropulse.org" + , "testpoints.moneropulse.net" + , "testpoints.moneropulse.co" + }; + + std::vector > records; + records.resize(dns_urls.size()); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, dns_urls.size() - 1); + size_t first_index = dis(gen); + + bool avail, valid; + size_t cur_index = first_index; + do + { + std::string url; + if (testnet) + { + url = testnet_dns_urls[cur_index]; + } + else + { + url = dns_urls[cur_index]; + } + + records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid); + if (!avail) + { + records[cur_index].clear(); + LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); + } + if (!valid) + { + records[cur_index].clear(); + LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); + } + + cur_index++; + if (cur_index == dns_urls.size()) + { + cur_index = 0; + } + records[cur_index].clear(); + } while (cur_index != first_index); + + size_t num_valid_records = 0; + + for( const auto& record_set : records) + { + if (record_set.size() != 0) + { + num_valid_records++; + } + } + + if (num_valid_records < 2) + { + LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received"); + return true; + } + + int good_records_index = -1; + for (size_t i = 0; i < records.size() - 1; ++i) + { + if (records[i].size() == 0) continue; + + for (size_t j = i + 1; j < records.size(); ++j) + { + if (dns_records_match(records[i], records[j])) + { + good_records_index = i; + break; + } + } + if (good_records_index >= 0) break; + } + + if (good_records_index < 0) + { + LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched"); + return true; + } + + for (auto& record : records[good_records_index]) + { + auto pos = record.find(":"); + if (pos != std::string::npos) + { + uint64_t height; + crypto::hash hash; + + // parse the first part as uint64_t, + // if this fails move on to the next record + std::stringstream ss(record.substr(0, pos)); + if (!(ss >> height)) + { + continue; + } + + // parse the second part as crypto::hash, + // if this fails move on to the next record + std::string hashStr = record.substr(pos + 1); + if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash)) + { + continue; + } + + ADD_CHECKPOINT(height, hashStr); + } + } + return true; + } + + bool checkpoints::load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet, bool dns) + { + bool result; + + result = load_checkpoints_from_json(json_hashfile_fullpath); + if (dns) + { + result &= load_checkpoints_from_dns(testnet); + } + + return result; + } } diff --git a/src/cryptonote_core/checkpoints.h b/src/cryptonote_core/checkpoints.h index 00a53ec24..71727753e 100644 --- a/src/cryptonote_core/checkpoints.h +++ b/src/cryptonote_core/checkpoints.h @@ -1,21 +1,21 @@ // Copyright (c) 2014-2016, 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 @@ -25,30 +25,193 @@ // 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. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once #include #include #include "cryptonote_basic_impl.h" +#include "misc_log_ex.h" +#include "storages/portable_storage_template_helper.h" // epee json include + +#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false); +#define JSON_HASH_FILE_NAME "checkpoints.json" namespace cryptonote { + /** + * @brief A container for blockchain checkpoints + * + * A checkpoint is a pre-defined hash for the block at a given height. + * Some of these are compiled-in, while others can be loaded at runtime + * either from a json file or via DNS from a checkpoint-hosting server. + */ class checkpoints { public: + + /** + * @brief default constructor + */ checkpoints(); + + /** + * @brief adds a checkpoint to the container + * + * @param height the height of the block the checkpoint is for + * @param hash_str the hash of the block, as a string + * + * @return false if parsing the hash fails, or if the height is a duplicate + * AND the existing checkpoint hash does not match the new one, + * otherwise returns true + */ bool add_checkpoint(uint64_t height, const std::string& hash_str); + + /** + * @brief checks if there is a checkpoint in the future + * + * This function checks if the height passed is lower than the highest + * checkpoint. + * + * @param height the height to check against + * + * @return false if no checkpoints, otherwise returns whether or not + * the height passed is lower than the highest checkpoint. + */ bool is_in_checkpoint_zone(uint64_t height) const; - bool check_block(uint64_t height, const crypto::hash& h) const; + + /** + * @brief checks if the given height and hash agree with the checkpoints + * + * This function checks if the given height and hash exist in the + * checkpoints container. If so, it returns whether or not the passed + * parameters match the stored values. + * + * @param height the height to be checked + * @param h the hash to be checked + * @param is_a_checkpoint return-by-reference if there is a checkpoint at the given height + * + * @return true if there is no checkpoint at the given height, + * true if the passed parameters match the stored checkpoint, + * false otherwise + */ bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const; + + /** + * @overload + */ + bool check_block(uint64_t height, const crypto::hash& h) const; + + /** + * @brief checks if alternate chain blocks should be kept for a given height + * + * this basically says if the blockchain is smaller than the first + * checkpoint then alternate blocks are allowed. Alternatively, if the + * last checkpoint *before* the end of the current chain is also before + * the block to be added, then this is fine. + * + * @param blockchain_height the current blockchain height + * @param block_height the height of the block to be added as alternate + * + * @return true if alternate blocks are allowed given the parameters, + * otherwise false + */ bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const; + + /** + * @brief gets the highest checkpoint height + * + * @return the height of the highest checkpoint + */ uint64_t get_max_height() const; + + /** + * @brief gets the checkpoints container + * + * @return a const reference to the checkpoints container + */ const std::map& get_points() const; + + /** + * @brief checks if our checkpoints container conflicts with another + * + * A conflict refers to a case where both checkpoint sets have a checkpoint + * for a specific height but their hashes for that height do not match. + * + * @param other the other checkpoints instance to check against + * + * @return false if any conflict is found, otherwise true + */ bool check_for_conflicts(const checkpoints& other) const; + + /** + * @brief loads the default main chain checkpoints + * + * @return true unless adding a checkpoint fails + */ + bool init_default_checkpoints(); + + /** + * @brief load new checkpoints + * + * Loads new checkpoints from the specified json file, as well as + * (optionally) from DNS. + * + * @param json_hashfile_fullpath path to the json checkpoints file + * @param testnet whether to load testnet checkpoints or mainnet + * @param dns whether or not to load DNS checkpoints + * + * @return true if loading successful and no conflicts + */ + bool load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet=false, bool dns=true); + + /** + * @brief load new checkpoints from json + * + * @param json_hashfile_fullpath path to the json checkpoints file + * + * @return true if loading successful and no conflicts + */ + bool load_checkpoints_from_json(const std::string json_hashfile_fullpath); + + /** + * @brief load new checkpoints from DNS + * + * @param testnet whether to load testnet checkpoints or mainnet + * + * @return true if loading successful and no conflicts + */ + bool load_checkpoints_from_dns(bool testnet = false); + private: - std::map m_points; + + + /** + * @brief struct for loading a checkpoint from json + */ + struct t_hashline + { + uint64_t height; //!< the height of the checkpoint + std::string hash; //!< the hash for the checkpoint + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(hash) + END_KV_SERIALIZE_MAP() + }; + + /** + * @brief struct for loading many checkpoints from json + */ + struct t_hash_json { + std::vector hashlines; //!< the checkpoint lines from the file + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hashlines) + END_KV_SERIALIZE_MAP() + }; + + std::map m_points; //!< the checkpoints container + }; } diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp deleted file mode 100644 index 41f2321d5..000000000 --- a/src/cryptonote_core/checkpoints_create.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (c) 2014-2016, 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. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#include "checkpoints_create.h" -#include "common/dns_utils.h" -#include "include_base_utils.h" -#include -#include -#include "storages/portable_storage_template_helper.h" // epee json include - -namespace -{ - bool dns_records_match(const std::vector& a, const std::vector& b) - { - if (a.size() != b.size()) return false; - - for (const auto& record_in_a : a) - { - bool ok = false; - for (const auto& record_in_b : b) - { - if (record_in_a == record_in_b) - { - ok = true; - break; - } - } - if (!ok) return false; - } - - return true; - } -} // anonymous namespace - -namespace cryptonote -{ - -struct t_hashline -{ - uint64_t height; - std::string hash; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(height) - KV_SERIALIZE(hash) - END_KV_SERIALIZE_MAP() -}; - -struct t_hash_json { - std::vector hashlines; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(hashlines) - END_KV_SERIALIZE_MAP() -}; - -bool create_checkpoints(cryptonote::checkpoints& checkpoints) -{ - ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); - ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); - ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); - ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876"); - ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2"); - ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); - ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); - ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); - ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3"); - ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"); - ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); - ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); - ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); - ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553"); - ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61"); - ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf"); - ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131"); - ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8"); - ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d"); - ADD_CHECKPOINT(300000, "0c1cd46df6ccff90ec4ab493281f2583c344cd62216c427628990fe9db1bb8b6"); - ADD_CHECKPOINT(400000, "1b2b0e7a30e59691491529a3d506d1ba3d6052d0f6b52198b7330b28a6f1b6ac"); - ADD_CHECKPOINT(450000, "4d098b511ca97723e81737c448343cfd4e6dadb3d8a0e757c6e4d595e6e48357"); - ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831"); - ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02"); - ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5"); - ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd"); - ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60"); - ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337"); - ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f"); - - return true; -} - -bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath) -{ - boost::system::error_code errcode; - if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode))) - { - LOG_PRINT_L1("Blockchain checkpoints file not found"); - return true; - } - - LOG_PRINT_L1("Adding checkpoints from blockchain hashfile"); - - uint64_t prev_max_height = checkpoints.get_max_height(); - LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height); - t_hash_json hashes; - epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath); - for (std::vector::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); ) - { - uint64_t height; - height = it->height; - if (height <= prev_max_height) { - LOG_PRINT_L1("ignoring checkpoint height " << height); - } else { - std::string blockhash = it->hash; - LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash); - ADD_CHECKPOINT(height, blockhash); - } - ++it; - } - - return true; -} - -bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet) -{ - // All four MoneroPulse domains have DNSSEC on and valid - static const std::vector dns_urls = { "checkpoints.moneropulse.se" - , "checkpoints.moneropulse.org" - , "checkpoints.moneropulse.net" - , "checkpoints.moneropulse.co" - }; - - static const std::vector testnet_dns_urls = { "testpoints.moneropulse.se" - , "testpoints.moneropulse.org" - , "testpoints.moneropulse.net" - , "testpoints.moneropulse.co" - }; - - std::vector > records; - records.resize(dns_urls.size()); - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(0, dns_urls.size() - 1); - size_t first_index = dis(gen); - - bool avail, valid; - size_t cur_index = first_index; - do - { - std::string url; - if (testnet) - { - url = testnet_dns_urls[cur_index]; - } - else - { - url = dns_urls[cur_index]; - } - - records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid); - if (!avail) - { - records[cur_index].clear(); - LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); - } - if (!valid) - { - records[cur_index].clear(); - LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); - } - - cur_index++; - if (cur_index == dns_urls.size()) - { - cur_index = 0; - } - records[cur_index].clear(); - } while (cur_index != first_index); - - size_t num_valid_records = 0; - - for( const auto& record_set : records) - { - if (record_set.size() != 0) - { - num_valid_records++; - } - } - - if (num_valid_records < 2) - { - LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received"); - return true; - } - - int good_records_index = -1; - for (size_t i = 0; i < records.size() - 1; ++i) - { - if (records[i].size() == 0) continue; - - for (size_t j = i + 1; j < records.size(); ++j) - { - if (dns_records_match(records[i], records[j])) - { - good_records_index = i; - break; - } - } - if (good_records_index >= 0) break; - } - - if (good_records_index < 0) - { - LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched"); - return true; - } - - for (auto& record : records[good_records_index]) - { - auto pos = record.find(":"); - if (pos != std::string::npos) - { - uint64_t height; - crypto::hash hash; - - // parse the first part as uint64_t, - // if this fails move on to the next record - std::stringstream ss(record.substr(0, pos)); - if (!(ss >> height)) - { - continue; - } - - // parse the second part as crypto::hash, - // if this fails move on to the next record - std::string hashStr = record.substr(pos + 1); - if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash)) - { - continue; - } - - ADD_CHECKPOINT(height, hashStr); - } - } - return true; -} - -bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath) -{ - // TODO: replace hard-coded url with const string or #define - return (load_checkpoints_from_json(checkpoints, json_hashfile_fullpath) && load_checkpoints_from_dns(checkpoints)); -} - -} // namespace cryptonote diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h deleted file mode 100644 index 83830f8a2..000000000 --- a/src/cryptonote_core/checkpoints_create.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2014-2016, 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. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#pragma once - -#include "checkpoints.h" -#include "misc_log_ex.h" - -#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false); -#define JSON_HASH_FILE_NAME "checkpoints.json" - -namespace cryptonote -{ - - bool create_checkpoints(cryptonote::checkpoints& checkpoints); - - bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath); - bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, bool testnet = false); - bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath); - -} // namespace cryptonote diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 6f0fe88a4..c31be5acf 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -42,7 +42,7 @@ using namespace epee; #include "cryptonote_format_utils.h" #include "misc_language.h" #include -#include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/checkpoints.h" #include "blockchain_db/blockchain_db.h" #include "blockchain_db/lmdb/db_lmdb.h" #if defined(BERKELEY_DB) @@ -159,7 +159,7 @@ namespace cryptonote if (!m_testnet && !m_fakechain) { cryptonote::checkpoints checkpoints; - if (!cryptonote::create_checkpoints(checkpoints)) + if (!checkpoints.init_default_checkpoints()) { throw std::runtime_error("Failed to initialize checkpoints"); } @@ -415,7 +415,7 @@ namespace cryptonote CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints."); r = m_miner.init(vm, m_testnet); - CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); + CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance"); return load_state_data(); } @@ -634,11 +634,6 @@ namespace cryptonote return m_blockchain_storage.get_total_transactions(); } //----------------------------------------------------------------------------------------------- - //bool core::get_outs(uint64_t amount, std::list& pkeys) - //{ - // return m_blockchain_storage.get_outs(amount, pkeys); - //} - //----------------------------------------------------------------------------------------------- bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed) { if(m_mempool.have_tx(tx_hash)) @@ -770,10 +765,6 @@ namespace cryptonote { m_miner.on_synchronized(); } - //bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count) - //{ - // return m_blockchain_storage.get_backward_blocks_sizes(from_height, sizes, count); - //} //----------------------------------------------------------------------------------------------- bool core::add_new_block(const block& b, block_verification_context& bvc) { @@ -894,10 +885,6 @@ namespace cryptonote return m_blockchain_storage.get_block_by_hash(h, blk); } //----------------------------------------------------------------------------------------------- - //void core::get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) { - // m_blockchain_storage.get_all_known_block_ids(main, alt, invalid); - //} - //----------------------------------------------------------------------------------------------- std::string core::print_pool(bool short_format) const { return m_mempool.print_pool(short_format); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 32f0b2ad4..30384209f 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -63,157 +63,739 @@ namespace cryptonote /************************************************************************/ /* */ /************************************************************************/ + + /** + * @brief handles core cryptonote functionality + * + * This class coordinates cryptonote functionality including, but not + * limited to, communication among the Blockchain, the transaction pool, + * any miners, and the network. + */ class core: public i_miner_handler { public: + + /** + * @brief constructor + * + * sets member variables into a usable state + * + * @param pprotocol pre-constructed protocol object to store and use + */ core(i_cryptonote_protocol* pprotocol); + + /** + * @copydoc Blockchain::handle_get_objects + * + * @note see Blockchain::handle_get_objects() + * @param context connection context associated with the request + */ bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote_connection_context& context); + + /** + * @brief calls various idle routines + * + * @note see miner::on_idle and tx_memory_pool::on_idle + * + * @return true + */ bool on_idle(); + + /** + * @brief handles an incoming transaction + * + * Parses an incoming transaction and, if nothing is obviously wrong, + * passes it along to the transaction pool + * + * @param tx_blob the tx to handle + * @param tvc metadata about the transaction's validity + * @param keeped_by_block if the transaction has been in a block + * @param relayed whether or not the transaction was relayed to us + * + * @return true if the transaction made it to the transaction pool, otherwise false + */ bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed); + + /** + * @brief handles an incoming block + * + * periodic update to checkpoints is triggered here + * Attempts to add the block to the Blockchain and, on success, + * optionally updates the miner's block template. + * + * @param block_blob the block to be added + * @param bvc return-by-reference metadata context about the block's validity + * @param update_miner_blocktemplate whether or not to update the miner's block template + * + * @return false if loading new checkpoints fails, or the block is not + * added, otherwise true + */ bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true); + + /** + * @copydoc Blockchain::prepare_handle_incoming_blocks + * + * @note see Blockchain::prepare_handle_incoming_blocks + */ bool prepare_handle_incoming_blocks(const std::list &blocks); - bool cleanup_handle_incoming_blocks(bool force_sync = false); + /** + * @copydoc Blockchain::cleanup_handle_incoming_blocks + * + * @note see Blockchain::cleanup_handle_incoming_blocks + */ + bool cleanup_handle_incoming_blocks(bool force_sync = false); + + /** + * @brief check the size of a block against the current maximum + * + * @param block_blob the block to check + * + * @return whether or not the block is too big + */ bool check_incoming_block_size(const blobdata& block_blob) const; + + /** + * @brief get the cryptonote protocol instance + * + * @return the instance + */ i_cryptonote_protocol* get_protocol(){return m_pprotocol;} //-------------------- i_miner_handler ----------------------- + + /** + * @brief stores and relays a block found by a miner + * + * Updates the miner's target block, attempts to store the found + * block in Blockchain, and -- on success -- relays that block to + * the network. + * + * @param b the block found + * + * @return true if the block was added to the main chain, otherwise false + */ virtual bool handle_block_found( block& b); + + /** + * @copydoc Blockchain::create_block_template + * + * @note see Blockchain::create_block_template + */ virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce); + /** + * @brief gets the miner instance + * + * @return a reference to the miner instance + */ miner& get_miner(){return m_miner;} + + /** + * @brief gets the miner instance (const) + * + * @return a const reference to the miner instance + */ const miner& get_miner()const{return m_miner;} + + /** + * @brief adds command line options to the given options set + * + * As of now, there are no command line options specific to core, + * so this function simply returns. + * + * @param desc return-by-reference the command line options set to add to + */ static void init_options(boost::program_options::options_description& desc); + + /** + * @brief initializes the core as needed + * + * This function initializes the transaction pool, the Blockchain, and + * a miner instance with parameters given on the command line (or defaults) + * + * @param vm command line parameters + * @param test_options configuration options for testing + * + * @return false if one of the init steps fails, otherwise true + */ bool init(const boost::program_options::variables_map& vm, const test_options *test_options = NULL); + + /** + * @copydoc Blockchain::reset_and_set_genesis_block + * + * @note see Blockchain::reset_and_set_genesis_block + */ bool set_genesis_block(const block& b); + + /** + * @brief performs safe shutdown steps for core and core components + * + * Uninitializes the miner instance, transaction pool, and Blockchain + * + * if m_fast_exit is set, the call to Blockchain::deinit() is not made. + * + * @return true + */ bool deinit(); + + /** + * @brief sets fast exit flag + * + * @note see deinit() + */ static void set_fast_exit(); + + /** + * @brief gets the current state of the fast exit flag + * + * @return the fast exit flag + * + * @note see deinit() + */ static bool get_fast_exit(); + + /** + * @brief sets to drop blocks downloaded (for testing) + */ void test_drop_download(); + + /** + * @brief sets to drop blocks downloaded below a certain height + * + * @param height height below which to drop blocks + */ void test_drop_download_height(uint64_t height); + + /** + * @brief gets whether or not to drop blocks (for testing) + * + * @return whether or not to drop blocks + */ bool get_test_drop_download() const; + + /** + * @brief gets whether or not to drop blocks + * + * If the current blockchain height <= our block drop threshold + * and test drop blocks is set, return true + * + * @return see above + */ bool get_test_drop_download_height() const; + + /** + * @copydoc Blockchain::get_current_blockchain_height + * + * @note see Blockchain::get_current_blockchain_height() + */ uint64_t get_current_blockchain_height() const; - bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const; + + /** + * @brief get the hash and height of the most recent block + * + * @param height return-by-reference height of the block + * @param top_id return-by-reference hash of the block + * + * @return true + */ + bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) const; + + /** + * @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list&, std::list&) const + * + * @note see Blockchain::get_blocks(uint64_t, size_t, std::list&, std::list&) const + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const; + + /** + * @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list&) const + * + * @note see Blockchain::get_blocks(uint64_t, size_t, std::list&) const + */ bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const; + + /** + * @copydoc Blockchain::get_blocks(const t_ids_container&, t_blocks_container&, t_missed_container&) const + * + * @note see Blockchain::get_blocks(const t_ids_container&, t_blocks_container&, t_missed_container&) const + */ template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const { return m_blockchain_storage.get_blocks(block_ids, blocks, missed_bs); } + + /** + * @copydoc Blockchain::get_block_id_by_height + * + * @note see Blockchain::get_block_id_by_height + */ crypto::hash get_block_id_by_height(uint64_t height) const; + + /** + * @copydoc Blockchain::get_transactions + * + * @note see Blockchain::get_transactions + */ bool get_transactions(const std::vector& txs_ids, std::list& txs, std::list& missed_txs) const; + + /** + * @copydoc Blockchain::get_block_by_hash + * + * @note see Blockchain::get_block_by_hash + */ bool get_block_by_hash(const crypto::hash &h, block &blk) const; - //void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid); + /** + * @copydoc Blockchain::get_alternative_blocks + * + * @note see Blockchain::get_alternative_blocks(std::list&) const + */ bool get_alternative_blocks(std::list& blocks) const; + + /** + * @copydoc Blockchain::get_alternative_blocks_count + * + * @note see Blockchain::get_alternative_blocks_count() const + */ size_t get_alternative_blocks_count() const; + /** + * @brief set the pointer to the cryptonote protocol object to use + * + * @param pprotocol the pointer to set ours as + */ void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol); + + /** + * @copydoc Blockchain::set_checkpoints + * + * @note see Blockchain::set_checkpoints() + */ void set_checkpoints(checkpoints&& chk_pts); + + /** + * @brief set the file path to read from when loading checkpoints + * + * @param path the path to set ours as + */ void set_checkpoints_file_path(const std::string& path); + + /** + * @brief set whether or not we enforce DNS checkpoints + * + * @param enforce_dns enforce DNS checkpoints or not + */ void set_enforce_dns_checkpoints(bool enforce_dns); + /** + * @copydoc tx_memory_pool::get_transactions + * + * @note see tx_memory_pool::get_transactions + */ bool get_pool_transactions(std::list& txs) const; + + /** + * @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info + * + * @note see tx_memory_pool::get_pool_transactions_and_spent_keys_info + */ bool get_pool_transactions_and_spent_keys_info(std::vector& tx_infos, std::vector& key_image_infos) const; + + /** + * @copydoc tx_memory_pool::get_transactions_count + * + * @note see tx_memory_pool::get_transactions_count + */ size_t get_pool_transactions_count() const; + + /** + * @copydoc Blockchain::get_total_transactions + * + * @note see Blockchain::get_total_transactions + */ size_t get_blockchain_total_transactions() const; - //bool get_outs(uint64_t amount, std::list& pkeys); + + /** + * @copydoc Blockchain::have_block + * + * @note see Blockchain::have_block + */ bool have_block(const crypto::hash& id) const; + + /** + * @copydoc Blockchain::get_short_chain_history + * + * @note see Blockchain::get_short_chain_history + */ bool get_short_chain_history(std::list& ids) const; + + /** + * @copydoc Blockchain::find_blockchain_supplement(const std::list&, NOTIFY_RESPONSE_CHAIN_ENTRY::request&) const + * + * @note see Blockchain::find_blockchain_supplement(const std::list&, NOTIFY_RESPONSE_CHAIN_ENTRY::request&) const + */ bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const; + + /** + * @copydoc Blockchain::find_blockchain_supplement(const uint64_t, const std::list&, std::list > >&, uint64_t&, uint64_t&, size_t) const + * + * @note see Blockchain::find_blockchain_supplement(const uint64_t, const std::list&, std::list > >&, uint64_t&, uint64_t&, size_t) const + */ bool find_blockchain_supplement(const uint64_t req_start_block, const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const; + + /** + * @brief gets some stats about the daemon + * + * @param st_inf return-by-reference container for the stats requested + * + * @return true + */ bool get_stat_info(core_stat_info& st_inf) const; - //bool get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count); + + /** + * @copydoc Blockchain::get_tx_outputs_gindexs + * + * @note see Blockchain::get_tx_outputs_gindexs + */ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; + + /** + * @copydoc Blockchain::get_tail_id + * + * @note see Blockchain::get_tail_id + */ crypto::hash get_tail_id() const; + + /** + * @copydoc Blockchain::get_random_outs_for_amounts + * + * @note see Blockchain::get_random_outs_for_amounts + */ bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const; + + + /** + * @copydoc miner::pause + * + * @note see miner::pause + */ void pause_mine(); + + /** + * @copydoc miner::resume + * + * @note see miner::resume + */ void resume_mine(); + #if BLOCKCHAIN_DB == DB_LMDB + /** + * @brief gets the Blockchain instance + * + * @return a reference to the Blockchain instance + */ Blockchain& get_blockchain_storage(){return m_blockchain_storage;} + + /** + * @brief gets the Blockchain instance (const) + * + * @return a const reference to the Blockchain instance + */ const Blockchain& get_blockchain_storage()const{return m_blockchain_storage;} #else blockchain_storage& get_blockchain_storage(){return m_blockchain_storage;} const blockchain_storage& get_blockchain_storage()const{return m_blockchain_storage;} #endif - //debug functions + + /** + * @copydoc Blockchain::print_blockchain + * + * @note see Blockchain::print_blockchain + */ void print_blockchain(uint64_t start_index, uint64_t end_index) const; + + /** + * @copydoc Blockchain::print_blockchain_index + * + * @note see Blockchain::print_blockchain_index + */ void print_blockchain_index() const; + + /** + * @copydoc tx_memory_pool::print_pool + * + * @note see tx_memory_pool::print_pool + */ std::string print_pool(bool short_format) const; + + /** + * @copydoc Blockchain::print_blockchain_outs + * + * @note see Blockchain::print_blockchain_outs + */ void print_blockchain_outs(const std::string& file); + + /** + * @copydoc miner::on_synchronized + * + * @note see miner::on_synchronized + */ void on_synchronized(); + /** + * @brief sets the target blockchain height + * + * @param target_blockchain_height the height to set + */ void set_target_blockchain_height(uint64_t target_blockchain_height); + + /** + * @brief gets the target blockchain height + * + * @param target_blockchain_height the target height + */ uint64_t get_target_blockchain_height() const; + /** + * @brief tells the Blockchain to update its checkpoints + * + * This function will check if enough time has passed since the last + * time checkpoints were updated and tell the Blockchain to update + * its checkpoints if it is time. If updating checkpoints fails, + * the daemon is told to shut down. + * + * @note see Blockchain::update_checkpoints() + */ bool update_checkpoints(); + /** + * @brief tells the daemon to wind down operations and stop running + * + * Currently this function raises SIGTERM, allowing the installed signal + * handlers to do the actual stopping. + */ + void graceful_exit(); + + /** + * @brief stops the daemon running + * + * @note see graceful_exit() + */ void stop(); + /** + * @copydoc Blockchain::have_tx_keyimg_as_spent + * + * @note see Blockchain::have_tx_keyimg_as_spent + */ bool is_key_image_spent(const crypto::key_image& key_im) const; + + /** + * @brief check if multiple key images are spent + * + * plural version of is_key_image_spent() + * + * @param key_im list of key images to check + * @param spent return-by-reference result for each image checked + * + * @return true + */ bool are_key_images_spent(const std::vector& key_im, std::vector &spent) const; private: + + /** + * @copydoc add_new_tx(const transaction&, tx_verification_context&, bool) + * + * @param tx_hash the transaction's hash + * @param tx_prefix_hash the transaction prefix' hash + * @param blob_size the size of the transaction + * @param relayed whether or not the transaction was relayed to us + * + */ bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed); + + /** + * @brief add a new transaction to the transaction pool + * + * Adds a new transaction to the transaction pool. + * + * @param tx the transaction to add + * @param tvc return-by-reference metadata about the transaction's verification process + * @param keeped_by_block whether or not the transaction has been in a block + * @param relayed whether or not the transaction was relayed to us + * + * @return true if the transaction is already in the transaction pool, + * is already in a block on the Blockchain, or is successfully added + * to the transaction pool + */ bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed); + + /** + * @copydoc Blockchain::add_new_block + * + * @note see Blockchain::add_new_block + */ bool add_new_block(const block& b, block_verification_context& bvc); + + /** + * @brief load any core state stored on disk + * + * currently does nothing, but may have state to load in the future. + * + * @return true + */ bool load_state_data(); + + /** + * @copydoc parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const + * + * @note see parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const + */ bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob) const; + /** + * @brief check a transaction's syntax + * + * For now this does nothing, but it may check something about the tx + * in the future. + * + * @param tx the transaction to check + * + * @return true + */ bool check_tx_syntax(const transaction& tx) const; - //check correct values, amounts and all lightweight checks not related with database + + /** + * @brief validates some simple properties of a transaction + * + * Currently checks: tx has inputs, + * tx inputs all of supported type(s), + * tx outputs valid (type, key, amount), + * input and output total amounts don't overflow, + * output amount <= input amount, + * tx not too large, + * each input has a different key image. + * + * @param tx the transaction to check + * @param keeped_by_block if the transaction has been in a block + * + * @return true if all the checks pass, otherwise false + */ bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const; - //check if tx already in memory pool or in main blockchain - bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector& sig) const; - bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; + /** + * @copydoc miner::on_block_chain_update + * + * @note see miner::on_block_chain_update + * + * @return true + */ bool update_miner_block_template(); + + /** + * @brief act on a set of command line options given + * + * @param vm the command line options + * + * @return true + */ bool handle_command_line(const boost::program_options::variables_map& vm); - bool on_update_blocktemplate_interval(); + + /** + * @brief verify that each input key image in a transaction is unique + * + * @param tx the transaction to check + * + * @return false if any key image is repeated, otherwise true + */ bool check_tx_inputs_keyimages_diff(const transaction& tx) const; - void graceful_exit(); + + /** + * @brief checks HardFork status and prints messages about it + * + * Checks the status of HardFork and logs/prints if an update to + * the daemon is necessary. + * + * @note see Blockchain::get_hard_fork_state and HardFork::State + * + * @return true + */ bool check_fork_time(); + + /** + * @brief attempts to relay any transactions in the mempool which need it + * + * @return true + */ bool relay_txpool_transactions(); + + /** + * @brief locks a file in the BlockchainDB directory + * + * @param path the directory in which to place the file + * + * @return true if lock acquired successfully, otherwise false + */ bool lock_db_directory(const boost::filesystem::path &path); + + /** + * @brief unlocks the db directory + * + * @note see lock_db_directory() + * + * @return true + */ bool unlock_db_directory(); - static std::atomic m_fast_exit; - bool m_test_drop_download = true; - uint64_t m_test_drop_download_height = 0; + static std::atomic m_fast_exit; //!< whether or not to deinit Blockchain on exit + + bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing) - tx_memory_pool m_mempool; + uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so + + tx_memory_pool m_mempool; //!< transaction pool instance #if BLOCKCHAIN_DB == DB_LMDB - Blockchain m_blockchain_storage; + Blockchain m_blockchain_storage; //!< Blockchain instance #else blockchain_storage m_blockchain_storage; #endif - i_cryptonote_protocol* m_pprotocol; - epee::critical_section m_incoming_tx_lock; + + i_cryptonote_protocol* m_pprotocol; //!< cryptonote protocol instance + + epee::critical_section m_incoming_tx_lock; //!< incoming transaction lock + //m_miner and m_miner_addres are probably temporary here - miner m_miner; - account_public_address m_miner_address; - std::string m_config_folder; - cryptonote_protocol_stub m_protocol_stub; - epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; - epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; + 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 + + cryptonote_protocol_stub m_protocol_stub; //!< cryptonote protocol stub instance + + epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled + epee::math_helper::once_a_time_seconds<60*60*2, false> m_fork_moaner; //!< interval for checking HardFork status epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions + friend class tx_validate_inputs; - std::atomic m_starter_message_showed; + std::atomic m_starter_message_showed; //!< has the "daemon will sync now" message been shown? + + uint64_t m_target_blockchain_height; //!< blockchain height target + + bool m_testnet; //!< are we on testnet? - uint64_t m_target_blockchain_height; + bool m_fakechain; //!< are we using a fake chain (for testing purposes)? - bool m_testnet; - bool m_fakechain; - std::string m_checkpoints_path; - time_t m_last_dns_checkpoints_update; - time_t m_last_json_checkpoints_update; + std::string m_checkpoints_path; //!< path to json checkpoints file + time_t m_last_dns_checkpoints_update; //!< time when dns checkpoints were last updated + time_t m_last_json_checkpoints_update; //!< time when json checkpoints were last updated - std::atomic_flag m_checkpoints_updating; + std::atomic_flag m_checkpoints_updating; //!< set if checkpoints are currently updating to avoid multiple threads attempting to update at once - boost::interprocess::file_lock db_lock; + boost::interprocess::file_lock db_lock; //!< a lock object for a file lock in the db directory }; } diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp index 236e84481..54da77392 100644 --- a/src/cryptonote_core/difficulty.cpp +++ b/src/cryptonote_core/difficulty.cpp @@ -116,8 +116,8 @@ namespace cryptonote { return !carry; } - difficulty_type next_difficulty(vector timestamps, vector cumulative_difficulties, size_t target_seconds) { - //cutoff DIFFICULTY_LAG + difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { + if(timestamps.size() > DIFFICULTY_WINDOW) { timestamps.resize(DIFFICULTY_WINDOW); @@ -151,6 +151,8 @@ namespace cryptonote { assert(total_work > 0); uint64_t low, high; mul(total_work, target_seconds, low, high); + // blockchain errors "difficulty overhead" if this function returns zero. + // TODO: consider throwing an exception instead if (high != 0 || low + time_span - 1 < low) { return 0; } diff --git a/src/cryptonote_core/difficulty.h b/src/cryptonote_core/difficulty.h index d49c2f3b8..910f97035 100644 --- a/src/cryptonote_core/difficulty.h +++ b/src/cryptonote_core/difficulty.h @@ -39,6 +39,18 @@ namespace cryptonote { typedef std::uint64_t difficulty_type; + /** + * @brief checks if a hash fits the given difficulty + * + * The hash passes if (hash * difficulty) < 2^192. + * Phrased differently, if (hash * difficulty) fits without overflow into + * the least significant 192 bits of the 256 bit multiplication result. + * + * @param hash the hash to check + * @param difficulty the difficulty to check against + * + * @return true if valid, else false + */ bool check_hash(const crypto::hash &hash, difficulty_type difficulty); difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); } diff --git a/src/daemon/core.h b/src/daemon/core.h index 2208ef25a..2b7f0d177 100644 --- a/src/daemon/core.h +++ b/src/daemon/core.h @@ -28,7 +28,6 @@ #pragma once -#include "cryptonote_core/checkpoints_create.h" #include "cryptonote_core/cryptonote_core.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "misc_log_ex.h" -- cgit v1.2.3 From 287e88283cba79cf74b4282c76931713dc0ee9c2 Mon Sep 17 00:00:00 2001 From: Riccardo Spagni Date: Fri, 25 Mar 2016 14:52:19 +0200 Subject: remove connectivity tool, comment it out from munin plugins too --- src/CMakeLists.txt | 1 - src/connectivity_tool/CMakeLists.txt | 46 --- src/connectivity_tool/conn_tool.cpp | 377 ------------------------- utils/munin_plugins/alt_blocks_count | 2 +- utils/munin_plugins/difficulty | 2 +- utils/munin_plugins/grey_peerlist_size | 2 +- utils/munin_plugins/height | 2 +- utils/munin_plugins/incoming_connections_count | 2 +- utils/munin_plugins/outgoing_connections_count | 2 +- utils/munin_plugins/tx_count | 2 +- utils/munin_plugins/tx_pool_size | 2 +- utils/munin_plugins/white_peerlist_size | 2 +- 12 files changed, 9 insertions(+), 433 deletions(-) delete mode 100644 src/connectivity_tool/CMakeLists.txt delete mode 100644 src/connectivity_tool/conn_tool.cpp (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ac4a0aa1..e2349744d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,7 +87,6 @@ add_subdirectory(wallet) add_subdirectory(p2p) add_subdirectory(cryptonote_protocol) -add_subdirectory(connectivity_tool) add_subdirectory(miner) add_subdirectory(simplewallet) add_subdirectory(daemonizer) diff --git a/src/connectivity_tool/CMakeLists.txt b/src/connectivity_tool/CMakeLists.txt deleted file mode 100644 index 0ade952d2..000000000 --- a/src/connectivity_tool/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) 2014-2016, 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. - -set(connectivity_tool_sources - conn_tool.cpp) - -set(connectivity_tool_private_headers) - -bitmonero_add_executable(connectivity_tool - ${connectivity_tool_sources} - ${connectivity_tool_private_headers}) -target_link_libraries(connectivity_tool - LINK_PRIVATE - cryptonote_core - crypto - common - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${Boost_CHRONO_LIBRARY} - ${Boost_SYSTEM_LIBRARY}) diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp deleted file mode 100644 index 458d30cc3..000000000 --- a/src/connectivity_tool/conn_tool.cpp +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright (c) 2014-2016, 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. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#include "include_base_utils.h" -#include "version.h" - -using namespace epee; -#include -#include "p2p/p2p_protocol_defs.h" -#include "common/command_line.h" -#include "cryptonote_core/cryptonote_core.h" -#include "cryptonote_protocol/cryptonote_protocol_handler.h" -#include "net/levin_client.h" -#include "storages/levin_abstract_invoke2.h" -#include "cryptonote_core/cryptonote_core.h" -#include "storages/portable_storage_template_helper.h" -#include "crypto/crypto.h" -#include "storages/http_abstract_invoke.h" -#include "net/http_client.h" - -namespace po = boost::program_options; -using namespace cryptonote; -using namespace nodetool; - -namespace -{ - const command_line::arg_descriptor arg_ip = {"ip", "set ip"}; - const command_line::arg_descriptor arg_port = {"port", "set port"}; - const command_line::arg_descriptor arg_rpc_port = {"rpc_port", "set rpc port"}; - const command_line::arg_descriptor arg_timeout = {"timeout", "set timeout"}; - const command_line::arg_descriptor arg_priv_key = {"private_key", "private key to subscribe debug command", "", true}; - const command_line::arg_descriptor arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0}; - const command_line::arg_descriptor arg_generate_keys = {"generate_keys_pair", "generate private and public keys pair"}; - const command_line::arg_descriptor arg_request_stat_info = {"request_stat_info", "request statistics information"}; - const command_line::arg_descriptor arg_request_net_state = {"request_net_state", "request network state information (peer list, connections count)"}; - const command_line::arg_descriptor arg_get_daemon_info = {"rpc_get_daemon_info", "request daemon state info vie rpc (--rpc_port option should be set ).", "", true}; -} - -typedef COMMAND_REQUEST_STAT_INFO_T::stat_info> COMMAND_REQUEST_STAT_INFO; - -struct response_schema -{ - std::string status; - std::string COMMAND_REQUEST_STAT_INFO_status; - std::string COMMAND_REQUEST_NETWORK_STATE_status; - enableable si_rsp; - enableable ns_rsp; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - KV_SERIALIZE(COMMAND_REQUEST_STAT_INFO_status) - KV_SERIALIZE(COMMAND_REQUEST_NETWORK_STATE_status) - KV_SERIALIZE(si_rsp) - KV_SERIALIZE(ns_rsp) - END_KV_SERIALIZE_MAP() -}; - - std::string get_response_schema_as_json(response_schema& rs) - { - std::stringstream ss; - ss << "{" << ENDL - << " \"status\": \"" << rs.status << "\"," << ENDL - << " \"COMMAND_REQUEST_NETWORK_STATE_status\": \"" << rs.COMMAND_REQUEST_NETWORK_STATE_status << "\"," << ENDL - << " \"COMMAND_REQUEST_STAT_INFO_status\": \"" << rs.COMMAND_REQUEST_STAT_INFO_status << "\""; - if(rs.si_rsp.enabled) - { - ss << "," << ENDL << " \"si_rsp\": " << epee::serialization::store_t_to_json(rs.si_rsp.v, 1); - } - if(rs.ns_rsp.enabled) - { - ss << "," << ENDL << " \"ns_rsp\": {" << ENDL - << " \"local_time\": " << rs.ns_rsp.v.local_time << "," << ENDL - << " \"my_id\": \"" << rs.ns_rsp.v.my_id << "\"," << ENDL - << " \"connections_list\": [" << ENDL; - - size_t i = 0; - BOOST_FOREACH(const connection_entry& ce, rs.ns_rsp.v.connections_list) - { - ss << " {\"peer_id\": \"" << ce.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(ce.adr.ip) << "\", \"port\": " << ce.adr.port << ", \"is_income\": "<< ce.is_income << "}"; - if(rs.ns_rsp.v.connections_list.size()-1 != i) - ss << ","; - ss << ENDL; - i++; - } - ss << " ]," << ENDL; - ss << " \"local_peerlist_white\": [" << ENDL; - i = 0; - BOOST_FOREACH(const peerlist_entry& pe, rs.ns_rsp.v.local_peerlist_white) - { - ss << " {\"peer_id\": \"" << pe.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(pe.adr.ip) << "\", \"port\": " << pe.adr.port << ", \"last_seen\": "<< rs.ns_rsp.v.local_time - pe.last_seen << "}"; - if(rs.ns_rsp.v.local_peerlist_white.size()-1 != i) - ss << ","; - ss << ENDL; - i++; - } - ss << " ]," << ENDL; - - ss << " \"local_peerlist_gray\": [" << ENDL; - i = 0; - BOOST_FOREACH(const peerlist_entry& pe, rs.ns_rsp.v.local_peerlist_gray) - { - ss << " {\"peer_id\": \"" << pe.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(pe.adr.ip) << "\", \"port\": " << pe.adr.port << ", \"last_seen\": "<< rs.ns_rsp.v.local_time - pe.last_seen << "}"; - if(rs.ns_rsp.v.local_peerlist_gray.size()-1 != i) - ss << ","; - ss << ENDL; - i++; - } - ss << " ]" << ENDL << " }" << ENDL; - } - ss << "}"; - return std::move(ss.str()); - } -//--------------------------------------------------------------------------------------------------------------- -bool print_COMMAND_REQUEST_STAT_INFO(const COMMAND_REQUEST_STAT_INFO::response& si) -{ - std::cout << " ------ COMMAND_REQUEST_STAT_INFO ------ " << ENDL; - std::cout << "Version: " << si.version << ENDL; - std::cout << "OS Version: " << si.os_version << ENDL; - std::cout << "Connections: " << si.connections_count << ENDL; - std::cout << "INC Connections: " << si.incoming_connections_count << ENDL; - - - std::cout << "Tx pool size: " << si.payload_info.tx_pool_size << ENDL; - std::cout << "BC height: " << si.payload_info.blockchain_height << ENDL; - std::cout << "Mining speed: " << si.payload_info.mining_speed << ENDL; - std::cout << "Alternative blocks: " << si.payload_info.alternative_blocks << ENDL; - std::cout << "Top block id: " << si.payload_info.top_block_id_str << ENDL; - return true; -} -//--------------------------------------------------------------------------------------------------------------- -bool print_COMMAND_REQUEST_NETWORK_STATE(const COMMAND_REQUEST_NETWORK_STATE::response& ns) -{ - std::cout << " ------ COMMAND_REQUEST_NETWORK_STATE ------ " << ENDL; - std::cout << "Peer id: " << ns.my_id << ENDL; - std::cout << "Active connections:" << ENDL; - BOOST_FOREACH(const connection_entry& ce, ns.connections_list) - { - std::cout << ce.id << "\t" << string_tools::get_ip_string_from_int32(ce.adr.ip) << ":" << ce.adr.port << (ce.is_income ? "(INC)":"(OUT)") << ENDL; - } - - std::cout << "Peer list white:" << ns.my_id << ENDL; - BOOST_FOREACH(const peerlist_entry& pe, ns.local_peerlist_white) - { - std::cout << pe.id << "\t" << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << pe.adr.port << "\t" << misc_utils::get_time_interval_string(ns.local_time - pe.last_seen) << ENDL; - } - - std::cout << "Peer list gray:" << ns.my_id << ENDL; - BOOST_FOREACH(const peerlist_entry& pe, ns.local_peerlist_gray) - { - std::cout << pe.id << "\t" << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << pe.adr.port << "\t" << misc_utils::get_time_interval_string(ns.local_time - pe.last_seen) << ENDL; - } - - - return true; -} -//--------------------------------------------------------------------------------------------------------------- -bool handle_get_daemon_info(po::variables_map& vm) -{ - if(!command_line::has_arg(vm, arg_rpc_port)) - { - std::cout << "ERROR: rpc port not set" << ENDL; - return false; - } - - epee::net_utils::http::http_simple_client http_client; - - cryptonote::COMMAND_RPC_GET_INFO::request req = AUTO_VAL_INIT(req); - cryptonote::COMMAND_RPC_GET_INFO::response res = AUTO_VAL_INIT(res); - std::string daemon_addr = command_line::get_arg(vm, arg_ip) + ":" + std::to_string(command_line::get_arg(vm, arg_rpc_port)); - bool r = net_utils::invoke_http_json_remote_command2(daemon_addr + "/getinfo", req, res, http_client, command_line::get_arg(vm, arg_timeout)); - if(!r) - { - std::cout << "ERROR: failed to invoke request" << ENDL; - return false; - } - std::cout << "OK" << ENDL - << "height: " << res.height << ENDL - << "difficulty: " << res.difficulty << ENDL - << "tx_count: " << res.tx_count << ENDL - << "tx_pool_size: " << res.tx_pool_size << ENDL - << "alt_blocks_count: " << res.alt_blocks_count << ENDL - << "outgoing_connections_count: " << res.outgoing_connections_count << ENDL - << "incoming_connections_count: " << res.incoming_connections_count << ENDL - << "white_peerlist_size: " << res.white_peerlist_size << ENDL - << "grey_peerlist_size: " << res.grey_peerlist_size << ENDL; - - return true; -} -//--------------------------------------------------------------------------------------------------------------- -bool handle_request_stat(po::variables_map& vm, peerid_type peer_id) -{ - - if(!command_line::has_arg(vm, arg_priv_key)) - { - std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "secret key not set \"" << ENDL << "}"; - return false; - } - crypto::secret_key prvk = AUTO_VAL_INIT(prvk); - if(!string_tools::hex_to_pod(command_line::get_arg(vm, arg_priv_key) , prvk)) - { - std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "wrong secret key set \"" << ENDL << "}"; - return false; - } - - - response_schema rs = AUTO_VAL_INIT(rs); - - levin::levin_client_impl2 transport; - if(!transport.connect(command_line::get_arg(vm, arg_ip), static_cast(command_line::get_arg(vm, arg_port)), static_cast(command_line::get_arg(vm, arg_timeout)))) - { - std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}"; - return false; - }else - rs.status = "OK"; - - if(!peer_id) - { - COMMAND_REQUEST_PEER_ID::request req = AUTO_VAL_INIT(req); - COMMAND_REQUEST_PEER_ID::response rsp = AUTO_VAL_INIT(rsp); - if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_PEER_ID::ID, req, rsp, transport)) - { - std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}"; - return false; - }else - { - peer_id = rsp.my_id; - } - } - - - nodetool::proof_of_trust pot = AUTO_VAL_INIT(pot); - pot.peer_id = peer_id; - pot.time = time(NULL); - crypto::public_key pubk = AUTO_VAL_INIT(pubk); - string_tools::hex_to_pod(::config::P2P_REMOTE_DEBUG_TRUSTED_PUB_KEY, pubk); - crypto::hash h = tools::get_proof_of_trust_hash(pot); - crypto::generate_signature(h, pubk, prvk, pot.sign); - - if(command_line::get_arg(vm, arg_request_stat_info)) - { - COMMAND_REQUEST_STAT_INFO::request req = AUTO_VAL_INIT(req); - req.tr = pot; - if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_STAT_INFO::ID, req, rs.si_rsp.v, transport)) - { - std::stringstream ss; - ss << "ERROR: " << "Failed to invoke remote command COMMAND_REQUEST_STAT_INFO to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port); - rs.COMMAND_REQUEST_STAT_INFO_status = ss.str(); - }else - { - rs.si_rsp.enabled = true; - rs.COMMAND_REQUEST_STAT_INFO_status = "OK"; - } - } - - - if(command_line::get_arg(vm, arg_request_net_state)) - { - ++pot.time; - h = tools::get_proof_of_trust_hash(pot); - crypto::generate_signature(h, pubk, prvk, pot.sign); - COMMAND_REQUEST_NETWORK_STATE::request req = AUTO_VAL_INIT(req); - req.tr = pot; - if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_NETWORK_STATE::ID, req, rs.ns_rsp.v, transport)) - { - std::stringstream ss; - ss << "ERROR: " << "Failed to invoke remote command COMMAND_REQUEST_NETWORK_STATE to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port); - rs.COMMAND_REQUEST_NETWORK_STATE_status = ss.str(); - }else - { - rs.ns_rsp.enabled = true; - rs.COMMAND_REQUEST_NETWORK_STATE_status = "OK"; - } - } - std::cout << get_response_schema_as_json(rs); - return true; -} -//--------------------------------------------------------------------------------------------------------------- -bool generate_and_print_keys() -{ - crypto::public_key pk = AUTO_VAL_INIT(pk); - crypto::secret_key sk = AUTO_VAL_INIT(sk); - generate_keys(pk, sk); - std::cout << "PUBLIC KEY: " << epee::string_tools::pod_to_hex(pk) << ENDL - << "PRIVATE KEY: " << epee::string_tools::pod_to_hex(sk); - return true; -} -int main(int argc, char* argv[]) -{ - string_tools::set_module_name_and_folder(argv[0]); - log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); - - // Declare the supported options. - po::options_description desc_general("General options"); - command_line::add_arg(desc_general, command_line::arg_help); - - po::options_description desc_params("Connectivity options"); - command_line::add_arg(desc_params, arg_ip); - command_line::add_arg(desc_params, arg_port); - command_line::add_arg(desc_params, arg_rpc_port); - command_line::add_arg(desc_params, arg_timeout); - command_line::add_arg(desc_params, arg_request_stat_info); - command_line::add_arg(desc_params, arg_request_net_state); - command_line::add_arg(desc_params, arg_generate_keys); - command_line::add_arg(desc_params, arg_peer_id); - command_line::add_arg(desc_params, arg_priv_key); - command_line::add_arg(desc_params, arg_get_daemon_info); - - - po::options_description desc_all; - desc_all.add(desc_general).add(desc_params); - - po::variables_map vm; - bool r = command_line::handle_error_helper(desc_all, [&]() - { - po::store(command_line::parse_command_line(argc, argv, desc_general, true), vm); - if (command_line::get_arg(vm, command_line::arg_help)) - { - std::cout << desc_all << ENDL; - return false; - } - - po::store(command_line::parse_command_line(argc, argv, desc_params, false), vm); - po::notify(vm); - - return true; - }); - if (!r) - return 1; - - if(command_line::has_arg(vm, arg_request_stat_info) || command_line::has_arg(vm, arg_request_net_state)) - { - return handle_request_stat(vm, command_line::get_arg(vm, arg_peer_id)) ? 0:1; - } - if(command_line::has_arg(vm, arg_get_daemon_info)) - { - return handle_get_daemon_info(vm) ? 0:1; - } - else if(command_line::has_arg(vm, arg_generate_keys)) - { - return generate_and_print_keys() ? 0:1; - } - else - { - std::cerr << "Not enough arguments." << ENDL; - std::cerr << desc_all << ENDL; - } - - return 1; -} - diff --git a/utils/munin_plugins/alt_blocks_count b/utils/munin_plugins/alt_blocks_count index d68289c34..cf6b3651b 100644 --- a/utils/munin_plugins/alt_blocks_count +++ b/utils/munin_plugins/alt_blocks_count @@ -42,4 +42,4 @@ EOM esac printf "alt_blocks_count.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep alt_blocks_count | cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep alt_blocks_count | cut -d ' ' -f2 diff --git a/utils/munin_plugins/difficulty b/utils/munin_plugins/difficulty index e22b76829..edfd2bf16 100644 --- a/utils/munin_plugins/difficulty +++ b/utils/munin_plugins/difficulty @@ -42,4 +42,4 @@ EOM esac printf "difficulty.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep difficulty | cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep difficulty | cut -d ' ' -f2 diff --git a/utils/munin_plugins/grey_peerlist_size b/utils/munin_plugins/grey_peerlist_size index e18c4cd06..d7b1bd6a7 100644 --- a/utils/munin_plugins/grey_peerlist_size +++ b/utils/munin_plugins/grey_peerlist_size @@ -42,4 +42,4 @@ EOM esac printf "grey_peerlist_size.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep grey_peerlist_size | cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep grey_peerlist_size | cut -d ' ' -f2 diff --git a/utils/munin_plugins/height b/utils/munin_plugins/height index ca68b31b9..3f79fa302 100644 --- a/utils/munin_plugins/height +++ b/utils/munin_plugins/height @@ -43,4 +43,4 @@ EOM esac printf "height.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep height | cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep height | cut -d ' ' -f2 diff --git a/utils/munin_plugins/incoming_connections_count b/utils/munin_plugins/incoming_connections_count index 2521d4c99..7232e5736 100644 --- a/utils/munin_plugins/incoming_connections_count +++ b/utils/munin_plugins/incoming_connections_count @@ -42,4 +42,4 @@ EOM esac printf "incoming_connections_count.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep incoming_connections_count | cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep incoming_connections_count | cut -d ' ' -f2 diff --git a/utils/munin_plugins/outgoing_connections_count b/utils/munin_plugins/outgoing_connections_count index 92edb3d67..773ce4624 100644 --- a/utils/munin_plugins/outgoing_connections_count +++ b/utils/munin_plugins/outgoing_connections_count @@ -42,4 +42,4 @@ EOM esac printf "outgoing_connections_count.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep outgoing_connections_count | cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep outgoing_connections_count | cut -d ' ' -f2 diff --git a/utils/munin_plugins/tx_count b/utils/munin_plugins/tx_count index 95bb8b540..f2504cd5f 100644 --- a/utils/munin_plugins/tx_count +++ b/utils/munin_plugins/tx_count @@ -43,4 +43,4 @@ EOM esac printf "tx_count.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep tx_count| cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep tx_count| cut -d ' ' -f2 diff --git a/utils/munin_plugins/tx_pool_size b/utils/munin_plugins/tx_pool_size index 58717cf1f..3bf952071 100644 --- a/utils/munin_plugins/tx_pool_size +++ b/utils/munin_plugins/tx_pool_size @@ -42,4 +42,4 @@ EOM esac printf "tx_pool_size.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep tx_pool_size| cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep tx_pool_size| cut -d ' ' -f2 diff --git a/utils/munin_plugins/white_peerlist_size b/utils/munin_plugins/white_peerlist_size index 2b92622e5..9e5771cc3 100644 --- a/utils/munin_plugins/white_peerlist_size +++ b/utils/munin_plugins/white_peerlist_size @@ -42,4 +42,4 @@ EOM esac printf "white_peerlist_size.value " -/home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep white_peerlist_size | cut -d ' ' -f2 +# rewrite using curl or similar: /home/user/bitmonero/build/release/src/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep white_peerlist_size | cut -d ' ' -f2 -- cgit v1.2.3 From 97638b1fb7fde487e4025066874fa3274779eabc Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 23 Mar 2016 17:01:49 +0000 Subject: core: fix miner tx block reward with fees --- src/cryptonote_core/cryptonote_format_utils.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 253e568b5..3c1acd8a9 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -126,20 +126,19 @@ namespace cryptonote return false; } - // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and - // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the - // emission schedule - if (hard_fork_version >= 2) - { - block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; - } - #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) LOG_PRINT_L1("Creating block template: reward " << block_reward << ", fee " << fee) #endif block_reward += fee; + // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and + // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the + // emission schedule + if (hard_fork_version >= 2) { + block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; + } + std::vector out_amounts; decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, -- cgit v1.2.3 From b8527668ffbcc4c95fe33e2ea163f07f25af5fcb Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 23 Mar 2016 17:56:08 +0000 Subject: blockchain: for v3, require miner tx to have well behaved outs This was meant to go in v2, but the miner tx slipped through the cracks as it doesn't go through the main tx verification since it doesn't get added to the pool. --- src/cryptonote_core/blockchain.cpp | 13 +++++++++++-- src/cryptonote_core/blockchain.h | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 2f42e1db5..0f6afe740 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -948,7 +948,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height) } //------------------------------------------------------------------ // This function validates the miner transaction reward -bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward) +bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version) { LOG_PRINT_L3("Blockchain::" << __func__); //validate reward @@ -957,6 +957,15 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl money_in_use += o.amount; partial_block_reward = false; + if (version >= 3) { + for (auto &o: b.miner_tx.vout) { + if (!is_valid_decomposed_amount(o.amount)) { + LOG_PRINT_L1("miner tx output " << print_money(o.amount) << " is not a valid decomposed amount"); + return false; + } + } + } + std::vector last_blocks_sizes; get_last_n_blocks_sizes(last_blocks_sizes, CRYPTONOTE_REWARD_BLOCKS_WINDOW); if (!get_block_reward(epee::misc_utils::median(last_blocks_sizes), cumulative_block_size, already_generated_coins, base_reward, get_current_hard_fork_version())) @@ -2698,7 +2707,7 @@ leave: TIME_MEASURE_START(vmt); uint64_t base_reward = 0; uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0; - if(!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins, bvc.m_partial_block_reward)) + if(!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins, bvc.m_partial_block_reward, m_hardfork->get_current_version())) { LOG_PRINT_L1("Block with id: " << id << " has incorrect miner transaction"); bvc.m_verifivation_failed = true; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 94def1aa9..393faef2a 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -980,10 +980,11 @@ namespace cryptonote * @param base_reward return-by-reference the new block's generated coins * @param already_generated_coins the amount of currency generated prior to this block * @param partial_block_reward return-by-reference true if miner accepted only partial reward + * @param version hard fork version for that transaction * * @return false if anything is found wrong with the miner transaction, otherwise true */ - bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward); + bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version); /** * @brief reverts the blockchain to its previous state following a failed switch -- cgit v1.2.3 From f26651ab8a3ed7f39a13f258880ee57f7ab85b68 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 11:44:43 +0000 Subject: wallet: factor fee calculation --- src/wallet/wallet2.cpp | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1c7187cf0..7c54ca5e9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -92,6 +92,13 @@ void do_prepare_file_names(const std::string& file_path, std::string& keys_file, } } +uint64_t calculate_fee(const cryptonote::blobdata &blob) +{ + uint64_t bytes = blob.size(); + uint64_t kB = (bytes + 1023) / 1024; + return kB * FEE_PER_KB; +} + } //namespace namespace tools @@ -2030,13 +2037,7 @@ std::vector wallet2::create_transactions(std::vector wallet2::create_transactions_2(std::vector available_for_fee && dsts[0].amount > 0) @@ -2686,13 +2681,7 @@ std::vector wallet2::create_dust_sweep_transactions() { transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); auto txBlob = t_serializable_object_to_blob(ptx.tx); - uint64_t txSize = txBlob.size(); - uint64_t numKB = txSize / 1024; - if (txSize % 1024) - { - numKB++; - } - needed_fee = numKB * FEE_PER_KB; + needed_fee = calculate_fee(txBlob); // reroll the tx with the actual amount minus the fee // if there's not enough for the fee, it'll throw -- cgit v1.2.3 From f9a2fd2ff55654cdbc458378d0365189ffd1c46a Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 11:51:58 +0000 Subject: wallet: handle rare case where fee adjustment can bump to the next kB It resulted in a tx being sent with too low a fee, and thus rejected. --- src/wallet/wallet2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7c54ca5e9..aa638143c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2677,7 +2677,7 @@ std::vector wallet2::create_dust_sweep_transactions() // loop until fee is met without increasing tx size to next KB boundary. uint64_t needed_fee = 0; - if (1) + do { transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); auto txBlob = t_serializable_object_to_blob(ptx.tx); @@ -2687,7 +2687,8 @@ std::vector wallet2::create_dust_sweep_transactions() // if there's not enough for the fee, it'll throw transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx); txBlob = t_serializable_object_to_blob(ptx.tx); - } + needed_fee = calculate_fee(txBlob); + } while (ptx.fee < needed_fee); ptx_vector.push_back(ptx); -- cgit v1.2.3 From 600a3cf0c0ca0a99dbdc91d32138db3c8aa4165c Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 14:30:23 +0000 Subject: New RPC and daemon command to get output histogram This is a list of existing output amounts along with the number of outputs of that amount in the blockchain. The daemon command takes: - no parameters: all outputs with at least 3 instances - one parameter: all outputs with at least that many instances - two parameters: all outputs within that many instances The default starts at 3 to avoid massive spamming of all dust outputs in the blockchain, and is the current minimum mixin requirement. An optional vector of amounts may be passed, to request histogram only for those outputs. --- src/blockchain_db/berkeleydb/db_bdb.cpp | 6 ++++ src/blockchain_db/berkeleydb/db_bdb.h | 9 ++++++ src/blockchain_db/blockchain_db.h | 9 ++++++ src/blockchain_db/lmdb/db_lmdb.cpp | 57 +++++++++++++++++++++++++++++++++ src/blockchain_db/lmdb/db_lmdb.h | 10 ++++++ src/cryptonote_core/blockchain.cpp | 5 +++ src/cryptonote_core/blockchain.h | 9 ++++++ src/daemon/command_parser_executor.cpp | 18 +++++++++++ src/daemon/command_parser_executor.h | 2 ++ src/daemon/command_server.cpp | 5 +++ src/daemon/rpc_command_executor.cpp | 36 +++++++++++++++++++++ src/daemon/rpc_command_executor.h | 2 ++ src/rpc/core_rpc_server.cpp | 32 ++++++++++++++++++ src/rpc/core_rpc_server.h | 2 ++ src/rpc/core_rpc_server_commands_defs.h | 41 ++++++++++++++++++++++++ tests/unit_tests/hardfork.cpp | 1 + 16 files changed, 244 insertions(+) (limited to 'src') diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp index 1fef9e619..a7fa556bd 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ b/src/blockchain_db/berkeleydb/db_bdb.cpp @@ -2180,6 +2180,12 @@ void BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const std::v LOG_PRINT_L3("db3: " << db3); } +std::map::BlockchainBDB::get_output_histogram(const std::vector &amounts) const +{ + LOG_PRINT_L3("BlockchainBDB::" << __func__); + throw1(DB_ERROR("Not implemented.")); +} + void BlockchainBDB::set_hard_fork_starting_height(uint8_t version, uint64_t height) { LOG_PRINT_L3("BlockchainBDB::" << __func__); diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h index d7cbd24e7..5c6bda4eb 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.h +++ b/src/blockchain_db/berkeleydb/db_bdb.h @@ -341,6 +341,15 @@ public: virtual bool can_thread_bulk_indices() const { return false; } #endif + /** + * @brief return a histogram of outputs on the blockchain + * + * @param amounts optional set of amounts to lookup + * + * @return a set of amount/instances + */ + std::map get_output_histogram(const std::vector &amounts) const; + private: virtual void add_block( const block& blk , const size_t& block_size diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 3e0ca141e..3585bd061 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -1288,6 +1288,15 @@ public: */ virtual void drop_hard_fork_info() = 0; + /** + * @brief return a histogram of outputs on the blockchain + * + * @param amounts optional set of amounts to lookup + * + * @return a set of amount/instances + */ + virtual std::map get_output_histogram(const std::vector &amounts) const = 0; + /** * @brief is BlockchainDB in read-only mode? * diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index e928ab803..9b99520a1 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -2692,6 +2692,63 @@ void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std:: LOG_PRINT_L3("db3: " << db3); } +std::map BlockchainLMDB::get_output_histogram(const std::vector &amounts) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + RCURSOR(output_amounts); + + std::map histogram; + MDB_val k; + MDB_val v; + + if (amounts.empty()) + { + MDB_cursor_op op = MDB_FIRST; + while (1) + { + int ret = mdb_cursor_get(m_cur_output_amounts, &k, &v, op); + op = MDB_NEXT_NODUP; + if (ret == MDB_NOTFOUND) + break; + if (ret) + throw0(DB_ERROR(lmdb_error("Failed to enumerate outputs: ", ret).c_str())); + mdb_size_t num_elems = 0; + mdb_cursor_count(m_cur_output_amounts, &num_elems); + uint64_t amount = *(const uint64_t*)k.mv_data; + histogram[amount] = num_elems; + } + } + else + { + for (const auto &amount: amounts) + { + MDB_val_copy k(amount); + int ret = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_SET); + if (ret == MDB_NOTFOUND) + { + histogram[amount] = 0; + } + else if (ret == MDB_SUCCESS) + { + mdb_size_t num_elems = 0; + mdb_cursor_count(m_cur_output_amounts, &num_elems); + histogram[amount] = num_elems; + } + else + { + throw0(DB_ERROR(lmdb_error("Failed to enumerate outputs: ", ret).c_str())); + } + } + } + + TXN_POSTFIX_RDONLY(); + + return histogram; +} + void BlockchainLMDB::check_hard_fork_info() { LOG_PRINT_L3("BlockchainLMDB::" << __func__); diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index a3f32ffaa..6cd3e0e8f 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -280,6 +280,16 @@ public: virtual void pop_block(block& blk, std::vector& txs); virtual bool can_thread_bulk_indices() const { return true; } + + /** + * @brief return a histogram of outputs on the blockchain + * + * @param amounts optional set of amounts to lookup + * + * @return a set of amount/instances + */ + std::map get_output_histogram(const std::vector &amounts) const; + private: void do_resize(uint64_t size_increase=0); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 2f42e1db5..035afc61e 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3313,6 +3313,11 @@ bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, ui return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting); } +std::map Blockchain:: get_output_histogram(const std::vector &amounts) const +{ + return m_db->get_output_histogram(amounts); +} + void Blockchain::load_compiled_in_block_hashes() { if (m_fast_sync && get_blocks_dat_start(m_testnet) != nullptr) diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 94def1aa9..36e0fedfc 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -682,6 +682,15 @@ namespace cryptonote */ bool flush_txes_from_pool(const std::list &txids); + /** + * @brief return a histogram of outputs on the blockchain + * + * @param amounts optional set of amounts to lookup + * + * @return a set of amount/instances + */ + std::map get_output_histogram(const std::vector &amounts) const; + /** * @brief perform a check on all key images in the blockchain * diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 0b42257e7..166fe04ca 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -439,5 +439,23 @@ bool t_command_parser_executor::flush_txpool(const std::vector& arg return m_executor.flush_txpool(txid); } +bool t_command_parser_executor::output_histogram(const std::vector& args) +{ + if (args.size() > 2) return false; + + uint64_t min_count = 3; + uint64_t max_count = 0; + + if (args.size() >= 1) + { + min_count = boost::lexical_cast(args[0]); + } + if (args.size() >= 2) + { + max_count = boost::lexical_cast(args[1]); + } + return m_executor.output_histogram(min_count, max_count); +} + } // namespace daemonize diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index 51c55a8c0..11df92a5e 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -114,6 +114,8 @@ public: bool unban(const std::vector& args); bool flush_txpool(const std::vector& args); + + bool output_histogram(const std::vector& args); }; } // namespace daemonize diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 206de9d4a..aabc2f09a 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -214,6 +214,11 @@ t_command_server::t_command_server( , std::bind(&t_command_parser_executor::flush_txpool, &m_parser, p::_1) , "Flush a transaction from the tx pool by its txid, or the whole tx pool" ); + m_command_lookup.set_handler( + "output_histogram" + , std::bind(&t_command_parser_executor::output_histogram, &m_parser, p::_1) + , "Print output histogram (amount, instances)" + ); } bool t_command_server::process_command_str(const std::string& cmd) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 15ddc081f..933c93ed7 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -1203,5 +1203,41 @@ bool t_rpc_command_executor::flush_txpool(const std::string &txid) return true; } +bool t_rpc_command_executor::output_histogram(uint64_t min_count, uint64_t max_count) +{ + cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req; + cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response res; + std::string fail_message = "Unsuccessful"; + epee::json_rpc::error error_resp; + + req.min_count = min_count; + req.max_count = max_count; + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "get_output_histogram", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_output_histogram(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + std::sort(res.histogram.begin(), res.histogram.end(), + [](const cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry &e1, const cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry &e2)->bool { return e1.instances < e2.instances; }); + for (const auto &e: res.histogram) + { + tools::msg_writer() << e.instances << " " << cryptonote::print_money(e.amount); + } + + return true; +} + }// namespace daemonize diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index bc3f2d5c5..7e73e7faf 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -132,6 +132,8 @@ public: bool unban(const std::string &ip); bool flush_txpool(const std::string &txid); + + bool output_histogram(uint64_t min_count, uint64_t max_count); }; } // namespace daemonize diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 6b625e77b..5350b6fe0 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1041,6 +1041,38 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::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) + { + if(!check_core_busy()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + + std::map histogram; + try + { + histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts); + } + catch (const std::exception &e) + { + res.status = "Failed to get output histogram"; + return true; + } + + res.histogram.clear(); + res.histogram.reserve(histogram.size()); + for (const auto &i: histogram) + { + if (i.second >= req.min_count && (i.second <= req.max_count || req.max_count == 0)) + res.histogram.push_back(COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry(i.first, i.second)); + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_fast_exit(const COMMAND_RPC_FAST_EXIT::request& req, COMMAND_RPC_FAST_EXIT::response& res) { cryptonote::core::set_fast_exit(); diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index f79087030..5c3707209 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -109,6 +109,7 @@ namespace cryptonote MAP_JON_RPC_WE("setbans", on_set_bans, COMMAND_RPC_SETBANS) MAP_JON_RPC_WE("getbans", on_get_bans, COMMAND_RPC_GETBANS) MAP_JON_RPC_WE("flush_txpool", on_flush_txpool, COMMAND_RPC_FLUSH_TRANSACTION_POOL) + MAP_JON_RPC_WE("get_output_histogram", on_get_output_histogram, COMMAND_RPC_GET_OUTPUT_HISTOGRAM) END_JSON_RPC_MAP() END_URI_MAP2() @@ -149,6 +150,7 @@ namespace cryptonote bool on_set_bans(const COMMAND_RPC_SETBANS::request& req, COMMAND_RPC_SETBANS::response& res, epee::json_rpc::error& error_resp); bool on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp); 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); + 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); //----------------------- private: diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 72e399ec4..6d4dd1252 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -986,5 +986,46 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; }; + + struct COMMAND_RPC_GET_OUTPUT_HISTOGRAM + { + struct request + { + std::vector amounts; + uint64_t min_count; + uint64_t max_count; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amounts); + KV_SERIALIZE(min_count); + KV_SERIALIZE(max_count); + END_KV_SERIALIZE_MAP() + }; + + struct entry + { + uint64_t amount; + uint64_t instances; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount); + KV_SERIALIZE(instances); + END_KV_SERIALIZE_MAP() + + entry(uint64_t amount, uint64_t instances): amount(amount), instances(instances) {} + entry() {} + }; + + struct response + { + std::string status; + std::vector histogram; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(histogram) + END_KV_SERIALIZE_MAP() + }; + }; } diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index 50e0e5ae8..c0ee5fff8 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -108,6 +108,7 @@ public: virtual bool for_all_transactions(std::function) const { return true; } virtual bool for_all_outputs(std::function f) const { return true; } virtual bool is_read_only() const { return false; } + virtual std::map get_output_histogram() const { return std::map(); } virtual void add_block( const block& blk , const size_t& block_size -- cgit v1.2.3 From 12146daeed66fc30319c481a378c8d317b49b4db Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 21:15:47 +0000 Subject: wallet: change sweep_dust to sweep_unmixable With the change in mixin rules for v2, the "annoying" outputs are slightly changed. There is high correlation between dust and unmixable, but no equivalence. --- src/simplewallet/simplewallet.cpp | 35 ++++++++----- src/simplewallet/simplewallet.h | 2 +- src/wallet/wallet2.cpp | 104 +++++++++++++++++++++++++++++++++----- src/wallet/wallet2.h | 7 ++- src/wallet/wallet_errors.h | 9 ++++ src/wallet/wallet_rpc_server.cpp | 2 +- 6 files changed, 129 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 1856118f7..dd166ede5 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -541,7 +541,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), tr("Show blockchain height")); m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), tr("transfer [] [ ... ] [payment_id] - Transfer ,... to ,... , respectively. is the number of extra inputs to include for untraceability (from 0 to maximum available)")); m_cmd_binder.set_handler("transfer_new", boost::bind(&simple_wallet::transfer_new, this, _1), tr("Same as transfer, but using a new transaction building algorithm")); - m_cmd_binder.set_handler("sweep_dust", boost::bind(&simple_wallet::sweep_dust, this, _1), tr("Send all dust outputs to yourself with mixin 0")); + m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::sweep_unmixable, this, _1), tr("Send all unmixable outputs to yourself with mixin 0")); m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log - Change current log detail level, <0-4>")); m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), tr("Show current wallet public address")); m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::print_integrated_address, this, _1), tr("integrated_address [PID] - Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID")); @@ -1722,8 +1722,7 @@ bool simple_wallet::refresh(const std::vector& args) bool simple_wallet::show_balance(const std::vector& args/* = std::vector()*/) { success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance()) << ", " - << tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance()) << ", " - << tr("including unlocked dust: ") << print_money(m_wallet->unlocked_dust_balance(tools::tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD))); + << tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance()); return true; } //---------------------------------------------------------------------------------------------------- @@ -2208,7 +2207,7 @@ bool simple_wallet::transfer_new(const std::vector &args_) } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::sweep_dust(const std::vector &args_) +bool simple_wallet::sweep_unmixable(const std::vector &args_) { if (!try_connect_to_daemon()) return true; @@ -2221,28 +2220,37 @@ bool simple_wallet::sweep_dust(const std::vector &args_) try { - uint64_t total_dust = m_wallet->unlocked_dust_balance(tools::tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD)); - // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_dust_sweep_transactions(); + auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(); + + if (ptx_vector.empty()) + { + fail_msg_writer() << tr("No unmixable outputs found"); + return true; + } // give user total and fee, and prompt to confirm - uint64_t total_fee = 0; + uint64_t total_fee = 0, total_unmixable = 0; for (size_t n = 0; n < ptx_vector.size(); ++n) { total_fee += ptx_vector[n].fee; + for (const auto &vin: ptx_vector[n].tx.vin) + { + if (vin.type() == typeid(txin_to_key)) + total_unmixable += boost::get(vin).amount; + } } - std::string prompt_str = tr("Sweeping ") + print_money(total_dust); + std::string prompt_str = tr("Sweeping ") + print_money(total_unmixable); if (ptx_vector.size() > 1) { prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No)")) % - print_money(total_dust) % + print_money(total_unmixable) % ((unsigned long long)ptx_vector.size()) % print_money(total_fee)).str(); } else { prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No)")) % - print_money(total_dust) % + print_money(total_unmixable) % print_money(total_fee)).str(); } std::string accepted = command_line::input_line(prompt_str); @@ -2285,11 +2293,12 @@ bool simple_wallet::sweep_dust(const std::vector &args_) } catch (const tools::error::not_enough_money& e) { - fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % + fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee).\n%s")) % print_money(e.available()) % print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % - print_money(e.fee()); + print_money(e.fee()) % + tr("This is usually due to dust which is so small it cannot pay for itself in fees"); } catch (const tools::error::not_enough_outs_to_mix& e) { diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 7dadb8536..21bbfa566 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -121,7 +121,7 @@ namespace cryptonote bool transfer_main(bool new_algorithm, const std::vector &args); bool transfer(const std::vector &args); bool transfer_new(const std::vector &args); - bool sweep_dust(const std::vector &args); + bool sweep_unmixable(const std::vector &args); std::vector> split_amounts( std::vector dsts, size_t num_splits ); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index aa638143c..7d308e615 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2508,7 +2508,7 @@ uint64_t wallet2::unlocked_dust_balance(const tx_dust_policy &dust_policy) const } template -void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector &extra, cryptonote::transaction& tx, pending_tx &ptx) +void wallet2::transfer_from(const std::vector &outs, size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector &extra, cryptonote::transaction& tx, pending_tx &ptx) { using namespace cryptonote; @@ -2518,6 +2518,19 @@ void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t n // throw if there are none uint64_t money = 0; std::list selected_transfers; +#if 1 + for (size_t n = 0; n < outs.size(); ++n) + { + const transfer_details& td = m_transfers[outs[n]]; + if (!td.m_spent) + { + selected_transfers.push_back (m_transfers.begin() + outs[n]); + money += td.amount(); + if (selected_transfers.size() >= num_outputs) + break; + } + } +#else for (transfer_container::iterator i = m_transfers.begin(); i != m_transfers.end(); ++i) { const transfer_details& td = *i; @@ -2529,6 +2542,7 @@ void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t n break; } } +#endif // we don't allow no output to self, easier, but one may want to burn the dust if = fee THROW_WALLET_EXCEPTION_IF(money <= needed_fee, error::not_enough_money, money, needed_fee, needed_fee); @@ -2622,8 +2636,8 @@ bool wallet2::use_fork_rules(uint8_t version) r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, false, "Failed to connect to daemon"); - CHECK_AND_ASSERT_MES(res.status != CORE_RPC_STATUS_BUSY, false, "Failed to connect to daemon"); - CHECK_AND_ASSERT_MES(res.status == CORE_RPC_STATUS_OK, false, "Failed to get hard fork status"); + CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, false, "Failed to connect to daemon"); + CHECK_AND_ASSERT_MES(resp_t.result.status == CORE_RPC_STATUS_OK, false, "Failed to get hard fork status"); bool close_enough = res.height >= resp_t.result.earliest_height - 10; // start using the rules a bit beforehand if (close_enough) @@ -2641,20 +2655,84 @@ uint64_t wallet2::get_upper_tranaction_size_limit() return ((full_reward_zone * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::create_dust_sweep_transactions() +std::vector wallet2::select_available_outputs(std::function f) +{ + std::vector outputs; + size_t n = 0; + for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i, ++n) + { + if (i->m_spent) + continue; + if (!is_transfer_unlocked(*i)) + continue; + if (f(*i)) + outputs.push_back(n); + } + return outputs; +} +//---------------------------------------------------------------------------------------------------- +std::vector wallet2::get_unspent_amounts_vector() +{ + std::set set; + for (const auto &td: m_transfers) + { + if (!td.m_spent) + set.insert(td.amount()); + } + std::vector vector; + vector.reserve(set.size()); + for (const auto &i: set) + { + vector.push_back(i); + } + return vector; +} +//---------------------------------------------------------------------------------------------------- +std::vector wallet2::select_available_unmixable_outputs() +{ + // request all outputs with at least 3 instances, so we can use mixin 2 with + epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); + epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); + m_daemon_rpc_mutex.lock(); + req_t.jsonrpc = "2.0"; + req_t.id = epee::serialization::storage_entry(0); + req_t.method = "get_output_histogram"; + req_t.params.amounts = get_unspent_amounts_vector(); + req_t.params.min_count = 3; + req_t.params.max_count = 0; + bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + m_daemon_rpc_mutex.unlock(); + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_unmixable_outputs"); + THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram"); + THROW_WALLET_EXCEPTION_IF(resp_t.result.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.result.status); + + std::set mixable; + for (const auto &i: resp_t.result.histogram) + { + mixable.insert(i.amount); + } + + return select_available_outputs([mixable](const transfer_details &td) { + const uint64_t amount = td.amount(); + if (mixable.find(amount) == mixable.end()) + return true; + return false; + }); +} +//---------------------------------------------------------------------------------------------------- +std::vector wallet2::create_unmixable_sweep_transactions() { // From hard fork 1, we don't consider small amounts to be dust anymore const bool hf1_rules = use_fork_rules(2); // first hard fork has version 2 tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD); - size_t num_dust_outputs = 0; - for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i) + // may throw + std::vector unmixable_outputs = select_available_unmixable_outputs(); + size_t num_dust_outputs = unmixable_outputs.size(); + + if (num_dust_outputs == 0) { - const transfer_details& td = *i; - if (!td.m_spent && (td.amount() < dust_policy.dust_threshold || !is_valid_decomposed_amount(td.amount())) && is_transfer_unlocked(td)) - { - num_dust_outputs++; - } + return std::vector(); } // failsafe split attempt counter @@ -2679,13 +2757,13 @@ std::vector wallet2::create_dust_sweep_transactions() uint64_t needed_fee = 0; do { - transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); + transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); auto txBlob = t_serializable_object_to_blob(ptx.tx); needed_fee = calculate_fee(txBlob); // reroll the tx with the actual amount minus the fee // if there's not enough for the fee, it'll throw - transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx); + transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx); txBlob = t_serializable_object_to_blob(ptx.tx); needed_fee = calculate_fee(txBlob); } while (ptx.fee < needed_fee); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e7b002925..2b6cdab92 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -280,7 +280,7 @@ namespace tools void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra); void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx); template - void transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx); + void transfer_from(const std::vector &outs, size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx); template void transfer_selected(const std::vector& dsts, const std::list selected_transfers, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx); @@ -289,7 +289,7 @@ namespace tools void commit_tx(std::vector& ptx_vector); std::vector create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector extra); std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra); - std::vector create_dust_sweep_transactions(); + std::vector create_unmixable_sweep_transactions(); bool check_connection(); void get_transfers(wallet2::transfer_container& incoming_transfers) const; void get_payments(const crypto::hash& payment_id, std::list& payments, uint64_t min_height = 0) const; @@ -402,6 +402,9 @@ namespace tools void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; uint64_t get_upper_tranaction_size_limit(); void check_pending_txes(); + std::vector get_unspent_amounts_vector(); + std::vector select_available_outputs(std::function f); + std::vector select_available_unmixable_outputs(); cryptonote::account_base m_account; std::string m_daemon_address; diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 6074e0858..652b19499 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -76,6 +76,7 @@ namespace tools // daemon_busy // no_connection_to_daemon // is_key_image_spent_error + // get_histogram_error // wallet_files_doesnt_correspond // // * - class with protected ctor @@ -600,6 +601,14 @@ namespace tools } }; //---------------------------------------------------------------------------------------------------- + struct get_histogram_error : public wallet_rpc_error + { + explicit get_histogram_error(std::string&& loc, const std::string& request) + : wallet_rpc_error(std::move(loc), "failed to get output histogram", request) + { + } + }; + //---------------------------------------------------------------------------------------------------- struct wallet_files_doesnt_correspond : public wallet_logic_error { explicit wallet_files_doesnt_correspond(std::string&& loc, const std::string& keys_file, const std::string& wallet_file) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 418de327c..83e1f7535 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -347,7 +347,7 @@ namespace tools try { - std::vector ptx_vector = m_wallet.create_dust_sweep_transactions(); + std::vector ptx_vector = m_wallet.create_unmixable_sweep_transactions(); m_wallet.commit_tx(ptx_vector); -- cgit v1.2.3 From 0be6e08dd0faf5f7e3492652f00b8904e7e8216d Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 23:22:57 +0000 Subject: wallet: do not leak owned amounts to the daemon unless --trusted-daemon This will be slower, though more private. New trusted_daemon parameter to the matching RPC call, false by default. --- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/wallet2.cpp | 9 +++++---- src/wallet/wallet2.h | 4 ++-- src/wallet/wallet_rpc_server.cpp | 2 +- src/wallet/wallet_rpc_server_commands_defs.h | 2 ++ 5 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index dd166ede5..04170df62 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2221,7 +2221,7 @@ bool simple_wallet::sweep_unmixable(const std::vector &args_) try { // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(); + auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon); if (ptx_vector.empty()) { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7d308e615..3ec2265fa 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2688,7 +2688,7 @@ std::vector wallet2::get_unspent_amounts_vector() return vector; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::select_available_unmixable_outputs() +std::vector wallet2::select_available_unmixable_outputs(bool trusted_daemon) { // request all outputs with at least 3 instances, so we can use mixin 2 with epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); @@ -2697,7 +2697,8 @@ std::vector wallet2::select_available_unmixable_outputs() req_t.jsonrpc = "2.0"; req_t.id = epee::serialization::storage_entry(0); req_t.method = "get_output_histogram"; - req_t.params.amounts = get_unspent_amounts_vector(); + if (trusted_daemon) + req_t.params.amounts = get_unspent_amounts_vector(); req_t.params.min_count = 3; req_t.params.max_count = 0; bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); @@ -2720,14 +2721,14 @@ std::vector wallet2::select_available_unmixable_outputs() }); } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::create_unmixable_sweep_transactions() +std::vector wallet2::create_unmixable_sweep_transactions(bool trusted_daemon) { // From hard fork 1, we don't consider small amounts to be dust anymore const bool hf1_rules = use_fork_rules(2); // first hard fork has version 2 tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD); // may throw - std::vector unmixable_outputs = select_available_unmixable_outputs(); + std::vector unmixable_outputs = select_available_unmixable_outputs(trusted_daemon); size_t num_dust_outputs = unmixable_outputs.size(); if (num_dust_outputs == 0) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2b6cdab92..566be59c6 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -289,7 +289,7 @@ namespace tools void commit_tx(std::vector& ptx_vector); std::vector create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector extra); std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra); - std::vector create_unmixable_sweep_transactions(); + std::vector create_unmixable_sweep_transactions(bool trusted_daemon); bool check_connection(); void get_transfers(wallet2::transfer_container& incoming_transfers) const; void get_payments(const crypto::hash& payment_id, std::list& payments, uint64_t min_height = 0) const; @@ -404,7 +404,7 @@ namespace tools void check_pending_txes(); std::vector get_unspent_amounts_vector(); std::vector select_available_outputs(std::function f); - std::vector select_available_unmixable_outputs(); + std::vector select_available_unmixable_outputs(bool trusted_daemon); cryptonote::account_base m_account; std::string m_daemon_address; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 83e1f7535..d7d99c2ae 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -347,7 +347,7 @@ namespace tools try { - std::vector ptx_vector = m_wallet.create_unmixable_sweep_transactions(); + std::vector ptx_vector = m_wallet.create_unmixable_sweep_transactions(req.trusted_daemon); m_wallet.commit_tx(ptx_vector); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 40d6fd8f8..2c4e26406 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -178,9 +178,11 @@ namespace wallet_rpc struct request { bool get_tx_keys; + bool trusted_daemon; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(get_tx_keys) + KV_SERIALIZE(trusted_daemon) END_KV_SERIALIZE_MAP() }; -- cgit v1.2.3 From 25672d3f10e71f4db36d9497e2440f2ac26a6e01 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 23:32:45 +0000 Subject: wallet: pass std::function by const ref, not value Because we can. --- src/wallet/wallet2.cpp | 2 +- src/wallet/wallet2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3ec2265fa..6fd77eead 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2655,7 +2655,7 @@ uint64_t wallet2::get_upper_tranaction_size_limit() return ((full_reward_zone * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::select_available_outputs(std::function f) +std::vector wallet2::select_available_outputs(const std::function &f) { std::vector outputs; size_t n = 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 566be59c6..fc700a3de 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -403,7 +403,7 @@ namespace tools uint64_t get_upper_tranaction_size_limit(); void check_pending_txes(); std::vector get_unspent_amounts_vector(); - std::vector select_available_outputs(std::function f); + std::vector select_available_outputs(const std::function &f); std::vector select_available_unmixable_outputs(bool trusted_daemon); cryptonote::account_base m_account; -- cgit v1.2.3 From 878ab5d896c1a9cb5c50c36a0ded5da998c941d5 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 28 Mar 2016 16:46:19 +0100 Subject: wallet: fix --generate-from-keys saving as watch only --- src/wallet/wallet2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6fd77eead..363665024 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1214,7 +1214,7 @@ void wallet2::generate(const std::string& wallet_, const std::string& password, m_account_public_address = account_public_address; m_watch_only = false; - bool r = store_keys(m_keys_file, password, true); + bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); -- cgit v1.2.3