From 098dcf28858f244bae53d63f9d58f1d00d100808 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 3 Sep 2015 15:32:35 +0100 Subject: [PATCH 1/4] unit_tests: fix mnemonics unit test testing invalid seeds Some word triplets, such as "mugged names nail", are not valid results from any 32 bit value. If used to decode a 32 bit value, the result will therefore encode to a different word triplet. Fix this by using random words converted from an actual random bitstring, ensuring we always get valid triplets. --- tests/unit_tests/mnemonics.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp index 92a4c57f9..3dc5db7d4 100644 --- a/tests/unit_tests/mnemonics.cpp +++ b/tests/unit_tests/mnemonics.cpp @@ -44,16 +44,6 @@ namespace { - /*! - * \brief Returns random index from 0 to max-1 - * \param max Range maximum - * \return required random index - */ - uint32_t get_random_index(int max) - { - return rand() % max; - } - /*! * \brief Compares vectors for equality * \param expected expected vector @@ -78,11 +68,17 @@ namespace const std::vector &word_list = language.get_word_list(); std::string seed = "", return_seed = ""; // Generate a random seed without checksum - for (int ii = 0; ii < crypto::ElectrumWords::seed_length; ii++) + crypto::secret_key randkey; + for (size_t ii = 0; ii < sizeof(randkey); ++ii) { - seed += (word_list[get_random_index(word_list.size())] + ' '); + randkey.data[ii] = rand(); } - seed.pop_back(); + crypto::ElectrumWords::bytes_to_words(randkey, seed, language.get_language_name()); + // remove the checksum word + const char *space = strrchr(seed.c_str(), ' '); + ASSERT_TRUE(space != NULL); + seed = std::string(seed.c_str(), space-seed.c_str()); + std::cout << "Test seed without checksum:\n"; std::cout << seed << std::endl; From 1642be242d51c183532752bd482a04767c263740 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Wed, 7 Oct 2015 22:28:11 -0400 Subject: [PATCH 2/4] minor bugfixes and refactoring - Blockchain should store if it's running on testnet or not - moved loading compiled-in block hashes to its own function for clarity - on handle_get_objects, should now correctly return false if a block's transactions are missing - replace instances of BOOST_FOREACH with C++11 for loops in Blockchain. --- src/cryptonote_core/blockchain.cpp | 133 +++++++++++++++++------------ src/cryptonote_core/blockchain.h | 11 +++ 2 files changed, 88 insertions(+), 56 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 02f592b61..f18173ae8 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -270,7 +270,8 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const bool fakechain m_db = db; - if (testnet) { + m_testnet = testnet; + if (m_testnet) { m_hardfork = new HardFork(*db, 1, testnet_hard_fork_version_1_till); for (size_t n = 0; n < sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); ++n) m_hardfork->add_fork(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].threshold, testnet_hard_forks[n].time); @@ -292,7 +293,7 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const bool fakechain LOG_PRINT_L0("Blockchain not loaded, generating genesis block."); block bl = boost::value_initialized(); block_verification_context bvc = boost::value_initialized(); - if (testnet) + if (m_testnet) { generate_genesis_block(bl, config::testnet::GENESIS_TX, config::testnet::GENESIS_NONCE); } @@ -330,45 +331,8 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const bool fakechain m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service)); #if defined(PER_BLOCK_CHECKPOINT) - if (!fakechain && m_fast_sync && get_blocks_dat_start(testnet) != nullptr) - { - if (get_blocks_dat_size(testnet) > 4) - { - const unsigned char *p = get_blocks_dat_start(testnet); - const uint32_t nblocks = *p | ((*(p+1))<<8) | ((*(p+2))<<16) | ((*(p+3))<<24); - const size_t size_needed = 4 + nblocks * sizeof(crypto::hash); - if(nblocks > 0 && nblocks > m_db->height() && get_blocks_dat_size(testnet) >= size_needed) - { - LOG_PRINT_L0("Loading precomputed blocks: " << nblocks); - p += sizeof(uint32_t); - for (uint32_t i = 0; i < nblocks; i++) - { - crypto::hash hash; - memcpy(hash.data, p, sizeof(hash.data)); - p += sizeof(hash.data); - m_blocks_hash_check.push_back(hash); - } - - // FIXME: clear tx_pool because the process might have been - // terminated and caused it to store txs kept by blocks. - // The core will not call check_tx_inputs(..) for these - // transactions in this case. Consequently, the sanity check - // for tx hashes will fail in handle_block_to_main_chain(..) - std::list txs; - m_tx_pool.get_transactions(txs); - - size_t blob_size; - uint64_t fee; - bool relayed; - transaction pool_tx; - for(const transaction &tx : txs) - { - crypto::hash tx_hash = get_transaction_hash(tx); - m_tx_pool.take_tx(tx_hash, pool_tx, blob_size, fee, relayed); - } - } - } - } + if (!fakechain) + load_compiled_in_block_hashes(); #endif LOG_PRINT_GREEN("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block(), LOG_LEVEL_0); @@ -652,10 +616,10 @@ void Blockchain::get_all_known_block_ids(std::list &main, std::lis main.push_back(a); } - BOOST_FOREACH(const blocks_ext_by_hash::value_type &v, m_alternative_chains) + for (const blocks_ext_by_hash::value_type &v: m_alternative_chains) alt.push_back(v.first); - BOOST_FOREACH(const blocks_ext_by_hash::value_type &v, m_invalid_blocks) + for (const blocks_ext_by_hash::value_type &v: m_invalid_blocks) invalid.push_back(v.first); } //------------------------------------------------------------------ @@ -836,7 +800,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list blocks; get_blocks(arg.blocks, blocks, rsp.missed_ids); - BOOST_FOREACH(const auto& bl, blocks) + for (const auto& bl: blocks) { - std::list missed_tx_id; + std::list missed_tx_ids; std::list txs; - get_transactions(bl.tx_hashes, txs, rsp.missed_ids); - CHECK_AND_ASSERT_MES(!missed_tx_id.size(), false, "Internal error: has missed missed_tx_id.size()=" << missed_tx_id.size() - << std::endl << "for block id = " << get_block_hash(bl)); + get_transactions(bl.tx_hashes, txs, missed_tx_ids); + + if (missed_tx_ids.size() != 0) + { + LOG_ERROR("Error retrieving blocks, missed " << missed_tx_ids.size() + << " transactions for block with hash: " << get_block_hash(bl) + << std::endl + ); + rsp.missed_ids.push_back(get_block_hash(bl)); + + // append missed transaction hashes to response missed_ids field, + // as done below if any standalone transactions were requested + // and missed. + rsp.missed_ids.splice(rsp.missed_ids.end(), missed_tx_ids); + return false; + } + rsp.blocks.push_back(block_complete_entry()); block_complete_entry& e = rsp.blocks.back(); //pack block e.block = t_serializable_object_to_blob(bl); //pack transactions - BOOST_FOREACH(transaction& tx, txs) + for (transaction& tx: txs) e.txs.push_back(t_serializable_object_to_blob(tx)); } //get another transactions, if need std::list txs; get_transactions(arg.txs, txs, rsp.missed_ids); //pack aside transactions - BOOST_FOREACH(const auto& tx, txs) + for (const auto& tx: txs) rsp.txs.push_back(t_serializable_object_to_blob(tx)); return true; @@ -1439,7 +1417,7 @@ bool Blockchain::get_alternative_blocks(std::list& blocks) const LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_blockchain_lock); - BOOST_FOREACH(const auto& alt_bl, m_alternative_chains) + for (const auto& alt_bl: m_alternative_chains) { blocks.push_back(alt_bl.second.bl); } @@ -1988,7 +1966,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx) // from hard fork 2, we forbid dust and compound outputs if (m_hardfork->get_current_version() >= 2) { - BOOST_FOREACH(auto &o, tx.vout) { + for (auto &o: tx.vout) { if (!is_valid_decomposed_amount(o.amount)) { return false; } @@ -2001,7 +1979,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx) bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const { LOG_PRINT_L3("Blockchain::" << __func__); - BOOST_FOREACH(const txin_v& in, tx.vin) + for (const txin_v& in: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, in_to_key, true); if(have_tx_keyimg_as_spent(in_to_key.k_image)) @@ -3249,6 +3227,49 @@ 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); } +void Blockchain::load_compiled_in_block_hashes() +{ + if (m_fast_sync && get_blocks_dat_start(m_testnet) != nullptr) + { + if (get_blocks_dat_size(m_testnet) > 4) + { + const unsigned char *p = get_blocks_dat_start(m_testnet); + const uint32_t nblocks = *p | ((*(p+1))<<8) | ((*(p+2))<<16) | ((*(p+3))<<24); + const size_t size_needed = 4 + nblocks * sizeof(crypto::hash); + if(nblocks > 0 && nblocks > m_db->height() && get_blocks_dat_size(m_testnet) >= size_needed) + { + LOG_PRINT_L0("Loading precomputed blocks: " << nblocks); + p += sizeof(uint32_t); + for (uint32_t i = 0; i < nblocks; i++) + { + crypto::hash hash; + memcpy(hash.data, p, sizeof(hash.data)); + p += sizeof(hash.data); + m_blocks_hash_check.push_back(hash); + } + + // FIXME: clear tx_pool because the process might have been + // terminated and caused it to store txs kept by blocks. + // The core will not call check_tx_inputs(..) for these + // transactions in this case. Consequently, the sanity check + // for tx hashes will fail in handle_block_to_main_chain(..) + std::list txs; + m_tx_pool.get_transactions(txs); + + size_t blob_size; + uint64_t fee; + bool relayed; + transaction pool_tx; + for(const transaction &tx : txs) + { + crypto::hash tx_hash = get_transaction_hash(tx); + m_tx_pool.take_tx(tx_hash, pool_tx, blob_size, fee, relayed); + } + } + } + } +} + bool Blockchain::for_all_key_images(std::function f) const { return m_db->for_all_key_images(f); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index ecabf5376..89f623f90 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -239,6 +239,8 @@ namespace cryptonote HardFork *m_hardfork; + bool m_testnet; + 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; 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); @@ -274,5 +276,14 @@ namespace cryptonote 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); + + /** + * @brief loads block hashes from compiled-in data set + * + * A (possibly empty) set of block hashes can be compiled into the + * monero daemon binary. This function loads those hashes into + * a useful state. + */ + void load_compiled_in_block_hashes(); }; } // namespace cryptonote From 3a0f4d8a57c61b6b4dc8a6bfbf4f31acf14bf328 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 2 Sep 2015 18:16:26 +0100 Subject: [PATCH 3/4] berkeleydb: fix delete/free mismatch Despite being C++, the stats object is allocated by the underlying C layer using malloc(3). --- src/blockchain_db/berkeleydb/db_bdb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp index 832fb8f8d..6c80d1333 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ b/src/blockchain_db/berkeleydb/db_bdb.cpp @@ -925,12 +925,12 @@ void BlockchainBDB::open(const std::string& filename, const int db_flags) // to zero (0) for reliability. m_blocks->stat(NULL, &stats, 0); m_height = stats->bt_nkeys; - delete stats; + free(stats); // see above comment about DB_FAST_STAT m_output_indices->stat(NULL, &stats, 0); m_num_outputs = stats->bt_nkeys; - delete stats; + free(stats); // checks for compatibility bool compatible = true; From 7658ac0f45c4aba0d88935047b225bfbc0ba2548 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 3 Feb 2016 21:08:03 +0000 Subject: [PATCH 4/4] blockchain: revert handle_get_objects adding block id on tx not found This differs from the original CN code, and there seems to be no reason to include the block itself, if it was found --- src/cryptonote_core/blockchain.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index f18173ae8..afc479a4b 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1385,7 +1385,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO << " transactions for block with hash: " << get_block_hash(bl) << std::endl ); - rsp.missed_ids.push_back(get_block_hash(bl)); // append missed transaction hashes to response missed_ids field, // as done below if any standalone transactions were requested