From 4f4ef31a7c8e1e19c513d386bf61bd622d4c5cb9 Mon Sep 17 00:00:00 2001 From: deadlock Date: Wed, 8 May 2019 00:36:21 +0800 Subject: [PATCH 01/12] bugfix: fork_db migration incorrect pos align --- libraries/chain/fork_database.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 21cfd79dbc2..49df83289bc 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -78,10 +78,20 @@ namespace eosio { namespace chain { vector tmp = data; tmp.insert(tmp.begin(), {0,0,0,0}); fc::datastream tmp_ds(tmp.data(), tmp.size()); - block_state s; - fc::raw::unpack( tmp_ds, s ); - //prepend 4bytes for pbft_stable_checkpoint_blocknum and append 2 bytes for pbft_prepared and pbft_my_prepare - auto tmp_data_length = tmp_ds.tellp() - 6; + block_header_state h; + fc::raw::unpack( tmp_ds, h ); + signed_block_ptr b; + fc::raw::unpack( tmp_ds, b ); + bool validated; + fc::raw::unpack( tmp_ds, validated ); + bool in_current_chain; + fc::raw::unpack( tmp_ds, in_current_chain ); + block_state s{h}; + s.block = b; + s.validated = validated; + s.in_current_chain = in_current_chain; + //prepend 4bytes for pbft_stable_checkpoint_blocknum + auto tmp_data_length = tmp_ds.tellp() - 4; data.erase(data.begin(),data.begin()+tmp_data_length); s.pbft_prepared = false; s.pbft_my_prepare = false; From a8b587589a09f9fa3a3fa1bdda32126b932e4de9 Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 8 May 2019 14:05:24 +0800 Subject: [PATCH 02/12] bug fix: return default block id when trying to fetch block num 0; update pbft status during ctrl init. --- libraries/chain/controller.cpp | 56 +++++++++++++++++-------------- libraries/chain/pbft_database.cpp | 2 +- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 55f3a939acd..78ad0af441c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -389,6 +389,8 @@ struct controller_impl { } } + update_pbft_status(); + if( shutdown() ) return; const auto& ubi = reversible_blocks.get_index(); @@ -430,11 +432,38 @@ struct controller_impl { //generate upo. try { db.get(); + if (pbft_enabled) wlog("pbft enabled"); } catch( const boost::exception& e) { wlog("no upo found, generating..."); db.create([](auto&){}); } + } + + void update_pbft_status() { + auto utb = optional{}; + auto& upo = db.get(); + if (upo.upgrade_target_block_num > 0) utb = upo.upgrade_target_block_num; + auto ucb = optional{}; + if (upo.upgrade_complete_block_num > 0) ucb = upo.upgrade_complete_block_num; + + + if (utb && !ucb && head->dpos_irreversible_blocknum >= *utb) { + db.modify( upo, [&]( auto& up ) { + up.upgrade_complete_block_num = head->block_num; + }); + if (!replaying) wlog("pbft will be working after the block ${b}", ("b", head->block_num)); + } + + if ( !pbft_enabled && utb && head->block_num >= *utb) { + if (!pbft_upgrading) pbft_upgrading = true; + + // new version starts from the next block of ucb, this is to avoid inconsistency after pre calculation inside schedule loop. + if (ucb && head->block_num > *ucb) { + if (pbft_upgrading) pbft_upgrading = false; + pbft_enabled = true; + } + } } ~controller_impl() { @@ -1338,30 +1367,7 @@ struct controller_impl { pending.emplace(maybe_session()); } - auto utb = optional{}; - auto& upo = db.get(); - if (upo.upgrade_target_block_num > 0) utb = upo.upgrade_target_block_num; - - auto ucb = optional{}; - if (upo.upgrade_complete_block_num > 0) ucb = upo.upgrade_complete_block_num; - - - if (utb && !ucb && head->dpos_irreversible_blocknum >= *utb) { - db.modify( upo, [&]( auto& up ) { - up.upgrade_complete_block_num = head->block_num; - }); - if (!replaying) wlog("pbft will be working after the block ${b}", ("b", head->block_num)); - } - - if ( !pbft_enabled && utb && head->block_num >= *utb) { - if (!pbft_upgrading) pbft_upgrading = true; - - // new version starts from the next block of ucb, this is to avoid inconsistency after pre calculation inside schedule loop. - if (ucb && head->block_num > *ucb) { - if (pbft_upgrading) pbft_upgrading = false; - pbft_enabled = true; - } - } + update_pbft_status(); pending->_block_status = s; pending->_producer_block_id = producer_block_id; @@ -2329,7 +2335,7 @@ block_id_type controller::last_stable_checkpoint_block_id() const { if( block_header::num_from_id(tapos_block_summary.block_id) == lscb_num ) return tapos_block_summary.block_id; - + if (lscb_num == 0) return block_id_type{}; return fetch_block_by_number(lscb_num)->id(); } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index dea1e58da90..95ab033c85e 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -1173,7 +1173,7 @@ namespace eosio { const auto& ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; if (!ctrl.is_pbft_enabled()) return false; return in >= ucb - && (in % 100 == 1 || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end()); + && (in == ucb + 1 || in % 100 == 1 || std::find(prepare_watermarks.begin(), prepare_watermarks.end(), in) != prepare_watermarks.end()); }; for (auto i = psp->block_num; From 720b6172d7dd1ffa4de2b309318d6b4323ea8814 Mon Sep 17 00:00:00 2001 From: deadlock Date: Wed, 8 May 2019 14:11:10 +0800 Subject: [PATCH 03/12] add migration log --- libraries/chain/fork_database.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 49df83289bc..0ce58acec08 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -67,7 +67,7 @@ namespace eosio { namespace chain { bool is_version_1 = version_label != "version"; if(is_version_1){ /*start upgrade migration and this is a hack and ineffecient, but lucky we only need to do it once */ - + wlog("doing LIB upgrade migration"); auto start = ds.pos(); unsigned_int size; fc::raw::unpack( ds, size ); auto skipped_size_pos = ds.pos(); @@ -75,6 +75,7 @@ namespace eosio { namespace chain { vector data(content.begin()+(skipped_size_pos - start), content.end()); for( uint32_t i = 0, n = size.value; i < n; ++i ) { + wlog("processing block state in fork database ${i} of ${size}", ("i",i+1)("size",n)); vector tmp = data; tmp.insert(tmp.begin(), {0,0,0,0}); fc::datastream tmp_ds(tmp.data(), tmp.size()); From e1a52bd542c1a27d0c2ecda9e577bc92b7559891 Mon Sep 17 00:00:00 2001 From: deadlock Date: Wed, 8 May 2019 17:40:24 +0800 Subject: [PATCH 04/12] improve: change algorithm in LIB upgrade fork database migration, huge performance boost when fork db size is large --- libraries/chain/fork_database.cpp | 19 +++++++++++-------- .../eosio/chain/block_header_state.hpp | 6 +++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 0ce58acec08..d6624b54f04 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -74,13 +74,19 @@ namespace eosio { namespace chain { vector data(content.begin()+(skipped_size_pos - start), content.end()); + data.insert(data.end(),{0,0,0,0});//append 4 bytes for the very last block state, avoid underflow in case + fc::datastream tmp_ds(data.data(), data.size()); + for( uint32_t i = 0, n = size.value; i < n; ++i ) { wlog("processing block state in fork database ${i} of ${size}", ("i",i+1)("size",n)); - vector tmp = data; - tmp.insert(tmp.begin(), {0,0,0,0}); - fc::datastream tmp_ds(tmp.data(), tmp.size()); block_header_state h; fc::raw::unpack( tmp_ds, h ); + h.pbft_stable_checkpoint_blocknum = 0; + + //move pos backward 4 bytes for pbft_stable_checkpoint_blocknum + auto tmp_accumulated_data_length = tmp_ds.tellp() - 4; + tmp_ds.seekp(tmp_accumulated_data_length); + signed_block_ptr b; fc::raw::unpack( tmp_ds, b ); bool validated; @@ -91,16 +97,13 @@ namespace eosio { namespace chain { s.block = b; s.validated = validated; s.in_current_chain = in_current_chain; - //prepend 4bytes for pbft_stable_checkpoint_blocknum - auto tmp_data_length = tmp_ds.tellp() - 4; - data.erase(data.begin(),data.begin()+tmp_data_length); + s.pbft_prepared = false; s.pbft_my_prepare = false; set( std::make_shared( move( s ) ) ); } - fc::datastream head_id_stream(data.data(), data.size()); block_id_type head_id; - fc::raw::unpack( head_id_stream, head_id ); + fc::raw::unpack( tmp_ds, head_id ); my->head = get_block( head_id ); /*end upgrade migration*/ diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 26ba42cc9f8..a443532013a 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -10,7 +10,6 @@ namespace eosio { namespace chain { * @brief defines the minimum state necessary to validate transaction headers */ struct block_header_state { - uint32_t pbft_stable_checkpoint_blocknum = 0; block_id_type id; uint32_t block_num = 0; signed_block_header header; @@ -28,6 +27,7 @@ struct block_header_state { public_key_type block_signing_key; vector confirm_count; vector confirmations; + uint32_t pbft_stable_checkpoint_blocknum = 0; block_header_state next( const signed_block_header& h, bool trust = false, bool new_version = false)const; block_header_state generate_next( block_timestamp_type when, bool new_version = false )const; @@ -62,10 +62,10 @@ struct block_header_state { } } /// namespace eosio::chain FC_REFLECT( eosio::chain::block_header_state, - (pbft_stable_checkpoint_blocknum) (id)(block_num)(header)(dpos_proposed_irreversible_blocknum)(dpos_irreversible_blocknum)(bft_irreversible_blocknum) (pending_schedule_lib_num)(pending_schedule_hash) (pending_schedule)(active_schedule)(blockroot_merkle) (producer_to_last_produced)(producer_to_last_implied_irb)(block_signing_key) - (confirm_count)(confirmations) ) + (confirm_count)(confirmations) + (pbft_stable_checkpoint_blocknum)) From 27e417730ae26cdc07e98bd0a14a9956952a9aac Mon Sep 17 00:00:00 2001 From: oldcold Date: Wed, 8 May 2019 21:22:54 +0800 Subject: [PATCH 05/12] use schedule in ucb when there is no stable checkpoint. --- libraries/chain/controller.cpp | 6 ++++-- libraries/chain/pbft_database.cpp | 17 +++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 78ad0af441c..7c3ba286c4d 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2335,8 +2335,10 @@ block_id_type controller::last_stable_checkpoint_block_id() const { if( block_header::num_from_id(tapos_block_summary.block_id) == lscb_num ) return tapos_block_summary.block_id; - if (lscb_num == 0) return block_id_type{}; - return fetch_block_by_number(lscb_num)->id(); + + auto b = fetch_block_by_number(lscb_num); + if (b) return b->id(); + return block_id_type{}; } diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 95ab033c85e..3d7c736285e 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -1413,14 +1413,19 @@ namespace eosio { } producer_schedule_type pbft_database::lscb_active_producers() const { - auto lscb_num = ctrl.last_stable_checkpoint_block_num(); - if (lscb_num == 0) return ctrl.initial_schedule(); + auto num = ctrl.last_stable_checkpoint_block_num(); + + if (num == 0) { + const auto &ucb = ctrl.get_upgrade_properties().upgrade_complete_block_num; + if (ucb == 0) return ctrl.initial_schedule(); + num = ucb; + } - auto lscb_state = ctrl.fetch_block_state_by_number(lscb_num); - if (!lscb_state) return ctrl.initial_schedule(); + auto bs = ctrl.fetch_block_state_by_number(num); + if (!bs) return ctrl.initial_schedule(); - if (lscb_state->pending_schedule.producers.empty()) return lscb_state->active_schedule; - return lscb_state->pending_schedule; + if (bs->pending_schedule.producers.empty()) return bs->active_schedule; + return bs->pending_schedule; } chain_id_type pbft_database::chain_id() { From 51843061e52d8948a52edb50f6dbd9e74311489a Mon Sep 17 00:00:00 2001 From: deadlock Date: Fri, 10 May 2019 16:59:07 +0800 Subject: [PATCH 06/12] update snapshot migration logic to reflect struct change in block header state --- libraries/chain/include/eosio/chain/snapshot.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/snapshot.hpp b/libraries/chain/include/eosio/chain/snapshot.hpp index 70486b747f9..52b986510bd 100644 --- a/libraries/chain/include/eosio/chain/snapshot.hpp +++ b/libraries/chain/include/eosio/chain/snapshot.hpp @@ -232,9 +232,9 @@ namespace eosio { namespace chain { std::ostringstream sstream; sstream << in.rdbuf(); std::string str(sstream.str()); - //prepend uint32_t 0 + //append uint32_t 0 std::vector tmp(str.begin(), str.end()); - tmp.insert(tmp.begin(), {0,0,0,0}); + tmp.insert(tmp.end(), {0,0,0,0}); fc::datastream tmp_ds(tmp.data(), tmp.size()); fc::raw::unpack(tmp_ds, data); auto original_data_length = tmp_ds.tellp() - 4; From ddc3e6128f5192e51498a9bc056bdf8bfe80f9d0 Mon Sep 17 00:00:00 2001 From: oldcold Date: Fri, 10 May 2019 22:28:07 +0800 Subject: [PATCH 07/12] add forkdb block states into snapshot after pbft is enabled; fix replay bug. --- libraries/chain/controller.cpp | 89 +++++++++++++------ .../include/eosio/chain/chain_snapshot.hpp | 5 ++ 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 7c3ba286c4d..c6f611de03c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -361,12 +361,14 @@ struct controller_impl { read_from_snapshot( snapshot ); - //do upgrade migration if necessary; - migrate_upgrade(); //compatiable for snapshot integrity test + //do upgrade migration if necessary; + migrate_upgrade(); //compatiable for snapshot integrity test auto end = blog.read_head(); if( !end ) { - blog.reset( conf.genesis, signed_block_ptr(), head->block_num + 1 ); + auto reset_block_num = head->block_num + 1; + if (pbft_enabled) reset_block_num = head->pbft_stable_checkpoint_blocknum; + blog.reset( conf.genesis, signed_block_ptr(), reset_block_num ); } else if( end->block_num() > head->block_num ) { replay( shutdown ); } else { @@ -374,8 +376,8 @@ struct controller_impl { "Block log is provided with snapshot but does not contain the head block from the snapshot" ); } } else { - //do upgrade migration if necessary; - migrate_upgrade(); //compatiable for snapshot integrity test + //do upgrade migration if necessary; + migrate_upgrade(); //compatiable for snapshot integrity test if( !head ) { initialize_fork_db(); // set head to genesis state } @@ -388,9 +390,7 @@ struct controller_impl { report_integrity_hash = true; } } - - update_pbft_status(); - + if( shutdown() ) return; const auto& ubi = reversible_blocks.get_index(); @@ -437,6 +437,7 @@ struct controller_impl { wlog("no upo found, generating..."); db.create([](auto&){}); } + update_pbft_status(); } void update_pbft_status() { @@ -556,9 +557,21 @@ struct controller_impl { section.add_row(batch_pbft_snapshot_migration{}, db); }); - snapshot->write_section([this]( auto §ion ){ - section.template add_row(*fork_db.head(), db); - }); + if (pbft_enabled) { + snapshot->write_section([this]( auto §ion ) { + section.add_row(batch_pbft_enabled{}, db); + }); + snapshot->write_section([this](auto §ion) { + auto bid = fork_db.get_block_in_current_chain_by_num(fork_db.head()->pbft_stable_checkpoint_blocknum)->id; + EOS_ASSERT(bid != block_id_type{}, snapshot_exception, "cannot find lscb block"); + auto bss = fork_db.fetch_branch_from(fork_db.head()->id, bid).first; + section.template add_row(bss, db); + }); + } else { + snapshot->write_section([this]( auto §ion ){ + section.template add_row(*fork_db.head(), db); + }); + } controller_index_set::walk_indices([this, &snapshot]( auto utils ){ using value_t = typename decltype(utils)::index_t::value_type; @@ -589,19 +602,42 @@ struct controller_impl { }); bool migrated = snapshot->has_section(); - if(migrated) { - snapshot->read_section([this](auto §ion) { - block_header_state head_header_state; - section.read_row(head_header_state, db); - - auto head_state = std::make_shared(head_header_state); - fork_db.set(head_state); - fork_db.set_validity(head_state, true); - fork_db.mark_in_current_chain(head_state, true); - head = head_state; - snapshot_head_block = head->block_num; - }); - }else{ + if (migrated) { + auto upgraded = snapshot->has_section(); + if (upgraded) { + snapshot->read_section([this](auto §ion) { + branch_type bss; + section.template read_row(bss, db); + EOS_ASSERT(!bss.empty(), snapshot_exception, "no last stable checkpoint block in the snapshot"); + + wlog("${n} reversible blocks found in the snapshot", ("n", bss.size())); + + for (auto i = bss.rbegin(); i != bss.rend(); ++i ) { + if (i == bss.rbegin()) { + fork_db.set(*i); + snapshot_head_block = (*i)->block_num; + } else { + fork_db.add((*i), true, true); + } + fork_db.set_validity((*i), true); + fork_db.mark_in_current_chain((*i), true); + } + head = fork_db.head(); + }); + } else { + snapshot->read_section([this](auto §ion) { + block_header_state head_header_state; + section.read_row(head_header_state, db); + + auto head_state = std::make_shared(head_header_state); + fork_db.set(head_state); + fork_db.set_validity(head_state, true); + fork_db.mark_in_current_chain(head_state, true); + head = head_state; + snapshot_head_block = head->block_num; + }); + } + } else { snapshot->read_section([this](snapshot_reader::section_reader §ion) { block_header_state head_header_state; section.read_pbft_migrate_row(head_header_state, db); @@ -1622,6 +1658,9 @@ struct controller_impl { EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); + set_pbft_lib(); + set_pbft_lscb(); + try { EOS_ASSERT( b, block_validate_exception, "trying to push empty block" ); EOS_ASSERT( (s == controller::block_status::irreversible || s == controller::block_status::validated), @@ -1642,9 +1681,7 @@ struct controller_impl { for (const auto &extn: b->block_extensions) { if (extn.first == static_cast(block_extension_type::pbft_stable_checkpoint)) { pbft_commit_local(b->id()); - set_pbft_lib(); set_pbft_latest_checkpoint(b->id()); - set_pbft_lscb(); break; } } diff --git a/libraries/chain/include/eosio/chain/chain_snapshot.hpp b/libraries/chain/include/eosio/chain/chain_snapshot.hpp index 884293360a5..43801333d2f 100644 --- a/libraries/chain/include/eosio/chain/chain_snapshot.hpp +++ b/libraries/chain/include/eosio/chain/chain_snapshot.hpp @@ -33,7 +33,12 @@ struct batch_pbft_snapshot_migration{ bool migrated = true; }; +struct batch_pbft_enabled { + bool enabled = true; +}; + } } FC_REFLECT(eosio::chain::chain_snapshot_header,(version)) FC_REFLECT(eosio::chain::batch_pbft_snapshot_migration,(migrated)) +FC_REFLECT(eosio::chain::batch_pbft_enabled,(enabled)) \ No newline at end of file From 899ee7aec0106aaa75deb5f7c1854b8d86d38b43 Mon Sep 17 00:00:00 2001 From: oldcold Date: Sat, 11 May 2019 10:30:14 +0800 Subject: [PATCH 08/12] change block producing log --- plugins/producer_plugin/producer_plugin.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index b41e159a6db..e614e84d398 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1607,10 +1607,18 @@ void producer_plugin_impl::produce_block() { block_state_ptr new_bs = chain.head_block_state(); _producer_watermarks[new_bs->header.producer] = chain.head_block_num(); - ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, lscb: ${lscb}]", - ("p",new_bs->header.producer)("id",fc::variant(new_bs->id).as_string().substr(0,16)) - ("n",new_bs->block_num)("t",new_bs->header.timestamp) - ("count",new_bs->block->transactions.size())("lib",chain.last_irreversible_block_num())("lscb", chain.last_stable_checkpoint_block_num())); + if (chain.is_pbft_enabled()) { + ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, lscb: ${lscb}]", + ("p", new_bs->header.producer)("id", fc::variant(new_bs->id).as_string().substr(0, 16)) + ("n", new_bs->block_num)("t", new_bs->header.timestamp) + ("count", new_bs->block->transactions.size()) + ("lib", chain.last_irreversible_block_num())("lscb", chain.last_stable_checkpoint_block_num())); + } else { + ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, confirmed: ${confs}]", + ("p",new_bs->header.producer)("id",fc::variant(new_bs->id).as_string().substr(0,16)) + ("n",new_bs->block_num)("t",new_bs->header.timestamp) + ("count",new_bs->block->transactions.size())("lib",chain.last_irreversible_block_num())("confs", new_bs->header.confirmed)); + } } } // namespace eosio From e2a0abf5b831ba913a3849ff95d52e4ffe4086ef Mon Sep 17 00:00:00 2001 From: deadlock Date: Mon, 13 May 2019 12:42:37 +0800 Subject: [PATCH 09/12] update tps plugin, now tps trx support symbol BOS and cal cpu/net bill --- plugins/txn_test_gen_plugin/CMakeLists.txt | 2 +- .../txn_test_gen_plugin.cpp | 570 ++++++++++-------- 2 files changed, 324 insertions(+), 248 deletions(-) diff --git a/plugins/txn_test_gen_plugin/CMakeLists.txt b/plugins/txn_test_gen_plugin/CMakeLists.txt index e765f3478e6..286066d6149 100644 --- a/plugins/txn_test_gen_plugin/CMakeLists.txt +++ b/plugins/txn_test_gen_plugin/CMakeLists.txt @@ -5,6 +5,6 @@ add_library( txn_test_gen_plugin add_dependencies(txn_test_gen_plugin eosio.token) -target_link_libraries( txn_test_gen_plugin appbase fc http_plugin chain_plugin ) +target_link_libraries( txn_test_gen_plugin appbase fc http_plugin chain_plugin net_plugin) target_include_directories( txn_test_gen_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) target_include_directories( txn_test_gen_plugin PUBLIC ${CMAKE_BINARY_DIR}/contracts ) diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 3a2c4fed5fb..06b6f437cdb 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -4,6 +4,7 @@ */ #include #include +#include #include #include @@ -24,9 +25,11 @@ #include #include +#include +#include namespace eosio { namespace detail { - struct txn_test_gen_empty {}; +struct txn_test_gen_empty {}; }} FC_REFLECT(eosio::detail::txn_test_gen_empty, ); @@ -82,341 +85,414 @@ using namespace eosio::chain; }\ } -#define INVOKE_ASYNC_R_R(api_handle, call_name, in_param0, in_param1) \ +#define INVOKE_ASYNC_R_R(api_handle, call_name, in_param0, in_param1, in_param2) \ const auto& vs = fc::json::json::from_string(body).as(); \ - api_handle->call_name(vs.at(0).as(), vs.at(1).as(), result_handler); + api_handle->call_name(vs.at(0).as(), vs.at(1).as(), vs.at(2).as(), result_handler); struct txn_test_gen_plugin_impl { - uint64_t _total_us = 0; - uint64_t _txcount = 0; + uint64_t _total_us = 0; + uint64_t _txcount = 0; - int _remain = 0; + int _remain = 0; - void push_next_transaction(const std::shared_ptr>& trxs, size_t index, const std::function& next ) { + std::string cached_salt; + uint64_t cached_period; + uint64_t cached_batch_size; + + void push_next_transaction(const std::shared_ptr>& trxs, size_t index, const std::function& next ) { chain_plugin& cp = app().get_plugin(); const int overlap = 20; int end = std::min(index + overlap, trxs->size()); _remain = end - index; for (int i = index; i < end; ++i) { - cp.accept_transaction( packed_transaction(trxs->at(i)), [=](const fc::static_variant& result){ + cp.accept_transaction( packed_transaction(trxs->at(i)), [=](const fc::static_variant& result){ if (result.contains()) { - next(result.get()); + next(result.get()); } else { - if (result.contains() && result.get()->receipt) { - _total_us += result.get()->receipt->cpu_usage_us; - ++_txcount; - } - --_remain; - if (_remain == 0 ) { - if (end < trxs->size()) { - push_next_transaction(trxs, index + overlap, next); - } else { - next(nullptr); - } - } + if (result.contains() && result.get()->receipt) { + _total_us += result.get()->receipt->cpu_usage_us; + ++_txcount; + } + --_remain; + if (_remain == 0 ) { + if (end < trxs->size()) { + push_next_transaction(trxs, index + overlap, next); + } else { + next(nullptr); + } + } } - }); + }); } - } + } - void push_transactions( std::vector&& trxs, const std::function& next ) { + void push_transactions( std::vector&& trxs, const std::function& next ) { auto trxs_copy = std::make_shared>(std::move(trxs)); push_next_transaction(trxs_copy, 0, next); - } + } - void create_test_accounts(const std::string& init_name, const std::string& init_priv_key, const std::function& next) { + void create_test_accounts(const std::string& init_name, const std::string& init_priv_key, + const std::string& core_symbol, + const std::function& next) { std::vector trxs; trxs.reserve(2); try { - name newaccountA("txn.test.a"); - name newaccountB("txn.test.b"); - name newaccountC("txn.test.t"); - name creator(init_name); - - abi_def currency_abi_def = fc::json::from_string(eosio_token_abi).as(); - - controller& cc = app().get_plugin().chain(); - auto chainid = app().get_plugin().get_chain_id(); - auto abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); - - abi_serializer eosio_token_serializer{fc::json::from_string(eosio_token_abi).as(), abi_serializer_max_time}; - - fc::crypto::private_key txn_test_receiver_A_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); - fc::crypto::private_key txn_test_receiver_B_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); - fc::crypto::private_key txn_test_receiver_C_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'c'))); - fc::crypto::public_key txn_text_receiver_A_pub_key = txn_test_receiver_A_priv_key.get_public_key(); - fc::crypto::public_key txn_text_receiver_B_pub_key = txn_test_receiver_B_priv_key.get_public_key(); - fc::crypto::public_key txn_text_receiver_C_pub_key = txn_test_receiver_C_priv_key.get_public_key(); - fc::crypto::private_key creator_priv_key = fc::crypto::private_key(init_priv_key); - - //create some test accounts - { - signed_transaction trx; - - //create "A" account - { - auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; - auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; - - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountA, owner_auth, active_auth}); - } - //create "B" account - { - auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; - auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; - - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountB, owner_auth, active_auth}); - } - //create "txn.test.t" account - { - auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; - auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; - - trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountC, owner_auth, active_auth}); - } - - trx.expiration = cc.head_block_time() + fc::seconds(30); - trx.set_reference_block(cc.head_block_id()); - trx.sign(creator_priv_key, chainid); - trxs.emplace_back(std::move(trx)); - } - - //set txn.test.t contract to eosio.token & initialize it - { - signed_transaction trx; - - vector wasm = wast_to_wasm(std::string(eosio_token_wast)); - - setcode handler; - handler.account = newaccountC; - handler.code.assign(wasm.begin(), wasm.end()); - - trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); - - { - setabi handler; - handler.account = newaccountC; - handler.abi = fc::raw::pack(json::from_string(eosio_token_abi).as()); - trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); - } - - { - action act; - act.account = N(txn.test.t); - act.name = N(create); - act.authorization = vector{{newaccountC,config::active_name}}; - act.data = eosio_token_serializer.variant_to_binary("create", fc::json::from_string("{\"issuer\":\"txn.test.t\",\"maximum_supply\":\"1000000000.0000 CUR\"}}"), abi_serializer_max_time); - trx.actions.push_back(act); - } - { - action act; - act.account = N(txn.test.t); - act.name = N(issue); - act.authorization = vector{{newaccountC,config::active_name}}; - act.data = eosio_token_serializer.variant_to_binary("issue", fc::json::from_string("{\"to\":\"txn.test.t\",\"quantity\":\"600.0000 CUR\",\"memo\":\"\"}"), abi_serializer_max_time); - trx.actions.push_back(act); - } - { - action act; - act.account = N(txn.test.t); - act.name = N(transfer); - act.authorization = vector{{newaccountC,config::active_name}}; - act.data = eosio_token_serializer.variant_to_binary("transfer", fc::json::from_string("{\"from\":\"txn.test.t\",\"to\":\"txn.test.a\",\"quantity\":\"200.0000 CUR\",\"memo\":\"\"}"), abi_serializer_max_time); - trx.actions.push_back(act); - } - { - action act; - act.account = N(txn.test.t); - act.name = N(transfer); - act.authorization = vector{{newaccountC,config::active_name}}; - act.data = eosio_token_serializer.variant_to_binary("transfer", fc::json::from_string("{\"from\":\"txn.test.t\",\"to\":\"txn.test.b\",\"quantity\":\"200.0000 CUR\",\"memo\":\"\"}"), abi_serializer_max_time); - trx.actions.push_back(act); - } - - trx.expiration = cc.head_block_time() + fc::seconds(30); - trx.set_reference_block(cc.head_block_id()); - trx.max_net_usage_words = 5000; - trx.sign(txn_test_receiver_C_priv_key, chainid); - trxs.emplace_back(std::move(trx)); - } + name newaccountA("aaaaaaaaaaaa"); + name newaccountB("bbbbbbbbbbbb"); + name newaccountC("cccccccccccc"); + name creator(init_name); + + abi_def currency_abi_def = fc::json::from_string(eosio_token_abi).as(); + + controller& cc = app().get_plugin().chain(); + auto chainid = app().get_plugin().get_chain_id(); + auto abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); + + abi_serializer eosio_token_serializer{fc::json::from_string(eosio_token_abi).as(), abi_serializer_max_time}; + + fc::crypto::private_key txn_test_receiver_A_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); + fc::crypto::private_key txn_test_receiver_B_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); + fc::crypto::private_key txn_test_receiver_C_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'c'))); + fc::crypto::public_key txn_text_receiver_A_pub_key = txn_test_receiver_A_priv_key.get_public_key(); + fc::crypto::public_key txn_text_receiver_B_pub_key = txn_test_receiver_B_priv_key.get_public_key(); + fc::crypto::public_key txn_text_receiver_C_pub_key = txn_test_receiver_C_priv_key.get_public_key(); + fc::crypto::private_key creator_priv_key = fc::crypto::private_key(init_priv_key); + + eosio::chain::asset net{1000000, symbol(4,core_symbol.c_str())}; + eosio::chain::asset cpu{10000000000, symbol(4,core_symbol.c_str())}; + eosio::chain::asset ram{1000000, symbol(4,core_symbol.c_str())}; + + //create some test accounts + { + signed_transaction trx; + + //create "A" account + { + auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; + auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}}; + + trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountA, owner_auth, active_auth}); + + //delegate cpu net and buyram + auto act_delegatebw = create_action_delegatebw(creator, newaccountA,net,cpu,abi_serializer_max_time); + auto act_buyram = create_action_buyram(creator, newaccountA, ram, abi_serializer_max_time); + + trx.actions.emplace_back(act_delegatebw); + trx.actions.emplace_back(act_buyram); + + } + //create "B" account + { + auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; + auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}}; + + trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountB, owner_auth, active_auth}); + + //delegate cpu net and buyram + auto act_delegatebw = create_action_delegatebw(creator, newaccountB,net,cpu,abi_serializer_max_time); + auto act_buyram = create_action_buyram(creator, newaccountB, ram, abi_serializer_max_time); + + trx.actions.emplace_back(act_delegatebw); + trx.actions.emplace_back(act_buyram); + } + //create "cccccccccccc" account + { + auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; + auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_C_pub_key, 1}}, {}}; + + trx.actions.emplace_back(vector{{creator,"active"}}, newaccount{creator, newaccountC, owner_auth, active_auth}); + + //delegate cpu net and buyram + auto act_delegatebw = create_action_delegatebw(creator, newaccountC,net,cpu,abi_serializer_max_time); + auto act_buyram = create_action_buyram(creator, newaccountC, ram, abi_serializer_max_time); + + trx.actions.emplace_back(act_delegatebw); + trx.actions.emplace_back(act_buyram); + } + + trx.expiration = cc.head_block_time() + fc::seconds(30); + trx.set_reference_block(cc.head_block_id()); + trx.sign(creator_priv_key, chainid); + trxs.emplace_back(std::move(trx)); + } + + //set cccccccccccc contract to eosio.token & initialize it + { + signed_transaction trx; + + vector wasm = wast_to_wasm(std::string(eosio_token_wast)); + + setcode handler; + handler.account = newaccountC; + handler.code.assign(wasm.begin(), wasm.end()); + + trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + + { + setabi handler; + handler.account = newaccountC; + handler.abi = fc::raw::pack(json::from_string(eosio_token_abi).as()); + trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); + } + + { + action act; + act.account = N(cccccccccccc); + act.name = N(create); + act.authorization = vector{{newaccountC,config::active_name}}; + act.data = eosio_token_serializer.variant_to_binary("create", fc::json::from_string("{\"issuer\":\"cccccccccccc\",\"maximum_supply\":\"1000000000.0000 CUR\"}}"), abi_serializer_max_time); + trx.actions.push_back(act); + } + { + action act; + act.account = N(cccccccccccc); + act.name = N(issue); + act.authorization = vector{{newaccountC,config::active_name}}; + act.data = eosio_token_serializer.variant_to_binary("issue", fc::json::from_string("{\"to\":\"cccccccccccc\",\"quantity\":\"1000000000.0000 CUR\",\"memo\":\"\"}"), abi_serializer_max_time); + trx.actions.push_back(act); + } + { + action act; + act.account = N(cccccccccccc); + act.name = N(transfer); + act.authorization = vector{{newaccountC,config::active_name}}; + act.data = eosio_token_serializer.variant_to_binary("transfer", fc::json::from_string("{\"from\":\"cccccccccccc\",\"to\":\"aaaaaaaaaaaa\",\"quantity\":\"500000000.0000 CUR\",\"memo\":\"\"}"), abi_serializer_max_time); + trx.actions.push_back(act); + } + { + action act; + act.account = N(cccccccccccc); + act.name = N(transfer); + act.authorization = vector{{newaccountC,config::active_name}}; + act.data = eosio_token_serializer.variant_to_binary("transfer", fc::json::from_string("{\"from\":\"cccccccccccc\",\"to\":\"bbbbbbbbbbbb\",\"quantity\":\"500000000.0000 CUR\",\"memo\":\"\"}"), abi_serializer_max_time); + trx.actions.push_back(act); + } + + trx.expiration = cc.head_block_time() + fc::seconds(30); + trx.set_reference_block(cc.head_block_id()); + trx.max_net_usage_words = 5000; + trx.sign(txn_test_receiver_C_priv_key, chainid); + trxs.emplace_back(std::move(trx)); + } } catch (const fc::exception& e) { - next(e.dynamic_copy_exception()); - return; + next(e.dynamic_copy_exception()); + return; } push_transactions(std::move(trxs), next); - } - - void start_generation(const std::string& salt, const uint64_t& period, const uint64_t& batch_size) { + } + + eosio::chain::action create_action_delegatebw(const name &from, const name &to, const asset &net, const asset &cpu, const fc::microseconds &abi_serializer_max_time){ + fc::variant variant_delegate = fc::mutable_variant_object() + ("from", from.to_string()) + ("receiver", to.to_string()) + ("stake_net_quantity", net.to_string()) + ("stake_cpu_quantity", cpu.to_string()) + ("transfer", true); + abi_serializer eosio_system_serializer{fc::json::from_string(eosio_system_abi).as(), abi_serializer_max_time}; + + auto payload_delegate = eosio_system_serializer.variant_to_binary( "delegatebw", variant_delegate, abi_serializer_max_time); + eosio::chain::action act_delegate{vector{{from,"active"}}, + config::system_account_name, N(delegatebw), payload_delegate}; + + return act_delegate; + } + + eosio::chain::action create_action_buyram(const name &from, const name &to, const asset &quant, const fc::microseconds &abi_serializer_max_time){ + fc::variant variant_buyram = fc::mutable_variant_object() + ("payer", from.to_string()) + ("receiver", to.to_string()) + ("quant", quant.to_string()); + abi_serializer eosio_system_serializer{fc::json::from_string(eosio_system_abi).as(), abi_serializer_max_time}; + + auto payload_buyram = eosio_system_serializer.variant_to_binary( "buyram", variant_buyram, abi_serializer_max_time); + eosio::chain::action act_buyram{vector{{from,"active"}}, + config::system_account_name, N(buyram), payload_buyram}; + + return act_buyram; + } + + void start_generation(const std::string& salt, const uint64_t& period, const uint64_t& batch_size) { if(running) - throw fc::exception(fc::invalid_operation_exception_code); + throw fc::exception(fc::invalid_operation_exception_code); if(period < 1 || period > 2500) - throw fc::exception(fc::invalid_operation_exception_code); + throw fc::exception(fc::invalid_operation_exception_code); if(batch_size < 1 || batch_size > 250) - throw fc::exception(fc::invalid_operation_exception_code); + throw fc::exception(fc::invalid_operation_exception_code); if(batch_size & 1) - throw fc::exception(fc::invalid_operation_exception_code); + throw fc::exception(fc::invalid_operation_exception_code); running = true; + cached_salt = salt; + cached_period = period; + cached_batch_size = batch_size; controller& cc = app().get_plugin().chain(); auto abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); abi_serializer eosio_token_serializer{fc::json::from_string(eosio_token_abi).as(), abi_serializer_max_time}; //create the actions here - act_a_to_b.account = N(txn.test.t); + act_a_to_b.account = N(cccccccccccc); act_a_to_b.name = N(transfer); - act_a_to_b.authorization = vector{{name("txn.test.a"),config::active_name}}; - act_a_to_b.data = eosio_token_serializer.variant_to_binary("transfer", - fc::json::from_string(fc::format_string("{\"from\":\"txn.test.a\",\"to\":\"txn.test.b\",\"quantity\":\"1.0000 CUR\",\"memo\":\"${l}\"}", - fc::mutable_variant_object()("l", salt))), - abi_serializer_max_time); + act_a_to_b.authorization = vector{{name("aaaaaaaaaaaa"),config::active_name}}; + act_a_to_b.data = eosio_token_serializer.variant_to_binary("transfer", + fc::json::from_string(fc::format_string("{\"from\":\"aaaaaaaaaaaa\",\"to\":\"bbbbbbbbbbbb\",\"quantity\":\"1.0000 CUR\",\"memo\":\"${l}\"}", + fc::mutable_variant_object()("l", salt))), + abi_serializer_max_time); - act_b_to_a.account = N(txn.test.t); + act_b_to_a.account = N(cccccccccccc); act_b_to_a.name = N(transfer); - act_b_to_a.authorization = vector{{name("txn.test.b"),config::active_name}}; - act_b_to_a.data = eosio_token_serializer.variant_to_binary("transfer", - fc::json::from_string(fc::format_string("{\"from\":\"txn.test.b\",\"to\":\"txn.test.a\",\"quantity\":\"1.0000 CUR\",\"memo\":\"${l}\"}", - fc::mutable_variant_object()("l", salt))), - abi_serializer_max_time); + act_b_to_a.authorization = vector{{name("bbbbbbbbbbbb"),config::active_name}}; + act_b_to_a.data = eosio_token_serializer.variant_to_binary("transfer", + fc::json::from_string(fc::format_string("{\"from\":\"bbbbbbbbbbbb\",\"to\":\"aaaaaaaaaaaa\",\"quantity\":\"1.0000 CUR\",\"memo\":\"${l}\"}", + fc::mutable_variant_object()("l", salt))), + abi_serializer_max_time); timer_timeout = period; batch = batch_size/2; ilog("Started transaction test plugin; performing ${p} transactions every ${m}ms", ("p", batch_size)("m", period)); + ilog("wait 3 seconds to spin up"); + arm_timer(boost::asio::high_resolution_timer::clock_type::now() + std::chrono::milliseconds(3000) ); + } - arm_timer(boost::asio::high_resolution_timer::clock_type::now()); - } - - void arm_timer(boost::asio::high_resolution_timer::time_point s) { + void arm_timer(boost::asio::high_resolution_timer::time_point s) { timer.expires_at(s + std::chrono::milliseconds(timer_timeout)); timer.async_wait([this](const boost::system::error_code& ec) { - if(!running || ec) + if(!running || ec) return; - send_transaction([this](const fc::exception_ptr& e){ - if (e) { - elog("pushing transaction failed: ${e}", ("e", e->to_detail_string())); - stop_generation(); - } else { - arm_timer(timer.expires_at()); - } - }); + send_transaction([this](const fc::exception_ptr& e){ + if (e) { + elog("pushing transaction failed: ${e}", ("e", e->to_detail_string())); + stop_generation(); + auto peers_conn = app().get_plugin().connections(); + for(const auto c : peers_conn){ + app().get_plugin().disconnect(c.peer); + } + for(const auto c : peers_conn){ + app().get_plugin().connect(c.peer); + } + start_generation(cached_salt,cached_period,cached_batch_size); + } else { + arm_timer(timer.expires_at()); + } + }); }); - } + } - void send_transaction(std::function next) { + void send_transaction(std::function next) { std::vector trxs; trxs.reserve(2*batch); try { - controller& cc = app().get_plugin().chain(); - auto chainid = app().get_plugin().get_chain_id(); - - static fc::crypto::private_key a_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); - static fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); - - static uint64_t nonce = static_cast(fc::time_point::now().sec_since_epoch()) << 32; - - uint32_t reference_block_num = cc.last_irreversible_block_num(); - if (txn_reference_block_lag >= 0) { - reference_block_num = cc.head_block_num(); - if (reference_block_num <= (uint32_t)txn_reference_block_lag) { - reference_block_num = 0; - } else { - reference_block_num -= (uint32_t)txn_reference_block_lag; - } - } - - block_id_type reference_block_id = cc.get_block_id_for_num(reference_block_num); - - for(unsigned int i = 0; i < batch; ++i) { - { - signed_transaction trx; - trx.actions.push_back(act_a_to_b); - trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); - trx.set_reference_block(reference_block_id); - trx.expiration = cc.head_block_time() + fc::seconds(30); - trx.max_net_usage_words = 100; - trx.sign(a_priv_key, chainid); - trxs.emplace_back(std::move(trx)); - } - - { - signed_transaction trx; - trx.actions.push_back(act_b_to_a); - trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); - trx.set_reference_block(reference_block_id); - trx.expiration = cc.head_block_time() + fc::seconds(30); - trx.max_net_usage_words = 100; - trx.sign(b_priv_key, chainid); - trxs.emplace_back(std::move(trx)); - } - } + controller& cc = app().get_plugin().chain(); + auto chainid = app().get_plugin().get_chain_id(); + + static fc::crypto::private_key a_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); + static fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); + + static uint64_t nonce = static_cast(fc::time_point::now().sec_since_epoch()) << 32; + + uint32_t reference_block_num = cc.last_irreversible_block_num(); + if (txn_reference_block_lag >= 0) { + reference_block_num = cc.head_block_num(); + if (reference_block_num <= (uint32_t)txn_reference_block_lag) { + reference_block_num = 0; + } else { + reference_block_num -= (uint32_t)txn_reference_block_lag; + } + } + + block_id_type reference_block_id = cc.get_block_id_for_num(reference_block_num); + + for(unsigned int i = 0; i < batch; ++i) { + { + signed_transaction trx; + trx.actions.push_back(act_a_to_b); + trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); + trx.set_reference_block(reference_block_id); + trx.expiration = cc.head_block_time() + fc::seconds(30); + trx.max_net_usage_words = 100; + trx.sign(a_priv_key, chainid); + trxs.emplace_back(std::move(trx)); + } + + { + signed_transaction trx; + trx.actions.push_back(act_b_to_a); + trx.context_free_actions.emplace_back(action({}, config::null_account_name, "nonce", fc::raw::pack(nonce++))); + trx.set_reference_block(reference_block_id); + trx.expiration = cc.head_block_time() + fc::seconds(30); + trx.max_net_usage_words = 100; + trx.sign(b_priv_key, chainid); + trxs.emplace_back(std::move(trx)); + } + } } catch ( const fc::exception& e ) { - next(e.dynamic_copy_exception()); + next(e.dynamic_copy_exception()); } push_transactions(std::move(trxs), next); - } + } - void stop_generation() { + void stop_generation() { if(!running) - throw fc::exception(fc::invalid_operation_exception_code); + throw fc::exception(fc::invalid_operation_exception_code); timer.cancel(); running = false; ilog("Stopping transaction generation test"); if (_txcount) { - ilog("${d} transactions executed, ${t}us / transaction", ("d", _txcount)("t", _total_us / (double)_txcount)); - _txcount = _total_us = 0; + ilog("${d} transactions executed, ${t}us / transaction", ("d", _txcount)("t", _total_us / (double)_txcount)); + _txcount = _total_us = 0; } - } + } - boost::asio::high_resolution_timer timer{app().get_io_service()}; - bool running{false}; + boost::asio::high_resolution_timer timer{app().get_io_service()}; + bool running{false}; - unsigned timer_timeout; - unsigned batch; + unsigned timer_timeout; + unsigned batch; - action act_a_to_b; - action act_b_to_a; + action act_a_to_b; + action act_b_to_a; - int32_t txn_reference_block_lag; + int32_t txn_reference_block_lag; }; txn_test_gen_plugin::txn_test_gen_plugin() {} txn_test_gen_plugin::~txn_test_gen_plugin() {} void txn_test_gen_plugin::set_program_options(options_description&, options_description& cfg) { - cfg.add_options() - ("txn-reference-block-lag", bpo::value()->default_value(0), "Lag in number of blocks from the head block when selecting the reference block for transactions (-1 means Last Irreversible Block)") - ; + cfg.add_options() + ("txn-reference-block-lag", bpo::value()->default_value(0), "Lag in number of blocks from the head block when selecting the reference block for transactions (-1 means Last Irreversible Block)") + ; } void txn_test_gen_plugin::plugin_initialize(const variables_map& options) { - try { - my.reset( new txn_test_gen_plugin_impl ); - my->txn_reference_block_lag = options.at( "txn-reference-block-lag" ).as(); - } FC_LOG_AND_RETHROW() + try { + my.reset( new txn_test_gen_plugin_impl ); + my->txn_reference_block_lag = options.at( "txn-reference-block-lag" ).as(); + } FC_LOG_AND_RETHROW() } void txn_test_gen_plugin::plugin_startup() { - app().get_plugin().add_api({ - CALL_ASYNC(txn_test_gen, my, create_test_accounts, INVOKE_ASYNC_R_R(my, create_test_accounts, std::string, std::string), 200), - CALL(txn_test_gen, my, stop_generation, INVOKE_V_V(my, stop_generation), 200), - CALL(txn_test_gen, my, start_generation, INVOKE_V_R_R_R(my, start_generation, std::string, uint64_t, uint64_t), 200) - }); + app().get_plugin().add_api({ + CALL_ASYNC(txn_test_gen, my, create_test_accounts, INVOKE_ASYNC_R_R(my, create_test_accounts, std::string, std::string, std::string), 200), + CALL(txn_test_gen, my, stop_generation, INVOKE_V_V(my, stop_generation), 200), + CALL(txn_test_gen, my, start_generation, INVOKE_V_R_R_R(my, start_generation, std::string, uint64_t, uint64_t), 200) + }); } void txn_test_gen_plugin::plugin_shutdown() { - try { - my->stop_generation(); - } - catch(fc::exception e) { - } + try { + my->stop_generation(); + } + catch(fc::exception e) { + } } } From eb964cb886f319e5cbb1930799fdab33289e89c0 Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 13 May 2019 13:31:08 +0800 Subject: [PATCH 10/12] fix a potential crash during commit cert generation. --- libraries/chain/include/eosio/chain/pbft.hpp | 20 +++++----- libraries/chain/pbft.cpp | 40 ++++++++++---------- libraries/chain/pbft_database.cpp | 4 +- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/libraries/chain/include/eosio/chain/pbft.hpp b/libraries/chain/include/eosio/chain/pbft.hpp index ca8130a2381..dd275943451 100644 --- a/libraries/chain/include/eosio/chain/pbft.hpp +++ b/libraries/chain/include/eosio/chain/pbft.hpp @@ -56,15 +56,15 @@ namespace eosio { const vector &get_prepares_cache() const; - void set_prepares_cache(const vector &prepares_cache); + void set_prepares_cache(const vector &pcache); const vector &get_commits_cache() const; - void set_commits_cache(const vector &commits_cache); + void set_commits_cache(const vector &ccache); const vector &get_view_changes_cache() const; - void set_view_changes_cache(const vector &view_changes_cache); + void set_view_changes_cache(const vector &vc_cache); const uint32_t &get_current_view() const; @@ -72,29 +72,29 @@ namespace eosio { const vector &get_prepared_certificate() const; - void set_prepared_certificate(const vector &prepared_certificate); + void set_prepared_certificate(const vector &pcert); const vector> &get_committed_certificate() const; - void set_committed_certificate(const vector> &pbft_committed_certificate_vector); + void set_committed_certificate(const vector> &ccert); const vector &get_view_changed_certificate() const; - void set_view_changed_certificate(const vector &view_changed_certificate); + void set_view_changed_certificate(const vector &vc_cert); const uint32_t &get_target_view_retries() const; - void set_target_view_retries(const uint32_t &target_view_reties); + void set_target_view_retries(const uint32_t &tv_reties); const uint32_t &get_target_view() const; - void set_target_view(const uint32_t &target_view); + void set_target_view(const uint32_t &tv); const uint32_t &get_view_change_timer() const; - void set_view_change_timer(const uint32_t &view_change_timer); + void set_view_change_timer(const uint32_t &vc_timer); - void manually_set_current_view(const uint32_t ¤t_view); + void manually_set_current_view(const uint32_t &cv); protected: psm_cache cache; diff --git a/libraries/chain/pbft.cpp b/libraries/chain/pbft.cpp index 3d8b0ac2ff5..2236de50f5a 100644 --- a/libraries/chain/pbft.cpp +++ b/libraries/chain/pbft.cpp @@ -142,8 +142,8 @@ namespace eosio { current->on_new_view(this, e, pbft_db); } - void psm_machine::manually_set_current_view(const uint32_t ¤t_view) { - current->manually_set_view(this, current_view); + void psm_machine::manually_set_current_view(const uint32_t &cv) { + current->manually_set_view(this, cv); } /** @@ -575,24 +575,24 @@ namespace eosio { return this->cache.prepares_cache; } - void psm_machine::set_prepares_cache(const vector &prepares_cache) { - this->cache.prepares_cache = prepares_cache; + void psm_machine::set_prepares_cache(const vector &pcache) { + this->cache.prepares_cache = pcache; } const vector &psm_machine::get_commits_cache() const { return this->cache.commits_cache; } - void psm_machine::set_commits_cache(const vector &commits_cache) { - this->cache.commits_cache = commits_cache; + void psm_machine::set_commits_cache(const vector &ccache) { + this->cache.commits_cache = ccache; } const vector &psm_machine::get_view_changes_cache() const { return this->cache.view_changes_cache; } - void psm_machine::set_view_changes_cache(const vector &view_changes_cache) { - this->cache.view_changes_cache = view_changes_cache; + void psm_machine::set_view_changes_cache(const vector &vc_cache) { + this->cache.view_changes_cache = vc_cache; } const uint32_t &psm_machine::get_current_view() const { @@ -607,16 +607,16 @@ namespace eosio { return this->cache.prepared_certificate; } - void psm_machine::set_prepared_certificate(const vector &prepared_certificate) { - this->cache.prepared_certificate = prepared_certificate; + void psm_machine::set_prepared_certificate(const vector &pcert) { + this->cache.prepared_certificate = pcert; } const vector> &psm_machine::get_committed_certificate() const { return this->cache.committed_certificate; } - void psm_machine::set_committed_certificate(const vector> &pbft_committed_certificate_vector) { - this->cache.committed_certificate = pbft_committed_certificate_vector; + void psm_machine::set_committed_certificate(const vector> &ccert) { + this->cache.committed_certificate = ccert; } const vector &psm_machine::get_view_changed_certificate() const { @@ -624,32 +624,32 @@ namespace eosio { } void psm_machine::set_view_changed_certificate( - const vector &view_changed_certificate) { - this->cache.view_changed_certificate = view_changed_certificate; + const vector &vc_cert) { + this->cache.view_changed_certificate = vc_cert; } const uint32_t &psm_machine::get_target_view_retries() const { return this->target_view_retries; } - void psm_machine::set_target_view_retries(const uint32_t &target_view_reties) { - this->target_view_retries = target_view_reties; + void psm_machine::set_target_view_retries(const uint32_t &tv_reties) { + this->target_view_retries = tv_reties; } const uint32_t &psm_machine::get_target_view() const { return this->target_view; } - void psm_machine::set_target_view(const uint32_t &target_view) { - this->target_view = target_view; + void psm_machine::set_target_view(const uint32_t &tv) { + this->target_view = tv; } const uint32_t &psm_machine::get_view_change_timer() const { return this->view_change_timer; } - void psm_machine::set_view_change_timer(const uint32_t &view_change_timer) { - this->view_change_timer = view_change_timer; + void psm_machine::set_view_change_timer(const uint32_t &vc_timer) { + this->view_change_timer = vc_timer; } } } \ No newline at end of file diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 3d7c736285e..5b039bf337d 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -667,9 +667,11 @@ namespace eosio { pcc.resize(ctrl.my_signature_providers().size()); const auto &by_commit_and_num_index = pbft_state_index.get(); auto itr = by_commit_and_num_index.begin(); + if (itr == by_commit_and_num_index.end()) return vector>{}; pbft_state_ptr psp = *itr; - if (itr == by_commit_and_num_index.end() || !psp->should_committed) return vector>{}; + + if (!psp->should_committed) return vector>{}; auto highest_committed_block_num = psp->block_num; From 2c2ddd763d0693036777721ec3f509b29bb8e074 Mon Sep 17 00:00:00 2001 From: oldcold Date: Mon, 13 May 2019 13:59:04 +0800 Subject: [PATCH 11/12] fix typo. --- libraries/chain/pbft_database.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/pbft_database.cpp b/libraries/chain/pbft_database.cpp index 5b039bf337d..5440aec0db2 100644 --- a/libraries/chain/pbft_database.cpp +++ b/libraries/chain/pbft_database.cpp @@ -1202,7 +1202,7 @@ namespace eosio { } if (!pending_checkpoint_block_num.empty()) { - std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.begin()); + std::sort(pending_checkpoint_block_num.begin(), pending_checkpoint_block_num.end()); for (auto h: pending_checkpoint_block_num) { for (auto const &my_sp : ctrl.my_signature_providers()) { auto uuid = boost::uuids::to_string(uuid_generator()); From 3edf7443a07a3efbc14cb177a9dfdcc3303b3fa8 Mon Sep 17 00:00:00 2001 From: deadlock Date: Mon, 13 May 2019 16:37:49 +0800 Subject: [PATCH 12/12] update readme in txn generator plugin --- plugins/txn_test_gen_plugin/README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/plugins/txn_test_gen_plugin/README.md b/plugins/txn_test_gen_plugin/README.md index 8d74e6a0412..313fdf83e5d 100644 --- a/plugins/txn_test_gen_plugin/README.md +++ b/plugins/txn_test_gen_plugin/README.md @@ -68,8 +68,28 @@ $ ./cleos set contract eosio ~/eos/build.release/contracts/eosio.bios/ ### Initialize the accounts txn_test_gen_plugin uses ```bash -$ curl --data-binary '["eosio", "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]' http://127.0.0.1:8888/v1/txn_test_gen/create_test_accounts +$ curl --data-binary '[, , ]' http://127.0.0.1:8888/v1/txn_test_gen/create_test_accounts + +example: +$ curl --data-binary '["eosio", "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3", "EOS"]' http://127.0.0.1:8888/v1/txn_test_gen/create_test_accounts ``` +> **make sure there are more than 4000,0000 ** in creator + + +This api does: +1. creates following accounts: +aaaaaaaaaaaa +bbbbbbbbbbbb +cccccccccccc + +1. delegate 1000,0000 cpu, 100 net, and 100 ram to above accounts using +1. deploy a token contract to account cccccccccccc and issue a large number of tokens to cccccccccccc, then transfer some tokens to aaaaaaaaaaaa and bbbbbbbbbbbb +1. subsequent trx will be generated using deployed token contract + 1. aaaaaaaaaaaa transfer to bbbbbbbbbbbb + 1. bbbbbbbbbbbb transfer to aaaaaaaaaaaa + + + ### Start transaction generation, this will submit 20 transactions evey 20ms (total of 1000TPS) ```bash