diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/blockchain_db/berkeleydb/db_bdb.cpp | 4 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 132 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 11 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 18 | ||||
-rw-r--r-- | src/cryptonote_core/hardfork.cpp | 5 | ||||
-rw-r--r-- | src/daemon/rpc_command_executor.cpp | 1 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 61 |
7 files changed, 152 insertions, 80 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; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 02f592b61..afc479a4b 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>(); block_verification_context bvc = boost::value_initialized<block_verification_context>(); - 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<transaction> 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<crypto::hash> &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_ext_by_hash:: } //removing alt_chain entries from alternative chain - BOOST_FOREACH(auto ch_ent, alt_chain) + for (auto ch_ent: alt_chain) { m_alternative_chains.erase(ch_ent); } @@ -948,7 +912,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl LOG_PRINT_L3("Blockchain::" << __func__); //validate reward uint64_t money_in_use = 0; - BOOST_FOREACH(auto& o, b.miner_tx.vout) + for (auto& o: b.miner_tx.vout) money_in_use += o.amount; partial_block_reward = false; @@ -1055,7 +1019,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m size_t real_txs_size = 0; uint64_t real_fee = 0; CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock); - BOOST_FOREACH(crypto::hash &cur_hash, b.tx_hashes) + for(crypto::hash &cur_hash: b.tx_hashes) { auto cur_res = m_tx_pool.m_transactions.find(cur_hash); if (cur_res == m_tx_pool.m_transactions.end()) @@ -1409,26 +1373,39 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO std::list<block> blocks; get_blocks(arg.blocks, blocks, rsp.missed_ids); - BOOST_FOREACH(const auto& bl, blocks) + for (const auto& bl: blocks) { - std::list<crypto::hash> missed_tx_id; + std::list<crypto::hash> missed_tx_ids; std::list<transaction> 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 + ); + + // 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<transaction> 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 +1416,7 @@ bool Blockchain::get_alternative_blocks(std::list<block>& 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 +1965,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 +1978,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 +3226,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<transaction> 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<bool(const crypto::key_image&)> 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<class visitor_t> 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<crypto::signature>& sig, std::vector<crypto::public_key> &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<crypto::public_key> &pubkeys, const std::vector<crypto::signature> &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 diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 8d50e8bfd..2479931be 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -267,7 +267,16 @@ namespace cryptonote boost::filesystem::path folder(m_config_folder); if (m_fakechain) folder /= "fake"; - // + + // make sure the data directory exists, and try to lock it + CHECK_AND_ASSERT_MES (boost::filesystem::exists(folder) || boost::filesystem::create_directories(folder), false, + std::string("Failed to create directory ").append(folder.string()).c_str()); + if (!lock_db_directory (folder)) + { + LOG_ERROR ("Failed to lock " << folder); + return false; + } + // check for blockchain.bin try { @@ -313,13 +322,6 @@ namespace cryptonote folder /= db->get_db_name(); LOG_PRINT_L0("Loading blockchain from folder " << folder.string() << " ..."); - if (!lock_db_directory (folder)) - { - LOG_ERROR ("Failed to lock " << folder); - delete db; - return false; - } - const std::string filename = folder.string(); // temporarily default to fastest:async:1000 blockchain_db_sync_mode sync_mode = db_async; diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp index 66fb05010..9fe731ad1 100644 --- a/src/cryptonote_core/hardfork.cpp +++ b/src/cryptonote_core/hardfork.cpp @@ -318,10 +318,13 @@ HardFork::State HardFork::get_state() const uint8_t HardFork::get(uint64_t height) const { CRITICAL_REGION_LOCAL(lock); - if (height >= db.height()) { + if (height > db.height()) { assert(false); return 255; } + if (height == db.height()) { + return get_current_version(); + } return db.get_hard_fork_version(height); } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 49b4cc23a..361808cf7 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -251,7 +251,6 @@ bool t_rpc_command_executor::show_difficulty() { static std::string get_mining_speed(uint64_t hr) { -std::cerr << "get_mining_speed called with " << hr << std::endl; if (hr>1e9) return (boost::format("%.2f GH/s") % (hr/1e9)).str(); if (hr>1e6) return (boost::format("%.2f MH/s") % (hr/1e6)).str(); if (hr>1e3) return (boost::format("%.2f kH/s") % (hr/1e3)).str(); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 40f372c35..ed6d3842d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -323,22 +323,59 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ THROW_WALLET_EXCEPTION_IF(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" + std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size())); - m_transfers.push_back(boost::value_initialized<transfer_details>()); - transfer_details& td = m_transfers.back(); - td.m_block_height = height; - td.m_internal_output_index = o; - td.m_global_output_index = res.o_indexes[o]; - td.m_tx = tx; - td.m_spent = false; + crypto::key_image ki; cryptonote::keypair in_ephemeral; - cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, td.m_key_image); + cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, ki); THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[o].target).key, error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); - m_key_images[td.m_key_image] = m_transfers.size()-1; - LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx)); - if (0 != m_callback) - m_callback->on_money_received(height, td.m_tx, td.m_internal_output_index); + auto kit = m_key_images.find(ki); + THROW_WALLET_EXCEPTION_IF(kit != m_key_images.end() && kit->second >= m_transfers.size(), + error::wallet_internal_error, std::string("Unexpected transfer index from key image: ") + + "got " + (kit == m_key_images.end() ? "<none>" : boost::lexical_cast<std::string>(kit->second)) + + ", m_transfers.size() is " + boost::lexical_cast<std::string>(m_transfers.size())); + if (kit == m_key_images.end()) + { + m_transfers.push_back(boost::value_initialized<transfer_details>()); + transfer_details& td = m_transfers.back(); + td.m_block_height = height; + td.m_internal_output_index = o; + td.m_global_output_index = res.o_indexes[o]; + td.m_tx = tx; + td.m_key_image = ki; + td.m_spent = false; + m_key_images[td.m_key_image] = m_transfers.size()-1; + LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx)); + if (0 != m_callback) + m_callback->on_money_received(height, td.m_tx, td.m_internal_output_index); + } + else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx.vout[o].amount) + { + LOG_ERROR("key image " << epee::string_tools::pod_to_hex(ki) + << " from received " << print_money(tx.vout[o].amount) << " output already exists with " + << (m_transfers[kit->second].m_spent ? "spent" : "unspent") << " " + << print_money(m_transfers[kit->second].amount()) << ", received output ignored"); + } + else + { + LOG_ERROR("key image " << epee::string_tools::pod_to_hex(ki) + << " from received " << print_money(tx.vout[o].amount) << " output already exists with " + << print_money(m_transfers[kit->second].amount()) << ", replacing with new output"); + // The new larger output replaced a previous smaller one + tx_money_got_in_outs -= tx.vout[o].amount; + + transfer_details &td = m_transfers[kit->second]; + td.m_block_height = height; + td.m_internal_output_index = o; + td.m_global_output_index = res.o_indexes[o]; + td.m_tx = tx; + THROW_WALLET_EXCEPTION_IF(td.m_key_image != ki, error::wallet_internal_error, "Inconsistent key images"); + THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status"); + + LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx)); + if (0 != m_callback) + m_callback->on_money_received(height, td.m_tx, td.m_internal_output_index); + } } } } |