diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index cb0d8e86..eb1feb44 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -834,7 +834,9 @@ bool database::_push_block(const signed_block& new_block) try { - ilog("Pushing new block #${n} from ${w} with timestamp ${t} at time ${c}", ("n", new_block.block_num())("w", new_block.witness)("t", new_block.timestamp)("c", fc::time_point::now())); + if (new_block.block_num() % 10000 == 0) { + ilog("Pushing new block #${n} from ${w} with timestamp ${t} at time ${c}", ("n", new_block.block_num())("w", new_block.witness)("t", new_block.timestamp)("c", fc::time_point::now())); + } auto session = start_undo_session(); apply_block(new_block, skip); session.push(); @@ -1403,7 +1405,7 @@ void database::init_genesis( uint64_t init_supply ) auth.money.weight_threshold = 0; }); - ilog( "!!!!!! Preparing to create genesis account..." ); + ilog( "Preparing to create genesis account..." ); create< dynamic_global_property_object >( [&]( dynamic_global_property_object& p ) { p.mining_target = fc::sha256(XGT_MINING_TARGET_START); @@ -1702,10 +1704,11 @@ void database::_apply_block( const signed_block& next_block ) // process_required_actions( req_actions ); // process_optional_actions( opt_actions ); - // Ensure no duplicate mining rewards - /// @since 1.1.2 reject blocks with duplicate rewards + /// Ensure no duplicate mining rewards + /// @since 1.2.0 reject blocks with duplicate rewards + /// @since 1.3.0 deprecated uint32_t head_num = head_block_num(); - if (head_num >= 907200) + if (head_num >= 907200 && head_num < 2116800) { std::set< wallet_name_type > rewarded_wallets; for( const auto& trx : next_block.transactions ) @@ -1721,7 +1724,7 @@ void database::_apply_block( const signed_block& next_block ) auto it = rewarded_wallets.find(wallet_name); if (it != rewarded_wallets.end()) { - wlog("!!!!!! Wallet ${w} already rewarded, discarding duplicate operation!", ("w", wallet_name)); + // Wallet already rewarded, discarding duplicate operation continue; } rewarded_wallets.insert(wallet_name); @@ -1729,6 +1732,63 @@ void database::_apply_block( const signed_block& next_block ) } } + /// @since 1.3.0 reward the first miner, on the current ("next") block + if (head_num >= 2116800) + { + optional< wallet_name_type > rewarded_miner; + for( const auto& trx : next_block.transactions ) + { + if ( rewarded_miner ) + break; + const auto& operations = trx.operations; + for (auto& op : operations) + { + if ( rewarded_miner ) + break; + if ( !is_pow_operation(op) ) + continue; + const pow_operation& o = op.template get< pow_operation >(); + const wallet_name_type& wallet_name = o.get_worker_name(); + + const auto& dgp = get_dynamic_global_properties(); + uint32_t target_pow = get_pow_summary_target(); + + const auto& work = o.work.get< sha2_pow >(); + FC_ASSERT( work.pow_summary < target_pow, "Insufficient work difficulty. Work: ${w}, Target: ${t}", ("w",work.pow_summary)("t", target_pow) ); + FC_ASSERT( work.prev_block == next_block.previous, "Op prev block id ${m} doesn't match prev block id ${n} do not match.", ("m",work.prev_block)("n",next_block.previous) ); + FC_ASSERT( next_block.witness == wallet_name, "Block miner name ${m} and op miner name (${n}) do not match.", ("m",next_block.witness)("n",wallet_name) ); + wallet_name_type worker_account = work.input.worker_account; + + // TODO: Check for 0 + int halvings = (XGT_STARTING_OFFSET + dgp.head_block_number) / XGT_MINING_REWARD_HALVING_INTERVAL; + // TODO: Assert no overflow + long divisor = 1L << halvings; + asset base_reward = XGT_MINING_REWARD; + double value = base_reward.amount.value * (1.0 / static_cast(divisor)); + long price = static_cast(floor(value)); + asset reward = asset(price, base_reward.symbol); + ilog("Mining reward for ${w} amount ${r}", ("w",worker_account)("r",reward)); + + const wallet_object* w = find_account( worker_account ); + const witness_object* cur_witness = find_witness( worker_account ); + if (w == nullptr) + { + wlog( "Wallet does not exist for worker account ${w}", ("w",worker_account) ); + throw operation_validate_exception(); + } + if (cur_witness == nullptr) + { + wlog( "Witness does not exist for worker account ${w}", ("w",worker_account) ); + throw operation_validate_exception(); + } + + adjust_balance(worker_account, reward); + + rewarded_miner = optional< wallet_name_type >(wallet_name); + } + } + } + // Adjust mining difficulty const uint32_t frequency = XGT_MINING_RECALC_EVERY_N_BLOCKS; if( next_block_num == 1) diff --git a/libraries/chain/xgt_evaluator.cpp b/libraries/chain/xgt_evaluator.cpp index d3943056..03dae1ce 100644 --- a/libraries/chain/xgt_evaluator.cpp +++ b/libraries/chain/xgt_evaluator.cpp @@ -918,6 +918,10 @@ void pow_evaluator::do_apply( const pow_operation& o ) { database& db = this->db(); + uint32_t head_num = db.head_block_num(); + if (head_num >= 2116800) + return; + const auto& dgp = db.get_dynamic_global_properties(); uint32_t target_pow = db.get_pow_summary_target(); diff --git a/libraries/plugins/chain/chain_plugin.cpp b/libraries/plugins/chain/chain_plugin.cpp index edb0d796..ba8bf142 100644 --- a/libraries/plugins/chain/chain_plugin.cpp +++ b/libraries/plugins/chain/chain_plugin.cpp @@ -37,15 +37,23 @@ namespace asio = boost::asio; struct generate_block_request { - generate_block_request( const fc::time_point_sec w, const wallet_name_type& wo, const fc::ecc::private_key& priv_key, uint32_t s ) : + generate_block_request( + const fc::time_point_sec w, + const wallet_name_type& wo, + const fc::ecc::private_key& priv_key, + fc::optional< xgt::chain::signed_transaction > br, + uint32_t s + ) : when( w ), witness_recovery( wo ), block_signing_private_key( priv_key ), + block_reward( br ), skip( s ) {} const fc::time_point_sec when; const wallet_name_type& witness_recovery; const fc::ecc::private_key& block_signing_private_key; + fc::optional< xgt::chain::signed_transaction > block_reward; uint32_t skip; signed_block block; }; @@ -98,7 +106,7 @@ class chain_plugin_impl std::string to_state = ""; statefile::state_format_info state_format; - uint32_t allow_future_time = 5; + uint32_t allow_future_time = 48; bool running = true; std::shared_ptr< std::thread > write_processor_thread; @@ -183,6 +191,7 @@ struct write_request_visitor req->when, req->witness_recovery, req->block_signing_private_key, + fc::optional< xgt::chain::signed_transaction >(req->block_reward), req->skip ); @@ -733,9 +742,10 @@ xgt::chain::signed_block chain_plugin::generate_block( const fc::time_point_sec when, const wallet_name_type& witness_recovery, const fc::ecc::private_key& block_signing_private_key, + fc::optional< xgt::chain::signed_transaction > block_reward, uint32_t skip ) { - generate_block_request req( when, witness_recovery, block_signing_private_key, skip ); + generate_block_request req( when, witness_recovery, block_signing_private_key, block_reward, skip ); boost::promise< void > prom; write_context cxt; cxt.req_ptr = &req; diff --git a/libraries/plugins/chain/include/xgt/plugins/chain/abstract_block_producer.hpp b/libraries/plugins/chain/include/xgt/plugins/chain/abstract_block_producer.hpp index e3d2943d..64bbec7f 100644 --- a/libraries/plugins/chain/include/xgt/plugins/chain/abstract_block_producer.hpp +++ b/libraries/plugins/chain/include/xgt/plugins/chain/abstract_block_producer.hpp @@ -14,6 +14,7 @@ class abstract_block_producer { fc::time_point_sec when, const xgt::chain::wallet_name_type& witness_recovery, const fc::ecc::private_key& block_signing_private_key, + fc::optional< xgt::chain::signed_transaction > block_reward, uint32_t skip = xgt::chain::database::skip_nothing) = 0; }; diff --git a/libraries/plugins/chain/include/xgt/plugins/chain/chain_plugin.hpp b/libraries/plugins/chain/include/xgt/plugins/chain/chain_plugin.hpp index c8331cec..da1dbed2 100644 --- a/libraries/plugins/chain/include/xgt/plugins/chain/chain_plugin.hpp +++ b/libraries/plugins/chain/include/xgt/plugins/chain/chain_plugin.hpp @@ -51,6 +51,7 @@ class chain_plugin : public plugin< chain_plugin > const fc::time_point_sec when, const wallet_name_type& witness_recovery, const fc::ecc::private_key& block_signing_private_key, + fc::optional< xgt::chain::signed_transaction > block_reward, uint32_t skip = database::skip_nothing ); diff --git a/libraries/plugins/debug_node/debug_node_plugin.cpp b/libraries/plugins/debug_node/debug_node_plugin.cpp index 86a20ee1..fe09322a 100644 --- a/libraries/plugins/debug_node/debug_node_plugin.cpp +++ b/libraries/plugins/debug_node/debug_node_plugin.cpp @@ -253,7 +253,11 @@ void debug_node_plugin::debug_generate_blocks( break; } - bp.generate_block( scheduled_time, scheduled_witness_name, *debug_private_key, args.skip ); + // For expediency, this is just a hacked together block; a less-fake version would be a + // PoW operation. + protocol::signed_transaction fake_block_reward; + + bp.generate_block( scheduled_time, scheduled_witness_name, *debug_private_key, fake_block_reward, args.skip ); ++produced; slot = new_slot; } diff --git a/libraries/plugins/webserver/webserver_plugin.cpp b/libraries/plugins/webserver/webserver_plugin.cpp index 6a5805ad..9d03724f 100644 --- a/libraries/plugins/webserver/webserver_plugin.cpp +++ b/libraries/plugins/webserver/webserver_plugin.cpp @@ -118,10 +118,7 @@ class webserver_plugin_impl webserver_plugin_impl(thread_pool_size_t thread_pool_size) : thread_pool_work( this->thread_pool_ios ) { - if (http_endpoint || unix_endpoint) { - for( uint32_t i = 0; i < thread_pool_size; ++i ) - thread_pool.create_thread( boost::bind( &asio::io_service::run, &thread_pool_ios ) ); - } + this->thread_pool_size = thread_pool_size; } void start_webserver(); @@ -140,6 +137,7 @@ class webserver_plugin_impl optional< boost::asio::local::stream_protocol::endpoint > unix_endpoint; websocket_local_server_type unix_server; + thread_pool_size_t thread_pool_size; boost::thread_group thread_pool; asio::io_service thread_pool_ios; asio::io_service::work thread_pool_work; @@ -150,6 +148,10 @@ class webserver_plugin_impl void webserver_plugin_impl::start_webserver() { + if (http_endpoint || unix_endpoint) + for( uint32_t i = 0; i < thread_pool_size; ++i ) + thread_pool.create_thread( boost::bind( &asio::io_service::run, &thread_pool_ios ) ); + if( http_endpoint ) { http_thread = std::make_shared( [&]() @@ -361,6 +363,9 @@ void webserver_plugin::plugin_initialize( const variables_map& options ) my->unix_endpoint = ep; ilog( "configured http to listen on ${ep}", ("ep", unix_endpoint )); } + + if (my->http_endpoint || my->unix_endpoint) { + } } void webserver_plugin::plugin_startup() diff --git a/libraries/plugins/witness/block_producer.cpp b/libraries/plugins/witness/block_producer.cpp index b12e263f..de02d50d 100644 --- a/libraries/plugins/witness/block_producer.cpp +++ b/libraries/plugins/witness/block_producer.cpp @@ -16,7 +16,13 @@ namespace xgt { namespace plugins { namespace witness { -chain::signed_block block_producer::generate_block(fc::time_point_sec when, const chain::wallet_name_type& witness_recovery, const fc::ecc::private_key& block_signing_private_key, uint32_t skip) +chain::signed_block block_producer::generate_block( + fc::time_point_sec when, + const chain::wallet_name_type& witness_recovery, + const fc::ecc::private_key& block_signing_private_key, + fc::optional< xgt::chain::signed_transaction > trx, + uint32_t skip +) { chain::signed_block result; try @@ -29,7 +35,7 @@ chain::signed_block block_producer::generate_block(fc::time_point_sec when, cons { try { - result = _generate_block( when, witness_recovery, block_signing_private_key ); + result = _generate_block( when, witness_recovery, block_signing_private_key, trx ); } FC_CAPTURE_AND_RETHROW( (witness_recovery) ) }); @@ -44,7 +50,12 @@ chain::signed_block block_producer::generate_block(fc::time_point_sec when, cons return result; } -chain::signed_block block_producer::_generate_block(fc::time_point_sec when, const chain::wallet_name_type& witness, const fc::ecc::private_key& block_signing_private_key) +chain::signed_block block_producer::_generate_block( + fc::time_point_sec when, + const chain::wallet_name_type& witness, + const fc::ecc::private_key& block_signing_private_key, + fc::optional< xgt::chain::signed_transaction > block_reward +) { try { uint32_t skip = _db.get_node_properties().skip_flags; // const auto& witness_obj = _db.get_witness( witness ); @@ -70,7 +81,7 @@ chain::signed_block block_producer::_generate_block(fc::time_point_sec when, con adjust_hardfork_version_vote( _db.get_witness( witness ), pending_block ); - apply_pending_transactions( witness, when, pending_block ); + apply_pending_transactions( witness, when, pending_block, block_reward ); // We have temporarily broken the invariant that // _pending_tx_session is the result of applying _pending_tx, as @@ -118,9 +129,11 @@ void block_producer::adjust_hardfork_version_vote(const chain::witness_object& w } void block_producer::apply_pending_transactions( - const chain::wallet_name_type& witness_recovery, - fc::time_point_sec when, - chain::signed_block& pending_block) + const chain::wallet_name_type& witness_recovery, + fc::time_point_sec when, + chain::signed_block& pending_block, + fc::optional< xgt::chain::signed_transaction > block_reward +) { size_t total_block_size = fc::raw::pack_size( pending_block ); total_block_size += sizeof( uint32_t ); // Transaction vector length @@ -153,7 +166,39 @@ void block_producer::apply_pending_transactions( dgp.current_witness = witness_recovery; }); + uint64_t postponed_tx_count = 0; + + + // postpone transaction if it would make block too big + + if (block_reward) + { + uint64_t new_total_size = total_block_size + fc::raw::pack_size( *block_reward ); + if (new_total_size >= maximum_transaction_partition_size) + { + postponed_tx_count++; + } + else + { + try + { + auto temp_session = _db.start_undo_session(); + _db.apply_transaction(*block_reward, _db.get_node_properties().skip_flags); + temp_session.squash(); + + total_block_size = new_total_size; + pending_block.transactions.push_back(*block_reward); + } + catch (const fc::exception& e) + { + // Do nothing, transaction will not be re-applied + //wlog( "Transaction was not processed while generating block due to ${e}", ("e", e) ); + //wlog( "The transaction was ${t}", ("t", tx) ); + } + } + } + // pop pending state (reset to head block state) for( const chain::signed_transaction& tx : _db._pending_tx ) { diff --git a/libraries/plugins/witness/include/xgt/plugins/witness/block_producer.hpp b/libraries/plugins/witness/include/xgt/plugins/witness/block_producer.hpp index a5389d6b..8fe79413 100644 --- a/libraries/plugins/witness/include/xgt/plugins/witness/block_producer.hpp +++ b/libraries/plugins/witness/include/xgt/plugins/witness/block_producer.hpp @@ -22,7 +22,9 @@ class block_producer : public chain::abstract_block_producer { fc::time_point_sec when, const chain::wallet_name_type& witness_recovery, const fc::ecc::private_key& block_signing_private_key, - uint32_t skip = chain::database::skip_nothing); + fc::optional< xgt::chain::signed_transaction > trx, + uint32_t skip = chain::database::skip_nothing + ); private: chain::database& _db; @@ -30,14 +32,18 @@ class block_producer : public chain::abstract_block_producer { chain::signed_block _generate_block( fc::time_point_sec when, const chain::wallet_name_type& witness_recovery, - const fc::ecc::private_key& block_signing_private_key); + const fc::ecc::private_key& block_signing_private_key, + fc::optional< xgt::chain::signed_transaction > block_reward + ); void adjust_hardfork_version_vote( const chain::witness_object& witness, chain::signed_block& pending_block ); void apply_pending_transactions( const chain::wallet_name_type& witness_recovery, fc::time_point_sec when, - chain::signed_block& pending_block); + chain::signed_block& pending_block, + fc::optional< xgt::chain::signed_transaction > trx + ); }; } } } // xgt::plugins::witness diff --git a/libraries/plugins/witness/witness_plugin.cpp b/libraries/plugins/witness/witness_plugin.cpp index 31cbb81b..863a12b7 100644 --- a/libraries/plugins/witness/witness_plugin.cpp +++ b/libraries/plugins/witness/witness_plugin.cpp @@ -314,13 +314,37 @@ namespace detail { { wlog("Mined block proceeding #${n} with timestamp ${t} at time ${c}", ("n", block_num)("t", head_block_time)("c", fc::time_point::now())); fc::time_point now = fc::time_point::now(); - auto block = _chain_plugin.generate_block( now, miner, pk, _production_skip_flags); - _db.push_block(block, (uint32_t)0); - appbase::app().get_plugin< xgt::plugins::p2p::p2p_plugin >().broadcast_block( block ); - - wlog( "Broadcasting Proof of Work for ${miner}", ("miner", miner) ); - _db.push_transaction( trx ); - appbase::app().get_plugin< xgt::plugins::p2p::p2p_plugin >().broadcast_transaction( trx ); + uint32_t head_num = _db.head_block_num(); + if (head_num < 2116800) + { + auto block_reward = fc::optional< protocol::signed_transaction >(); + auto block = _chain_plugin.generate_block( + now, + miner, + pk, + block_reward, + _production_skip_flags + ); + _db.push_block(block, (uint32_t)0); + appbase::app().get_plugin< xgt::plugins::p2p::p2p_plugin >().broadcast_block( block ); + wlog( "Broadcasting Proof of Work for ${miner}", ("miner", miner) ); + _db.push_transaction( trx ); + appbase::app().get_plugin< xgt::plugins::p2p::p2p_plugin >().broadcast_transaction( trx ); + } + else + { + auto block_reward = fc::optional< protocol::signed_transaction >(trx); + auto block = _chain_plugin.generate_block( + now, + miner, + pk, + block_reward, + _production_skip_flags + ); + _db.push_block(block, (uint32_t)0); + appbase::app().get_plugin< xgt::plugins::p2p::p2p_plugin >().broadcast_block( block ); + wlog( "Broadcasting Proof of Work for ${miner}", ("miner", miner) ); + } ++this->_head_block_num; wlog( "Broadcast succeeded!" ); @@ -394,9 +418,15 @@ namespace detail { if (*name_ptr == XGT_INIT_MINER_NAME) { wlog("Generating genesis block..."); - auto pair = _private_keys.begin(); - auto block = _chain_plugin.generate_block( now, XGT_INIT_MINER_NAME, pair->second, _production_skip_flags ); + auto block_reward = fc::optional< xgt::chain::signed_transaction >(); + auto block = _chain_plugin.generate_block( + now, + XGT_INIT_MINER_NAME, + pair->second, + block_reward, + _production_skip_flags + ); _db.push_block(block, (uint32_t)0); this->_head_block_num++; schedule_production_loop();