From 29c2859a3e8a935ef605534c6c36333894980d50 Mon Sep 17 00:00:00 2001 From: Antonio Juarez Date: Wed, 2 Apr 2014 17:00:17 +0100 Subject: json rpc for wallet and bugfix --- src/cryptonote_core/blockchain_storage.cpp | 118 +++++++++--------------- src/cryptonote_core/blockchain_storage.h | 52 +++++++++-- src/cryptonote_core/cryptonote_basic_impl.cpp | 59 ++++++------ src/cryptonote_core/cryptonote_basic_impl.h | 2 +- src/cryptonote_core/cryptonote_format_utils.cpp | 68 +++++++------- src/cryptonote_core/cryptonote_format_utils.h | 5 +- src/cryptonote_core/tx_pool.cpp | 62 ++++++++++--- src/cryptonote_core/tx_pool.h | 2 +- 8 files changed, 200 insertions(+), 168 deletions(-) (limited to 'src/cryptonote_core') diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index 3eb7f86c0..cef988c40 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -44,6 +44,7 @@ bool blockchain_storage::have_tx_keyimg_as_spent(const crypto::key_image &key_im //------------------------------------------------------------------ transaction *blockchain_storage::get_tx(const crypto::hash &id) { + CRITICAL_REGION_LOCAL(m_blockchain_lock); auto it = m_transactions.find(id); if (it == m_transactions.end()) return NULL; @@ -65,26 +66,12 @@ bool blockchain_storage::init(const std::string& config_folder) const std::string filename = m_config_folder + "/" CRYPTONOTE_BLOCKCHAINDATA_FILENAME; if(!tools::unserialize_obj_from_file(*this, filename)) { - const std::string temp_filename = m_config_folder + "/" CRYPTONOTE_BLOCKCHAINDATA_TEMP_FILENAME; - if(tools::unserialize_obj_from_file(*this, temp_filename)) - { - LOG_PRINT_L0("Blockchain storage loaded from temporary file"); - std::error_code ec = tools::replace_file(temp_filename, filename); - if (ec) - { - LOG_ERROR("Failed to rename blockchain data file " << temp_filename << " to " << filename << ": " << ec.message() << ':' << ec.value()); - return false; - } - } - else - { - LOG_PRINT_L0("Blockchain storage file not found, generating genesis block."); + LOG_PRINT_L0("Can't load blockchain storage from file, generating genesis block."); block bl = boost::value_initialized(); block_verification_context bvc = boost::value_initialized(); generate_genesis_block(bl); add_new_block(bl, bvc); CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed && bvc.m_added_to_main_chain, false, "Failed to add genesis block to blockchain"); - } } if(!m_blocks.size()) { @@ -177,6 +164,7 @@ bool blockchain_storage::reset_and_set_genesis_block(const block& b) //------------------------------------------------------------------ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check) { + CRITICAL_REGION_LOCAL(m_blockchain_lock); struct purge_transaction_visitor: public boost::static_visitor { key_images_container& m_spent_keys; @@ -221,6 +209,7 @@ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const trans //------------------------------------------------------------------ bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& tx_id) { + CRITICAL_REGION_LOCAL(m_blockchain_lock); auto tx_index_it = m_transactions.find(tx_id); CHECK_AND_ASSERT_MES(tx_index_it != m_transactions.end(), false, "purge_block_data_from_blockchain: transaction not found in blockchain index!!"); transaction& tx = tx_index_it->second.tx; @@ -525,9 +514,7 @@ bool blockchain_storage::validate_miner_transaction(const block& b, size_t cumul std::vector last_blocks_sizes; get_last_n_blocks_sizes(last_blocks_sizes, CRYPTONOTE_REWARD_BLOCKS_WINDOW); - bool block_too_big = false; - base_reward = get_block_reward(last_blocks_sizes, cumulative_block_size, block_too_big, already_generated_coins); - if(block_too_big) + if(!get_block_reward(misc_utils::median(last_blocks_sizes), cumulative_block_size, already_generated_coins, base_reward)) { LOG_PRINT_L0("block size " << cumulative_block_size << " is bigger than allowed for this blockchain"); return false; @@ -568,18 +555,15 @@ bool blockchain_storage::get_last_n_blocks_sizes(std::vector& sz, size_t //------------------------------------------------------------------ uint64_t blockchain_storage::get_current_comulative_blocksize_limit() { - return m_current_block_comul_sz_limit; + return m_current_block_cumul_sz_limit; } //------------------------------------------------------------------ bool blockchain_storage::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) { - size_t txs_cumulative_size = 0; - uint64_t fee = 0; - size_t comul_sz_limit = 0; - std::vector sz; + size_t median_size; + uint64_t already_generated_coins; CRITICAL_REGION_BEGIN(m_blockchain_lock); - get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW); b.major_version = CURRENT_BLOCK_MAJOR_VERSION; b.minor_version = CURRENT_BLOCK_MINOR_VERSION; b.prev_id = get_tail_id(); @@ -588,72 +572,73 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad diffic = get_difficulty_for_next_block(); CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead."); - comul_sz_limit = m_current_block_comul_sz_limit - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; + median_size = m_current_block_cumul_sz_limit; + already_generated_coins = m_blocks.back().already_generated_coins; CRITICAL_REGION_END(); - m_tx_pool.fill_block_template(b, txs_cumulative_size, comul_sz_limit, fee); + size_t txs_size; + uint64_t fee; + if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) { + return false; + } /* two-phase miner transaction generation: we don't know exact block size until we prepare block, but we don't know reward until we know block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size */ //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size - bool r = construct_miner_tx(height, m_blocks.back().already_generated_coins, miner_address, b.miner_tx, fee, sz, txs_cumulative_size, ex_nonce, 11); + bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); #ifdef _DEBUG std::list try_val; try_val.push_back(get_object_blobsize(b.miner_tx)); #endif - size_t cumulative_size = txs_cumulative_size + get_object_blobsize(b.miner_tx); - size_t try_count = 0; - for(; try_count != 10; ++try_count) - { - r = construct_miner_tx(height, m_blocks.back().already_generated_coins, miner_address, b.miner_tx, fee, sz, cumulative_size, ex_nonce, 11); + size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); + for (size_t try_count = 0; try_count != 10; ++try_count) { + r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11); #ifdef _DEBUG try_val.push_back(get_object_blobsize(b.miner_tx)); #endif CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance"); size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); - if(coinbase_blob_size > cumulative_size - txs_cumulative_size ) - { - cumulative_size = txs_cumulative_size + coinbase_blob_size; + if (coinbase_blob_size > cumulative_size - txs_size) { + cumulative_size = txs_size + coinbase_blob_size; continue; - }else - { - if(coinbase_blob_size < cumulative_size - txs_cumulative_size ) - { - size_t delta = cumulative_size - txs_cumulative_size - coinbase_blob_size; - b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0); - //here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len. - if(cumulative_size != txs_cumulative_size + get_object_blobsize(b.miner_tx)) - { - CHECK_AND_ASSERT_MES(cumulative_size + 1== txs_cumulative_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " + 1 is not equal txs_cumulative_size=" << txs_cumulative_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx) ); - b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1 ); - if(cumulative_size != txs_cumulative_size + get_object_blobsize(b.miner_tx)) - {//fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_size - LOG_PRINT_RED("Miner tx creation have no luck with delta_extra size = " << delta << " and " << delta - 1 , LOG_LEVEL_2); - cumulative_size += delta + 1; - continue; - } - LOG_PRINT_GREEN("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count, LOG_LEVEL_1); + } + + if (coinbase_blob_size < cumulative_size - txs_size) { + size_t delta = cumulative_size - txs_size - coinbase_blob_size; + b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0); + //here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len. + if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) { + CHECK_AND_ASSERT_MES(cumulative_size + 1 == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " + 1 is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx)); + b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1); + if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) { + //fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_size + LOG_PRINT_RED("Miner tx creation have no luck with delta_extra size = " << delta << " and " << delta - 1 , LOG_LEVEL_2); + cumulative_size += delta - 1; + continue; } + LOG_PRINT_GREEN("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count, LOG_LEVEL_1); } - CHECK_AND_ASSERT_MES(cumulative_size == txs_cumulative_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_cumulative_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx) ); - return true; } + CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx)); + return true; } - LOG_ERROR("Failed to create_block_template with " << try_count << " tries"); + LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); return false; } //------------------------------------------------------------------ bool blockchain_storage::complete_timestamps_vector(uint64_t start_top_height, std::vector& timestamps) { + if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) return true; + CRITICAL_REGION_LOCAL(m_blockchain_lock); size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size(); CHECK_AND_ASSERT_MES(start_top_height < m_blocks.size(), false, "internal error: passed start_height = " << start_top_height << " not less then m_blocks.size()=" << m_blocks.size()); size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements:0; @@ -947,22 +932,6 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO return true; } //------------------------------------------------------------------ -//bool blockchain_storage::get_outs_for_amounts(uint64_t amount, std::vector >& keys, std::map& txs) -//{ -// auto it = m_outputs.find(amount); -// if(it == m_outputs.end()) -// return false; -// keys = it->second; -// typedef std::pair pair; -// BOOST_FOREACH(pair& pr, keys) -// { -// auto it = m_transactions.find(pr.first); -// CHECK_AND_ASSERT_MES(it != m_transactions.end(), false, "internal error: transaction with id " << pr.first << " not found in internal index, but have refference for amount " << amount); -// txs[pr.first] = it->second.tx; -// } -// return true; -//} -//------------------------------------------------------------------ bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset) { CRITICAL_REGION_LOCAL(m_blockchain_lock); @@ -1036,7 +1005,8 @@ void blockchain_storage::print_blockchain(uint64_t start_index, uint64_t end_ind << "\nid\t\t" << get_block_hash(m_blocks[i].bl) << "\ndifficulty\t\t" << block_difficulty(i) << ", nonce " << m_blocks[i].bl.nonce << ", tx_count " << m_blocks[i].bl.tx_hashes.size() << ENDL; } - LOG_PRINT_L0("Current blockchain:" << ENDL << ss.str()); + LOG_PRINT_L1("Current blockchain:" << ENDL << ss.str()); + LOG_PRINT_L0("Blockchain printed with log level 1"); } //------------------------------------------------------------------ void blockchain_storage::print_blockchain_index() @@ -1605,7 +1575,7 @@ bool blockchain_storage::update_next_comulative_size_limit() if(median <= CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE; - m_current_block_comul_sz_limit = median*2; + m_current_block_cumul_sz_limit = median*2; return true; } //------------------------------------------------------------------ diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index c263f7503..5a3ff3d84 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -50,7 +50,7 @@ namespace cryptonote uint64_t already_generated_coins; }; - blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_comul_sz_limit(0), m_is_in_checkpoint_zone(false) + blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false) {}; bool init() { return init(tools::get_default_data_dir()); } @@ -175,7 +175,7 @@ namespace cryptonote blocks_by_id_index m_blocks_index; // crypto::hash -> height transactions_container m_transactions; key_images_container m_spent_keys; - size_t m_current_block_comul_sz_limit; + size_t m_current_block_cumul_sz_limit; // all alternative chains @@ -235,12 +235,12 @@ namespace cryptonote /* */ /************************************************************************/ - #define CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER 11 + #define CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER 12 template void blockchain_storage::serialize(archive_t & ar, const unsigned int version) { - if(version < CURRENT_BLOCKCHAIN_STORAGE_ARCHIVE_VER) + if(version < 11) return; CRITICAL_REGION_LOCAL(m_blockchain_lock); ar & m_blocks; @@ -250,14 +250,54 @@ namespace cryptonote ar & m_alternative_chains; ar & m_outputs; ar & m_invalid_blocks; - ar & m_current_block_comul_sz_limit; + ar & m_current_block_cumul_sz_limit; + /*serialization bug workaround*/ + if(version > 11) + { + uint64_t total_check_count = m_blocks.size() + m_blocks_index.size() + m_transactions.size() + m_spent_keys.size() + m_alternative_chains.size() + m_outputs.size() + m_invalid_blocks.size() + m_current_block_cumul_sz_limit; + if(archive_t::is_saving::value) + { + ar & total_check_count; + }else + { + uint64_t total_check_count_loaded = 0; + ar & total_check_count_loaded; + if(total_check_count != total_check_count_loaded) + { + LOG_ERROR("Blockchain storage data corruption detected. total_count loaded from file = " << total_check_count_loaded << ", expected = " << total_check_count); + + LOG_PRINT_L0("Blockchain storage:" << ENDL << + "m_blocks: " << m_blocks.size() << ENDL << + "m_blocks_index: " << m_blocks_index.size() << ENDL << + "m_transactions: " << m_transactions.size() << ENDL << + "m_spent_keys: " << m_spent_keys.size() << ENDL << + "m_alternative_chains: " << m_alternative_chains.size() << ENDL << + "m_outputs: " << m_outputs.size() << ENDL << + "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"); + } + } + } + + + LOG_PRINT_L2("Blockchain storage:" << ENDL << + "m_blocks: " << m_blocks.size() << ENDL << + "m_blocks_index: " << m_blocks_index.size() << ENDL << + "m_transactions: " << m_transactions.size() << ENDL << + "m_spent_keys: " << m_spent_keys.size() << ENDL << + "m_alternative_chains: " << m_alternative_chains.size() << ENDL << + "m_outputs: " << m_outputs.size() << ENDL << + "m_invalid_blocks: " << m_invalid_blocks.size() << ENDL << + "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); } //------------------------------------------------------------------ template bool blockchain_storage::scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height) { - + CRITICAL_REGION_LOCAL(m_blockchain_lock); auto it = m_outputs.find(tx_in_to_key.amount); if(it == m_outputs.end() || !tx_in_to_key.key_offsets.size()) return false; diff --git a/src/cryptonote_core/cryptonote_basic_impl.cpp b/src/cryptonote_core/cryptonote_basic_impl.cpp index 194b89052..24b6b59d0 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.cpp +++ b/src/cryptonote_core/cryptonote_basic_impl.cpp @@ -25,7 +25,7 @@ namespace cryptonote { //----------------------------------------------------------------------------------------------- size_t get_max_block_size() { - return CRYPTONOTE_MAX_BLOCK_SIZE; + return CRYPTONOTE_MAX_BLOCK_SIZE; } //----------------------------------------------------------------------------------------------- size_t get_max_tx_size() @@ -33,46 +33,39 @@ namespace cryptonote { return CRYPTONOTE_MAX_TX_SIZE; } //----------------------------------------------------------------------------------------------- - uint64_t get_block_reward(std::vector& last_blocks_sizes, size_t current_block_size, bool& block_too_big, uint64_t already_generated_coins) - { - block_too_big = false; - + bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward) { uint64_t base_reward = (MONEY_SUPPLY - already_generated_coins) >> 18; - if(current_block_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) - return base_reward; - - size_t med_sz = misc_utils::median(last_blocks_sizes); - //make it soft - if(med_sz < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) - med_sz = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE; + if (median_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) { + median_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE; + } - if(current_block_size > med_sz) - { - if(current_block_size > med_sz*2) - { - LOG_PRINT_L0("Block cumulative size is too big: " << current_block_size << ", expected less than " << med_sz*2); - block_too_big = true; - return 0; - } + if (current_block_size <= median_size) { + reward = base_reward; + return true; + } + + if(current_block_size > 2 * median_size) { + LOG_PRINT_L4("Block cumulative size is too big: " << current_block_size << ", expected less than " << 2 * median_size); + return false; + } - assert(med_sz < std::numeric_limits::max()); - assert(current_block_size < std::numeric_limits::max()); + assert(median_size < std::numeric_limits::max()); + assert(current_block_size < std::numeric_limits::max()); - uint64_t product_hi; - uint64_t product_lo = mul128(base_reward, current_block_size * (2 * med_sz - current_block_size), &product_hi); + uint64_t product_hi; + uint64_t product_lo = mul128(base_reward, current_block_size * (2 * median_size - current_block_size), &product_hi); - uint64_t reward_hi; - uint64_t reward_lo; - div128_32(product_hi, product_lo, static_cast(med_sz), &reward_hi, &reward_lo); - div128_32(reward_hi, reward_lo, static_cast(med_sz), &reward_hi, &reward_lo); - assert(0 == reward_hi); - assert(reward_lo < base_reward); + uint64_t reward_hi; + uint64_t reward_lo; + div128_32(product_hi, product_lo, static_cast(median_size), &reward_hi, &reward_lo); + div128_32(reward_hi, reward_lo, static_cast(median_size), &reward_hi, &reward_lo); + assert(0 == reward_hi); + assert(reward_lo < base_reward); - return reward_lo; - }else - return base_reward; + reward = reward_lo; + return true; } //------------------------------------------------------------------------------------ uint8_t get_account_address_checksum(const public_address_outer_blob& bl) diff --git a/src/cryptonote_core/cryptonote_basic_impl.h b/src/cryptonote_core/cryptonote_basic_impl.h index f56d09a8e..cb6fb7692 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.h +++ b/src/cryptonote_core/cryptonote_basic_impl.h @@ -38,7 +38,7 @@ namespace cryptonote { /************************************************************************/ size_t get_max_block_size(); size_t get_max_tx_size(); - uint64_t get_block_reward(std::vector& last_blocks_sizes, size_t current_block_size, bool& block_too_big, uint64_t already_generated_coins); + bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward); uint8_t get_account_address_checksum(const public_address_outer_blob& bl); std::string get_account_address_as_str(const account_public_address& adr); bool get_account_address_from_str(account_public_address& adr, const std::string& str); diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index fbcadc081..b160ab8dc 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -54,13 +54,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector& blocks_sizes, size_t current_block_size, size_t max_outs) - { - return construct_miner_tx(height, already_generated_coins, miner_address, tx, fee, blocks_sizes, current_block_size, blobdata(), max_outs); - } - //--------------------------------------------------------------- - bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector& blocks_sizes, size_t current_block_size, const blobdata& extra_nonce, size_t max_outs) - { + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); @@ -74,13 +68,13 @@ namespace cryptonote txin_gen in; in.height = height; - bool block_too_big = false; - uint64_t block_reward = get_block_reward(blocks_sizes, current_block_size, block_too_big, already_generated_coins) + fee; - if(block_too_big) + uint64_t block_reward; + if(!get_block_reward(median_size, current_block_size, already_generated_coins, block_reward)) { LOG_PRINT_L0("Block is too big"); return false; } + block_reward += fee; std::vector out_amounts; decompose_amount_into_digits(block_reward, DEFAULT_FEE, @@ -120,7 +114,7 @@ namespace cryptonote //lock tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; tx.vin.push_back(in); - //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "(" << print_money(block_reward - fee) << "+" << print_money(fee) + //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "(" << print_money(block_reward - fee) << "+" << print_money(fee) // << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2); return true; } @@ -152,33 +146,37 @@ namespace cryptonote //--------------------------------------------------------------- bool parse_amount(uint64_t& amount, const std::string& str_amount_) { - std::vector pars; std::string str_amount = str_amount_; boost::algorithm::trim(str_amount); - if(!str_amount.size()) - return false; - if(str_amount[0] == '-') - return false; - boost::split(pars, str_amount, boost::is_any_of("."), boost::token_compress_on ); - if(pars.size() > 2 || pars.size() < 1) - return false; - uint64_t left = 0; - if(!string_tools::get_xtype_from_string(left, pars[0])) - return false; - amount = left * power_integral(10, CRYPTONOTE_DISPLAY_DECIMAL_POINT); - if(pars.size() == 2) + size_t point_index = str_amount.find_first_of('.'); + size_t fraction_size; + if (std::string::npos != point_index) { - uint64_t right = 0; - if(pars[1].size() > 8 ) + fraction_size = str_amount.size() - point_index - 1; + while (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size && '0' == str_amount.back()) + { + str_amount.erase(str_amount.size() - 1, 1); + --fraction_size; + } + if (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size) return false; - if(pars[1].size() < 8 ) - pars[1].append(8 - pars[1].size(), '0'); - if(!string_tools::get_xtype_from_string(right, pars[1])) - return false; - amount += right; + str_amount.erase(point_index, 1); } - return true; + else + { + fraction_size = 0; + } + + if (str_amount.empty()) + return false; + + if (fraction_size < CRYPTONOTE_DISPLAY_DECIMAL_POINT) + { + str_amount.append(CRYPTONOTE_DISPLAY_DECIMAL_POINT - fraction_size, '0'); + } + + return string_tools::get_xtype_from_string(amount, str_amount); } //--------------------------------------------------------------- bool get_tx_fee(const transaction& tx, uint64_t & fee) @@ -218,7 +216,7 @@ namespace cryptonote tx_pub_key = null_pkey; bool padding_started = false; //let the padding goes only at the end bool tx_extra_tag_pubkey_found = false; - bool tx_extra_extra_nonce_found = false; + bool tx_extra_extra_nonce_found = false; for(size_t i = 0; i != tx.extra.size();) { if(padding_started) @@ -573,7 +571,7 @@ namespace cryptonote blobdata get_block_hashing_blob(const block& b) { blobdata blob = t_serializable_object_to_blob(static_cast(b)); - crypto::hash tree_root_hash = get_tx_tree_hash(b); + crypto::hash tree_root_hash = get_tx_tree_hash(b); blob.append((const char*)&tree_root_hash, sizeof(tree_root_hash )); blob.append(tools::get_varint_data(b.tx_hashes.size()+1)); return blob; @@ -599,7 +597,7 @@ namespace cryptonote account_public_address ac = boost::value_initialized(); std::vector sz; - construct_miner_tx(0, 0, ac, bl.miner_tx, 0, sz, 0, 1); // zero fee in genesis + construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis blobdata txb = tx_to_blob(bl.miner_tx); std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb); diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 1bc180f8f..8f42b807a 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -17,9 +17,8 @@ namespace cryptonote void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h); crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash); - bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); - bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector& blocks_sizes, size_t current_block_size, const blobdata& extra_nonce, size_t max_outs = 1); - bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector& blocks_sizes, size_t current_block_size, size_t max_outs = 1); + bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 1); struct tx_source_entry { diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 3a1799675..6cd33a2d7 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -2,8 +2,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include +#include #include "tx_pool.h" #include "cryptonote_format_utils.h" @@ -11,6 +13,7 @@ #include "cryptonote_config.h" #include "blockchain_storage.h" #include "common/boost_serialization_helper.h" +#include "common/int-util.h" #include "misc_language.h" #include "warnings.h" #include "crypto/hash.h" @@ -345,31 +348,60 @@ namespace cryptonote return ss.str(); } //--------------------------------------------------------------------------------- - bool tx_memory_pool::fill_block_template(block& bl, size_t& cumulative_sizes, size_t max_comulative_sz, uint64_t& fee) - { + bool tx_memory_pool::fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee) { + typedef transactions_container::value_type txv; CRITICAL_REGION_LOCAL(m_transactions_lock); + std::vector txs(m_transactions.size()); + std::transform(m_transactions.begin(), m_transactions.end(), txs.begin(), [](txv &a) -> txv * { return &a; }); + std::sort(txs.begin(), txs.end(), [](txv *a, txv *b) -> bool { + uint64_t a_hi, a_lo = mul128(a->second.fee, b->second.blob_size, &a_hi); + uint64_t b_hi, b_lo = mul128(b->second.fee, a->second.blob_size, &b_hi); + return a_hi > b_hi || (a_hi == b_hi && a_lo > b_lo); + }); + + size_t current_size = 0; + uint64_t current_fee = 0; + uint64_t best_money; + if (!get_block_reward(median_size, CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, best_money)) { + LOG_ERROR("Block with just a miner transaction is already too large!"); + return false; + } + size_t best_position = 0; + total_size = 0; fee = 0; - std::unordered_set k_images; - BOOST_FOREACH(transactions_container::value_type& tx, m_transactions) - { - if(cumulative_sizes + tx.second.blob_size > max_comulative_sz) - continue; + std::unordered_set k_images; - if(!is_transaction_ready_to_go(tx.second)) - continue; + for (size_t i = 0; i < txs.size(); i++) { + txv &tx(*txs[i]); - if(have_key_images(k_images, tx.second.tx)) + if(!is_transaction_ready_to_go(tx.second) || have_key_images(k_images, tx.second.tx)) { + txs[i] = NULL; continue; - - bl.tx_hashes.push_back(tx.first); - cumulative_sizes += tx.second.blob_size; - fee += tx.second.fee; + } append_key_images(k_images, tx.second.tx); - if(cumulative_sizes >= max_comulative_sz) + current_size += tx.second.blob_size; + current_fee += tx.second.fee; + + uint64_t current_reward; + if (!get_block_reward(median_size, current_size + CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, current_reward)) { break; + } + + if (best_money < current_reward + current_fee) { + best_money = current_reward + current_fee; + best_position = i + 1; + total_size = current_size; + fee = current_fee; + } + } + + for (size_t i = 0; i < best_position; i++) { + if (txs[i]) { + bl.tx_hashes.push_back(txs[i]->first); + } } return true; diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 1dff7ee1c..3ac1331bd 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -49,7 +49,7 @@ namespace cryptonote // load/store operations bool init(const std::string& config_folder); bool deinit(); - bool fill_block_template(block& bl, size_t& cumulative_sizes, size_t max_comulative_sz, uint64_t& fee); + bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee); bool get_transactions(std::list& txs); bool get_transaction(const crypto::hash& h, transaction& tx); size_t get_transactions_count(); -- cgit v1.2.3