diff options
24 files changed, 258 insertions, 111 deletions
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index f0425278d..1864c77ad 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -841,21 +841,21 @@ namespace net_utils const char *ptr = m_header_cache.c_str(); CHECK_AND_ASSERT_MES(!memcmp(ptr, "HTTP/", 5), false, "Invalid first response line: " + m_header_cache); ptr += 5; - CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache); + CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache); unsigned long ul; char *end; ul = strtoul(ptr, &end, 10); CHECK_AND_ASSERT_MES(ul <= INT_MAX && *end =='.', false, "Invalid first response line: " + m_header_cache); m_response_info.m_http_ver_hi = ul; ptr = end + 1; - CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr); + CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr); ul = strtoul(ptr, &end, 10); CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(*end), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr); m_response_info.m_http_ver_lo = ul; ptr = end + 1; while (isblank(*ptr)) ++ptr; - CHECK_AND_ASSERT_MES(isdigit(*ptr), false, "Invalid first response line: " + m_header_cache); + CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache); ul = strtoul(ptr, &end, 10); CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(*end), false, "Invalid first response line: " + m_header_cache); m_response_info.m_response_code = ul; diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h index 19720ea8b..e100452ca 100644 --- a/contrib/epee/include/span.h +++ b/contrib/epee/include/span.h @@ -31,6 +31,7 @@ #include <algorithm> #include <cstdint> #include <memory> +#include <string> #include <type_traits> namespace epee diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h index 69b650cd4..b5c4138c5 100644 --- a/contrib/epee/include/storages/parserse_base_utils.h +++ b/contrib/epee/include/storages/parserse_base_utils.h @@ -42,13 +42,14 @@ namespace misc_utils // 4: alpha // 8: whitespace // 16: allowed in float but doesn't necessarily mean it's a float + // 32: \ and " (end of verbatim string) static const constexpr uint8_t lut[256]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, // 16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32 - 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48 + 8, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, // 64 0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 80 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 96 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 32, 0, 0, 0, // 96 0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 112 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -130,7 +131,7 @@ namespace misc_utils std::string::const_iterator it = star_end_string; ++it; std::string::const_iterator fi = it; - while (fi != buf_end && *fi != '\\' && *fi != '\"') + while (fi != buf_end && ((lut[(uint8_t)*fi] & 32)) == 0) ++fi; val.assign(it, fi); val.reserve(std::distance(star_end_string, buf_end)); diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h index 36bb28627..e54cda828 100644 --- a/contrib/epee/include/storages/portable_storage_val_converters.h +++ b/contrib/epee/include/storages/portable_storage_val_converters.h @@ -144,7 +144,7 @@ POP_WARNINGS { MTRACE("Converting std::string to uint64_t. Source: " << from); // String only contains digits - if(std::all_of(from.begin(), from.end(), ::isdigit)) + if(std::all_of(from.begin(), from.end(), epee::misc_utils::parse::isdigit)) to = boost::lexical_cast<uint64_t>(from); // MyMonero ISO 8061 timestamp (2017-05-06T16:27:06Z) else if (boost::regex_match (from, boost::regex("\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\dZ"))) diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 2e65876e6..da47b7d55 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -42,6 +42,8 @@ #include <type_traits> #include <boost/lexical_cast.hpp> #include <boost/algorithm/string/predicate.hpp> +#include "misc_log_ex.h" +#include "storages/parserse_base_utils.h" #include "hex.h" #include "memwipe.h" #include "mlocker.h" @@ -126,7 +128,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized) { for (char c : str_id) { - if (!std::isdigit(c)) + if (!epee::misc_utils::parse::isdigit(c)) return false; } } diff --git a/contrib/epee/src/net_ssl.cpp b/contrib/epee/src/net_ssl.cpp index eb0b0ad65..cb65121bd 100644 --- a/contrib/epee/src/net_ssl.cpp +++ b/contrib/epee/src/net_ssl.cpp @@ -46,8 +46,7 @@ namespace { void operator()(BIO* ptr) const noexcept { - if (ptr) - BIO_free(ptr); + BIO_free(ptr); } }; using openssl_bio = std::unique_ptr<BIO, openssl_bio_free>; @@ -56,12 +55,28 @@ namespace { void operator()(EVP_PKEY* ptr) const noexcept { - if (ptr) - EVP_PKEY_free(ptr); + EVP_PKEY_free(ptr); } }; using openssl_pkey = std::unique_ptr<EVP_PKEY, openssl_pkey_free>; + struct openssl_rsa_free + { + void operator()(RSA* ptr) const noexcept + { + RSA_free(ptr); + } + }; + using openssl_rsa = std::unique_ptr<RSA, openssl_rsa_free>; + + struct openssl_bignum_free + { + void operator()(BIGNUM* ptr) const noexcept + { + BN_free(ptr); + } + }; + using openssl_bignum = std::unique_ptr<BIGNUM, openssl_bignum_free>; } namespace epee @@ -81,19 +96,37 @@ bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert) } openssl_pkey pkey_deleter{pkey}; - RSA *rsa = RSA_generate_key(4096, RSA_F4, NULL, NULL); + openssl_rsa rsa{RSA_new()}; if (!rsa) { + MERROR("Error allocating RSA private key"); + return false; + } + + openssl_bignum exponent{BN_new()}; + if (!exponent) + { + MERROR("Error allocating exponent"); + return false; + } + + BN_set_word(exponent.get(), RSA_F4); + + if (RSA_generate_key_ex(rsa.get(), 4096, exponent.get(), nullptr) != 1) + { MERROR("Error generating RSA private key"); return false; } - if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) // The RSA will be automatically freed when the EVP_PKEY structure is freed. + + if (EVP_PKEY_assign_RSA(pkey, rsa.get()) <= 0) { MERROR("Error assigning RSA private key"); - RSA_free(rsa); return false; } + // the RSA key is now managed by the EVP_PKEY structure + (void)rsa.release(); + cert = X509_new(); if (!cert) { diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp index dda498088..189eb85eb 100644 --- a/src/common/perf_timer.cpp +++ b/src/common/perf_timer.cpp @@ -88,7 +88,7 @@ namespace tools namespace tools { -el::Level performance_timer_log_level = el::Level::Debug; +el::Level performance_timer_log_level = el::Level::Info; static __thread std::vector<LoggingPerformanceTimer*> *performance_timers = NULL; @@ -97,8 +97,8 @@ void set_performance_timer_log_level(el::Level level) if (level != el::Level::Debug && level != el::Level::Trace && level != el::Level::Info && level != el::Level::Warning && level != el::Level::Error && level != el::Level::Fatal) { - MERROR("Wrong log level: " << el::LevelHelper::convertToString(level) << ", using Debug"); - level = el::Level::Debug; + MERROR("Wrong log level: " << el::LevelHelper::convertToString(level) << ", using Info"); + level = el::Level::Info; } performance_timer_log_level = level; } diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 094057b1f..fecd67729 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1090,7 +1090,14 @@ namespace cryptonote // we still need the size if (blob_size) - *blob_size = get_object_blobsize(t); + { + if (!t.is_blob_size_valid()) + { + t.blob_size = blob.size(); + t.set_blob_size_valid(true); + } + *blob_size = t.blob_size; + } return true; } @@ -1143,21 +1150,37 @@ namespace cryptonote return blob; } //--------------------------------------------------------------- - bool calculate_block_hash(const block& b, crypto::hash& res) + bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob) { + blobdata bd; + if (!blob) + { + bd = block_to_blob(b); + blob = &bd; + } + + bool hash_result = get_object_hash(get_block_hashing_blob(b), res); + if (!hash_result) + return false; + + if (b.miner_tx.vin.size() == 1 && b.miner_tx.vin[0].type() == typeid(cryptonote::txin_gen)) + { + const cryptonote::txin_gen &txin_gen = boost::get<cryptonote::txin_gen>(b.miner_tx.vin[0]); + if (txin_gen.height != 202612) + return true; + } + // EXCEPTION FOR BLOCK 202612 const std::string correct_blob_hash_202612 = "3a8a2b3a29b50fc86ff73dd087ea43c6f0d6b8f936c849194d5c84c737903966"; const std::string existing_block_id_202612 = "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"; - crypto::hash block_blob_hash = get_blob_hash(block_to_blob(b)); + crypto::hash block_blob_hash = get_blob_hash(*blob); if (string_tools::pod_to_hex(block_blob_hash) == correct_blob_hash_202612) { string_tools::hex_to_pod(existing_block_id_202612, res); return true; } - bool hash_result = get_object_hash(get_block_hashing_blob(b), res); - if (hash_result) { // make sure that we aren't looking at a block with the 202612 block id but not the correct blobdata if (string_tools::pod_to_hex(res) == existing_block_id_202612) @@ -1200,9 +1223,9 @@ namespace cryptonote bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height) { // block 202612 bug workaround - const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000"; if (height == 202612) { + static const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000"; string_tools::hex_to_pod(longhash_202612, res); return true; } @@ -1239,7 +1262,7 @@ namespace cryptonote return p; } //--------------------------------------------------------------- - bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash) { std::stringstream ss; ss << b_blob; @@ -1248,9 +1271,26 @@ namespace cryptonote CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob"); b.invalidate_hashes(); b.miner_tx.invalidate_hashes(); + if (block_hash) + { + calculate_block_hash(b, *block_hash, &b_blob); + ++block_hashes_calculated_count; + b.hash = *block_hash; + b.set_hash_valid(true); + } return true; } //--------------------------------------------------------------- + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) + { + return parse_and_validate_block_from_blob(b_blob, b, NULL); + } + //--------------------------------------------------------------- + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash) + { + return parse_and_validate_block_from_blob(b_blob, b, &block_hash); + } + //--------------------------------------------------------------- blobdata block_to_blob(const block& b) { return t_serializable_object_to_blob(b); @@ -1286,6 +1326,7 @@ namespace cryptonote crypto::hash get_tx_tree_hash(const block& b) { std::vector<crypto::hash> txs_ids; + txs_ids.reserve(1 + b.tx_hashes.size()); crypto::hash h = null_hash; size_t bl_sz = 0; get_transaction_hash(b.miner_tx, h, bl_sz); diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 40a9907be..3f8eef076 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -114,12 +114,14 @@ namespace cryptonote crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash); blobdata get_block_hashing_blob(const block& b); - bool calculate_block_hash(const block& b, crypto::hash& res); + bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob = NULL); bool get_block_hash(const block& b, crypto::hash& res); crypto::hash get_block_hash(const block& b); bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height); crypto::hash get_block_longhash(const block& b, uint64_t height); + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); uint64_t get_outs_money_amount(const transaction& tx); bool check_inputs_types_supported(const transaction& tx); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 83d3044f8..73c60760b 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3176,6 +3176,7 @@ bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const if (version >= HF_VERSION_DYNAMIC_FEE) { median = m_current_block_cumul_weight_limit / 2; + const uint64_t blockchain_height = m_db->height(); already_generated_coins = blockchain_height ? m_db->get_block_already_generated_coins(blockchain_height - 1) : 0; if (!get_block_reward(median, 1, already_generated_coins, base_reward, version)) return false; @@ -4332,8 +4333,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete for (unsigned int j = 0; j < batches; j++, ++blockidx) { block &block = blocks[blockidx]; + crypto::hash block_hash; - if (!parse_and_validate_block_from_blob(it->block, block)) + if (!parse_and_validate_block_from_blob(it->block, block, block_hash)) return false; // check first block and skip all blocks if its not chained properly @@ -4346,7 +4348,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete return true; } } - if (have_block(get_block_hash(block))) + if (have_block(block_hash)) blocks_exist = true; std::advance(it, 1); @@ -4356,11 +4358,12 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete for (unsigned i = 0; i < extra && !blocks_exist; i++, blockidx++) { block &block = blocks[blockidx]; + crypto::hash block_hash; - if (!parse_and_validate_block_from_blob(it->block, block)) + if (!parse_and_validate_block_from_blob(it->block, block, block_hash)) return false; - if (have_block(get_block_hash(block))) + if (have_block(block_hash)) blocks_exist = true; std::advance(it, 1); diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index da413bbe2..8ab7d174c 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1432,7 +1432,8 @@ namespace cryptonote block lb; if (!b) { - if(!parse_and_validate_block_from_blob(block_blob, lb)) + crypto::hash block_hash; + if(!parse_and_validate_block_from_blob(block_blob, lb, block_hash)) { LOG_PRINT_L1("Failed to parse and validate new block"); bvc.m_verifivation_failed = true; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 32f0afceb..b7a50783a 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -48,6 +48,17 @@ #define MONERO_DEFAULT_LOG_CATEGORY "net.cn" #define MLOG_P2P_MESSAGE(x) MCINFO("net.p2p.msg", context << x) +#define MLOGIF_P2P_MESSAGE(init, test, x) \ + do { \ + const auto level = el::Level::Info; \ + const char *cat = "net.p2p.msg"; \ + if (ELPP->vRegistry()->allowed(level, cat)) { \ + init; \ + if (test) \ + el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << x; \ + } \ + } while(0) + #define MLOG_PEER_STATE(x) \ MCINFO(MONERO_DEFAULT_LOG_CATEGORY, context << "[" << epee::string_tools::to_string_hex(context.m_pruning_seed) << "] state: " << x << " in state " << cryptonote::get_protocol_state_string(context.m_state)) @@ -418,7 +429,7 @@ namespace cryptonote template<class t_core> int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context) { - MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (" << arg.b.txs.size() << " txes)"); + MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); if(context.m_state != cryptonote_connection_context::state_normal) return 1; if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks @@ -488,7 +499,7 @@ namespace cryptonote template<class t_core> int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context) { - MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); + MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); if(context.m_state != cryptonote_connection_context::state_normal) return 1; if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks @@ -858,6 +869,9 @@ namespace cryptonote int t_cryptonote_protocol_handler<t_core>::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context) { MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)"); + for (const auto &blob: arg.txs) + MLOGIF_P2P_MESSAGE(cryptonote::transaction tx; crypto::hash hash; bool ret = cryptonote::parse_and_validate_tx_from_blob(blob, tx, hash);, ret, "Including transaction " << hash); + if(context.m_state != cryptonote_connection_context::state_normal) return 1; @@ -995,7 +1009,8 @@ namespace cryptonote return 1; } - if(!parse_and_validate_block_from_blob(block_entry.block, b)) + crypto::hash block_hash; + if(!parse_and_validate_block_from_blob(block_entry.block, b, block_hash)) { LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: " << epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection"); @@ -1014,7 +1029,6 @@ namespace cryptonote if (start_height == std::numeric_limits<uint64_t>::max()) start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height; - const crypto::hash block_hash = get_block_hash(b); auto req_it = context.m_requested_objects.find(block_hash); if(req_it == context.m_requested_objects.end()) { @@ -1121,13 +1135,13 @@ namespace cryptonote << ", we need " << previous_height); block new_block; - if (!parse_and_validate_block_from_blob(blocks.back().block, new_block)) + crypto::hash last_block_hash; + if (!parse_and_validate_block_from_blob(blocks.back().block, new_block, last_block_hash)) { MERROR(context << "Failed to parse block, but it should already have been parsed"); m_block_queue.remove_spans(span_connection_id, start_height); continue; } - const crypto::hash last_block_hash = cryptonote::get_block_hash(new_block); if (m_core.have_block(last_block_hash)) { const uint64_t subchain_height = start_height + blocks.size(); diff --git a/src/lmdb/database.cpp b/src/lmdb/database.cpp index c6b244671..ccab1902a 100644 --- a/src/lmdb/database.cpp +++ b/src/lmdb/database.cpp @@ -46,7 +46,7 @@ namespace lmdb { namespace { - constexpr const std::size_t max_resize = 1 * 1024 * 1024 * 1024; // 1 GB + constexpr const mdb_size_t max_resize = 1 * 1024 * 1024 * 1024; // 1 GB void acquire_context(context& ctx) noexcept { while (ctx.lock.test_and_set()); @@ -136,7 +136,7 @@ namespace lmdb MDB_envinfo info{}; MONERO_LMDB_CHECK(mdb_env_info(handle(), &info)); - const std::size_t resize = std::min(info.me_mapsize, max_resize); + const mdb_size_t resize = std::min(info.me_mapsize, max_resize); const int err = mdb_env_set_mapsize(handle(), info.me_mapsize + resize); ctx.lock.clear(); if (err) diff --git a/src/lmdb/value_stream.cpp b/src/lmdb/value_stream.cpp index 1024deb06..604140e47 100644 --- a/src/lmdb/value_stream.cpp +++ b/src/lmdb/value_stream.cpp @@ -36,9 +36,9 @@ namespace lmdb { namespace stream { - std::size_t count(MDB_cursor* cur) + mdb_size_t count(MDB_cursor* cur) { - std::size_t out = 0; + mdb_size_t out = 0; if (cur) { const int rc = mdb_cursor_count(cur, &out); diff --git a/src/lmdb/value_stream.h b/src/lmdb/value_stream.h index c9977221f..01090aa67 100644 --- a/src/lmdb/value_stream.h +++ b/src/lmdb/value_stream.h @@ -43,7 +43,7 @@ namespace lmdb \throw std::system_error if unexpected LMDB error. \return 0 if `cur == nullptr`, otherwise count of values at current key. */ - std::size_t count(MDB_cursor* cur); + mdb_size_t count(MDB_cursor* cur); /*! Calls `mdb_cursor_get` and does some error checking. diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index f5f1a2f9a..2e7ef3e1b 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -646,30 +646,61 @@ namespace cryptonote e.prunable_hash = epee::string_tools::pod_to_hex(std::get<2>(tx)); if (req.split || req.prune || std::get<3>(tx).empty()) { + // use splitted form with pruned and prunable (filled only when prune=false and the daemon has it), leaving as_hex as empty e.pruned_as_hex = string_tools::buff_to_hex_nodelimer(std::get<1>(tx)); if (!req.prune) e.prunable_as_hex = string_tools::buff_to_hex_nodelimer(std::get<3>(tx)); - } - else - { - cryptonote::blobdata tx_data; - if (req.prune) - tx_data = std::get<1>(tx); - else - tx_data = std::get<1>(tx) + std::get<3>(tx); - e.as_hex = string_tools::buff_to_hex_nodelimer(tx_data); - if (req.decode_as_json && !tx_data.empty()) + if (req.decode_as_json) { + cryptonote::blobdata tx_data; cryptonote::transaction t; - if (cryptonote::parse_and_validate_tx_from_blob(tx_data, t)) + if (req.prune || std::get<3>(tx).empty()) { - if (req.prune) + // decode pruned tx to JSON + tx_data = std::get<1>(tx); + if (cryptonote::parse_and_validate_tx_base_from_blob(tx_data, t)) { pruned_transaction pruned_tx{t}; e.as_json = obj_to_json_str(pruned_tx); } else + { + res.status = "Failed to parse and validate pruned tx from blob"; + return true; + } + } + else + { + // decode full tx to JSON + tx_data = std::get<1>(tx) + std::get<3>(tx); + if (cryptonote::parse_and_validate_tx_from_blob(tx_data, t)) + { e.as_json = obj_to_json_str(t); + } + else + { + res.status = "Failed to parse and validate tx from blob"; + return true; + } + } + } + } + else + { + // use non-splitted form, leaving pruned_as_hex and prunable_as_hex as empty + cryptonote::blobdata tx_data = std::get<1>(tx) + std::get<3>(tx); + e.as_hex = string_tools::buff_to_hex_nodelimer(tx_data); + if (req.decode_as_json) + { + cryptonote::transaction t; + if (cryptonote::parse_and_validate_tx_from_blob(tx_data, t)) + { + e.as_json = obj_to_json_str(t); + } + else + { + res.status = "Failed to parse and validate tx from blob"; + return true; } } } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 8974bd1e0..9f7cc9c3b 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6654,7 +6654,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes, { const tx_destination_entry &entry = cd.splitted_dsts[d]; std::string address, standard_address = get_account_address_as_str(m_wallet->nettype(), entry.is_subaddress, entry.addr); - if (has_encrypted_payment_id && !entry.is_subaddress) + if (has_encrypted_payment_id && !entry.is_subaddress && standard_address != entry.original) { address = get_account_integrated_address_as_str(m_wallet->nettype(), entry.addr, payment_id8); address += std::string(" (" + standard_address + " with encrypted payment id " + epee::string_tools::pod_to_hex(payment_id8) + ")"); diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index def23aff0..d0fc21f51 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -127,6 +127,7 @@ if (BUILD_GUI_DEPS) ringct_basic checkpoints version + net device_trezor) foreach(lib ${libs_to_merge}) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0e82f1a91..54fbd9ca8 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2275,6 +2275,12 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans add_rings(tx); } //---------------------------------------------------------------------------------------------------- +bool wallet2::should_skip_block(const cryptonote::block &b, uint64_t height) const +{ + // 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 + return !(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height); +} +//---------------------------------------------------------------------------------------------------- void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache) { THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error, @@ -2284,7 +2290,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() && height >= m_refresh_from_block_height) + if (!should_skip_block(b, height)) { TIME_MEASURE_START(miner_tx_handle_time); if (m_refresh_type != RefreshNoCoinbase) @@ -2348,9 +2354,7 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids, uint64_t gra //---------------------------------------------------------------------------------------------------- void wallet2::parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const { - error = !cryptonote::parse_and_validate_block_from_blob(blob, bl); - if (!error) - bl_id = get_block_hash(bl); + error = !cryptonote::parse_and_validate_block_from_blob(blob, bl, bl_id); } //---------------------------------------------------------------------------------------------------- void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices) @@ -2416,6 +2420,11 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry { THROW_WALLET_EXCEPTION_IF(parsed_blocks[i].txes.size() != parsed_blocks[i].block.tx_hashes.size(), error::wallet_internal_error, "Mismatched parsed_blocks[i].txes.size() and parsed_blocks[i].block.tx_hashes.size()"); + if (should_skip_block(parsed_blocks[i].block, start_height + i)) + { + txidx += 1 + parsed_blocks[i].block.tx_hashes.size(); + continue; + } if (m_refresh_type != RefreshNoCoinbase) tpool.submit(&waiter, [&, i, txidx](){ cache_tx_data(parsed_blocks[i].block.miner_tx, get_transaction_hash(parsed_blocks[i].block.miner_tx), tx_cache_data[txidx]); }); ++txidx; @@ -2444,6 +2453,8 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry for (size_t i = 0; i < tx_cache_data.size(); ++i) { + if (tx_cache_data[i].empty()) + continue; tpool.submit(&waiter, [&hwdev, &gender, &tx_cache_data, i]() { auto &slot = tx_cache_data[i]; boost::unique_lock<hw::device> hwdev_lock(hwdev); @@ -2462,6 +2473,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry if (o.target.type() == typeid(cryptonote::txout_to_key)) { std::vector<crypto::key_derivation> additional_derivations; + additional_derivations.reserve(tx_cache_data[txidx].additional.size()); for (const auto &iod: tx_cache_data[txidx].additional) additional_derivations.push_back(iod.derivation); const auto &key = boost::get<txout_to_key>(o.target).key; @@ -2479,6 +2491,12 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry txidx = 0; for (size_t i = 0; i < blocks.size(); ++i) { + if (should_skip_block(parsed_blocks[i].block, start_height + i)) + { + txidx += 1 + parsed_blocks[i].block.tx_hashes.size(); + continue; + } + if (m_refresh_type != RefreshType::RefreshNoCoinbase) { THROW_WALLET_EXCEPTION_IF(txidx >= tx_cache_data.size(), error::wallet_internal_error, "txidx out of range"); @@ -4128,6 +4146,17 @@ bool wallet2::query_device(hw::device::device_type& device_type, const std::stri return true; } +void wallet2::init_type(hw::device::device_type device_type) +{ + m_account_public_address = m_account.get_keys().m_account_address; + m_watch_only = false; + m_multisig = false; + m_multisig_threshold = 0; + m_multisig_signers.clear(); + m_original_keys_available = false; + m_key_device_type = device_type; +} + /*! * \brief Generates a wallet or restores one. * \param wallet_ Name of wallet file @@ -4197,18 +4226,15 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys); m_account.finalize_multisig(spend_public_key); - m_account_public_address = m_account.get_keys().m_account_address; - m_watch_only = false; + // Not possible to restore a multisig wallet that is able to activate the MMS + // (because the original keys are not (yet) part of the restore info), so + // keep m_original_keys_available to false + init_type(hw::device::device_type::SOFTWARE); m_multisig = true; m_multisig_threshold = threshold; m_multisig_signers = multisig_signers; - m_key_device_type = hw::device::device_type::SOFTWARE; setup_keys(password); - // Not possible to restore a multisig wallet that is able to activate the MMS - // (because the original keys are not (yet) part of the restore info) - m_original_keys_available = false; - create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file); setup_new_blockchain(); @@ -4241,13 +4267,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip crypto::secret_key retval = m_account.generate(recovery_param, recover, two_random); - m_account_public_address = m_account.get_keys().m_account_address; - m_watch_only = false; - m_multisig = false; - m_multisig_threshold = 0; - m_multisig_signers.clear(); - m_original_keys_available = false; - m_key_device_type = hw::device::device_type::SOFTWARE; + init_type(hw::device::device_type::SOFTWARE); setup_keys(password); // calculate a starting refresh height @@ -4330,13 +4350,9 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& } m_account.create_from_viewkey(account_public_address, viewkey); - m_account_public_address = account_public_address; + init_type(hw::device::device_type::SOFTWARE); m_watch_only = true; - m_multisig = false; - m_multisig_threshold = 0; - m_multisig_signers.clear(); - m_original_keys_available = false; - m_key_device_type = hw::device::device_type::SOFTWARE; + m_account_public_address = account_public_address; setup_keys(password); create_keys_file(wallet_, true, password, m_nettype != MAINNET || create_address_file); @@ -4371,13 +4387,8 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& } m_account.create_from_keys(account_public_address, spendkey, viewkey); + init_type(hw::device::device_type::SOFTWARE); m_account_public_address = account_public_address; - m_watch_only = false; - m_multisig = false; - m_multisig_threshold = 0; - m_multisig_signers.clear(); - m_original_keys_available = false; - m_key_device_type = hw::device::device_type::SOFTWARE; setup_keys(password); create_keys_file(wallet_, false, password, create_address_file); @@ -4412,13 +4423,7 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p hwdev.set_callback(get_device_callback()); m_account.create_from_device(hwdev); - m_key_device_type = m_account.get_device().get_type(); - m_account_public_address = m_account.get_keys().m_account_address; - m_watch_only = false; - m_multisig = false; - m_multisig_threshold = 0; - m_multisig_signers.clear(); - m_original_keys_available = false; + init_type(m_account.get_device().get_type()); setup_keys(password); m_device_name = device_name; @@ -4550,10 +4555,9 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, "Failed to create multisig wallet due to bad keys"); memwipe(&spend_skey, sizeof(rct::key)); - m_account_public_address = m_account.get_keys().m_account_address; - m_watch_only = false; + init_type(hw::device::device_type::SOFTWARE); + m_original_keys_available = true; m_multisig = true; - m_key_device_type = hw::device::device_type::SOFTWARE; m_multisig_threshold = threshold; m_multisig_signers = multisig_signers; ++m_multisig_rounds_passed; @@ -10584,13 +10588,13 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de check_tx_key_helper(tx, derivation, additional_derivations, address, received); in_pool = res.txs.front().in_pool; - confirmations = (uint64_t)-1; + confirmations = 0; if (!in_pool) { std::string err; uint64_t bc_height = get_daemon_blockchain_height(err); if (err.empty()) - confirmations = bc_height - (res.txs.front().block_height + 1); + confirmations = bc_height - res.txs.front().block_height; } } @@ -10786,13 +10790,13 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account return false; in_pool = res.txs.front().in_pool; - confirmations = (uint64_t)-1; + confirmations = 0; if (!in_pool) { std::string err; uint64_t bc_height = get_daemon_blockchain_height(err); if (err.empty()) - confirmations = bc_height - (res.txs.front().block_height + 1); + confirmations = bc_height - res.txs.front().block_height; } return true; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2eb7de94a..a24127800 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -533,6 +533,8 @@ namespace tools std::vector<cryptonote::tx_extra_field> tx_extra_fields; std::vector<is_out_data> primary; std::vector<is_out_data> additional; + + bool empty() const { return tx_extra_fields.empty() && primary.empty() && additional.empty(); } }; /*! @@ -1296,6 +1298,7 @@ namespace tools */ bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password); void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); + bool should_skip_block(const cryptonote::block &b, uint64_t height) const; void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); void detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const; @@ -1362,6 +1365,7 @@ namespace tools void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const; std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> create_output_tracker_cache() const; + void init_type(hw::device::device_type device_type); void setup_new_blockchain(); void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 95cda7f1e..92265d954 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -1173,7 +1173,7 @@ namespace tools { const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d]; std::string address = cryptonote::get_account_address_as_str(m_wallet->nettype(), entry.is_subaddress, entry.addr); - if (has_encrypted_payment_id && !entry.is_subaddress) + if (has_encrypted_payment_id && !entry.is_subaddress && address != entry.original) address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), entry.addr, payment_id8); auto i = dests.find(entry.addr); if (i == dests.end()) @@ -2916,7 +2916,8 @@ namespace tools //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_get_languages(const wallet_rpc::COMMAND_RPC_GET_LANGUAGES::request& req, wallet_rpc::COMMAND_RPC_GET_LANGUAGES::response& res, epee::json_rpc::error& er, const connection_context *ctx) { - crypto::ElectrumWords::get_language_list(res.languages); + crypto::ElectrumWords::get_language_list(res.languages, true); + crypto::ElectrumWords::get_language_list(res.languages_local, false); return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -2947,14 +2948,19 @@ namespace tools std::string wallet_file = req.filename.empty() ? "" : (m_wallet_dir + "/" + req.filename); { std::vector<std::string> languages; - crypto::ElectrumWords::get_language_list(languages); + crypto::ElectrumWords::get_language_list(languages, false); std::vector<std::string>::iterator it; it = std::find(languages.begin(), languages.end(), req.language); if (it == languages.end()) { + crypto::ElectrumWords::get_language_list(languages, true); + it = std::find(languages.begin(), languages.end(), req.language); + } + if (it == languages.end()) + { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Unknown language"; + er.message = "Unknown language: " + req.language; return false; } } diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 298f34f66..7984f6584 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -47,7 +47,7 @@ // advance which version they will stop working with // Don't go over 32767 for any of these #define WALLET_RPC_VERSION_MAJOR 1 -#define WALLET_RPC_VERSION_MINOR 8 +#define WALLET_RPC_VERSION_MINOR 9 #define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR) namespace tools @@ -1999,9 +1999,11 @@ namespace wallet_rpc struct response_t { std::vector<std::string> languages; + std::vector<std::string> languages_local; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(languages) + KV_SERIALIZE(languages_local) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; diff --git a/tests/trezor/trezor_tests.cpp b/tests/trezor/trezor_tests.cpp index 310fa45f1..8d5540328 100644 --- a/tests/trezor/trezor_tests.cpp +++ b/tests/trezor/trezor_tests.cpp @@ -1406,7 +1406,7 @@ tsx_builder * tsx_builder::construct_pending_tx(tools::wallet2::pending_tx &ptx, ptx.construction_data.extra = tx.extra; ptx.construction_data.unlock_time = 0; ptx.construction_data.use_rct = true; - ptx.construction_data.use_bulletproofs = true; + ptx.construction_data.rct_config = m_rct_config; ptx.construction_data.dests = m_destinations_orig; ptx.construction_data.subaddr_account = 0; diff --git a/tests/unit_tests/hmac_keccak.cpp b/tests/unit_tests/hmac_keccak.cpp index cb35d272a..3898d4a7a 100644 --- a/tests/unit_tests/hmac_keccak.cpp +++ b/tests/unit_tests/hmac_keccak.cpp @@ -88,7 +88,8 @@ static void test_keccak_hmac(const size_t * chunks) uint8_t key_buff[1024]; uint8_t res_exp[32]; uint8_t res_comp[32]; - const size_t len_chunks = chunks ? sizeof(chunks) / sizeof(*chunks) : 0; + size_t len_chunks = 0; + for(; chunks && chunks[len_chunks] > 0; ++len_chunks); for (size_t i = 0; i < (sizeof(keccak_hmac_vectors) / sizeof(*keccak_hmac_vectors)); i++) { @@ -124,29 +125,29 @@ static void test_keccak_hmac(const size_t * chunks) TEST(keccak_hmac, ) { - test_keccak_hmac({}); + test_keccak_hmac(nullptr); } TEST(keccak_hmac, 1) { - static const size_t chunks[] = {1}; + static const size_t chunks[] = {1, 0}; test_keccak_hmac(chunks); } TEST(keccak_hmac, 1_20) { - static const size_t chunks[] = {1, 20}; + static const size_t chunks[] = {1, 20, 0}; test_keccak_hmac(chunks); } TEST(keccak_hmac, 136_1) { - static const size_t chunks[] = {136, 1}; + static const size_t chunks[] = {136, 1, 0}; test_keccak_hmac(chunks); } TEST(keccak_hmac, 137_1) { - static const size_t chunks[] = {137, 1}; + static const size_t chunks[] = {137, 1, 0}; test_keccak_hmac(chunks); } |