Skip to content

Commit

Permalink
Merge pull request #1134 from AntelopeIO/read_only_trx_config_fix_main
Browse files Browse the repository at this point in the history
[4.0 -> main] Check read-only trx options only when read-only-thread enabled, and present better error message
  • Loading branch information
linh2931 authored May 4, 2023
2 parents a361138 + 4fc70c3 commit 31ae4cb
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
39 changes: 22 additions & 17 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,8 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
}
}
}
EOS_ASSERT( test_mode_ || my->_ro_thread_pool_size == 0 || my->_producers.empty(), plugin_config_exception, "--read-only-threads not allowed on producer node" );
EOS_ASSERT( test_mode_ || my->_ro_thread_pool_size == 0 || my->_producers.empty(), plugin_config_exception, "read-only-threads not allowed on producer node" );

// only initialize other read-only options when read-only thread pool is enabled
if ( my->_ro_thread_pool_size > 0 ) {
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
Expand Down Expand Up @@ -1075,30 +1076,34 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
num_threads_supported -= 2;
auto actual_threads_allowed = std::min(my->_ro_max_threads_allowed, num_threads_supported);
ilog("vm total in kb: ${total}, vm used in kb: ${used}, number of EOS VM OC threads supported ((vm total - vm used)/4.2 TB - 2): ${supp}, max allowed: ${max}, actual allowed: ${actual}", ("total", vm_total_kb) ("used", vm_used_kb) ("supp", num_threads_supported) ("max", my->_ro_max_threads_allowed)("actual", actual_threads_allowed));
EOS_ASSERT( my->_ro_thread_pool_size <= actual_threads_allowed, plugin_config_exception, "--read-only-threads (${th}) greater than number of threads allowed for EOS VM OC (${allowed})", ("th", my->_ro_thread_pool_size) ("allowed", actual_threads_allowed) );
EOS_ASSERT( my->_ro_thread_pool_size <= actual_threads_allowed, plugin_config_exception, "read-only-threads (${th}) greater than number of threads allowed for EOS VM OC (${allowed})", ("th", my->_ro_thread_pool_size) ("allowed", actual_threads_allowed) );
}
#endif
EOS_ASSERT( my->_ro_thread_pool_size <= my->_ro_max_threads_allowed, plugin_config_exception, "--read-only-threads (${th}) greater than number of threads allowed (${allowed})", ("th", my->_ro_thread_pool_size) ("allowed", my->_ro_max_threads_allowed) );
}
EOS_ASSERT( my->_ro_thread_pool_size <= my->_ro_max_threads_allowed, plugin_config_exception, "read-only-threads (${th}) greater than the number of threads allowed (${allowed})", ("th", my->_ro_thread_pool_size) ("allowed", my->_ro_max_threads_allowed) );

my->_ro_write_window_time_us = fc::microseconds( options.at( "read-only-write-window-time-us" ).as<uint32_t>() );
my->_ro_read_window_time_us = fc::microseconds( options.at( "read-only-read-window-time-us" ).as<uint32_t>() );
EOS_ASSERT( my->_ro_read_window_time_us > my->_ro_read_window_minimum_time_us, plugin_config_exception, "read-only-read-window-time-us (${read}) must be at least greater than ${min} us", ("read", my->_ro_read_window_time_us) ("min", my->_ro_read_window_minimum_time_us) );
my->_ro_read_window_effective_time_us = my->_ro_read_window_time_us - my->_ro_read_window_minimum_time_us;

my->_ro_write_window_time_us = fc::microseconds( options.at( "read-only-write-window-time-us" ).as<uint32_t>() );
my->_ro_read_window_time_us = fc::microseconds( options.at( "read-only-read-window-time-us" ).as<uint32_t>() );
EOS_ASSERT( my->_ro_read_window_time_us > my->_ro_read_window_minimum_time_us, plugin_config_exception, "minimum of --read-only-read-window-time-us (${read}) must be ${min} microseconds", ("read", my->_ro_read_window_time_us) ("min", my->_ro_read_window_minimum_time_us) );
my->_ro_read_window_effective_time_us = my->_ro_read_window_time_us - my->_ro_read_window_minimum_time_us;
// Make sure a read-only transaction can finish within the read
// window if scheduled at the very beginning of the window.
// Add _ro_read_window_minimum_time_us for safety margin.
if ( my->_max_transaction_time_ms.load() > 0 ) {
EOS_ASSERT( my->_ro_read_window_time_us > ( fc::milliseconds(my->_max_transaction_time_ms.load()) + my->_ro_read_window_minimum_time_us ), plugin_config_exception, "read-only-read-window-time-us (${read} us) must be greater than max-transaction-time (${trx_time} us) plus ${min} us, required: ${read} us > (${trx_time} us + ${min} us).", ("read", my->_ro_read_window_time_us) ("trx_time", my->_max_transaction_time_ms.load() * 1000) ("min", my->_ro_read_window_minimum_time_us) );
}
ilog("read-only-write-window-time-us: ${ww} us, read-only-read-window-time-us: ${rw} us, effective read window time to be used: ${w} us",
("ww", my->_ro_write_window_time_us)("rw", my->_ro_read_window_time_us)("w", my->_ro_read_window_effective_time_us));
}

// Make sure a read-only transaction can finish within the read
// window if scheduled at the very beginning of the window.
// Use _ro_read_window_effective_time_us instead of _ro_read_window_time_us
// for safety margin
// Make sure _ro_max_trx_time_us is alwasys set.
if ( my->_max_transaction_time_ms.load() > 0 ) {
EOS_ASSERT( my->_ro_read_window_effective_time_us > fc::milliseconds(my->_max_transaction_time_ms.load()), plugin_config_exception, "--read-only-read-window-time-us (${read}) must be greater than --max-transaction-time ${trx_time} ms plus a margin of ${min} us", ("read", my->_ro_read_window_time_us) ("trx_time", my->_max_transaction_time_ms.load()) ("min", my->_ro_read_window_minimum_time_us) );
my->_ro_max_trx_time_us = fc::milliseconds(my->_max_transaction_time_ms.load());
} else {
// _max_transaction_time_ms can be set to negative in testing (for unlimited)
my->_ro_max_trx_time_us = my->_ro_read_window_effective_time_us;
// max-transaction-time can be set to negative for unlimited time
my->_ro_max_trx_time_us = fc::microseconds::maximum();
}
ilog("ro_thread_pool_size ${s}, ro_write_window_time_us ${ww}, ro_read_window_time_us ${rw}, ro_max_trx_time_us ${t}, ro_read_window_effective_time_us ${w}",
("s", my->_ro_thread_pool_size)("ww", my->_ro_write_window_time_us)("rw", my->_ro_read_window_time_us)("t", my->_ro_max_trx_time_us)("w", my->_ro_read_window_effective_time_us));
ilog("read-only-threads ${s}, max read-only trx time to be enforced: ${t} us}", ("s", my->_ro_thread_pool_size)("t", my->_ro_max_trx_time_us));

my->_incoming_block_sync_provider = app().get_method<incoming::methods::block_sync>().register_provider(
[this](const signed_block_ptr& block, const std::optional<block_id_type>& block_id, const block_state_ptr& bsp) {
Expand Down
21 changes: 17 additions & 4 deletions plugins/producer_plugin/test/test_read_only_trx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ auto make_unique_trx( const chain_id_type& chain_id ) {

BOOST_AUTO_TEST_SUITE(read_only_trxs)

void error_handling_common(std::vector<const char*>& specific_args) {
enum class app_init_status { failed, succeeded };

void test_configs_common(std::vector<const char*>& specific_args, app_init_status expected_status) {
appbase::scoped_app app;
fc::temp_directory temp;
auto temp_dir_str = temp.path().string();
Expand All @@ -58,19 +60,30 @@ void error_handling_common(std::vector<const char*>& specific_args) {
std::vector<const char*> argv =
{"test", "--data-dir", temp_dir_str.c_str(), "--config-dir", temp_dir_str.c_str()};
argv.insert( argv.end(), specific_args.begin(), specific_args.end() );
BOOST_CHECK_EQUAL( app->initialize<producer_plugin>( argv.size(), (char**) &argv[0]), false );

// app->initialize() returns a boolean. BOOST_CHECK_EQUAL cannot compare
// a boolean with a app_init_status directly
bool rc = (expected_status == app_init_status::succeeded) ? true : false;
BOOST_CHECK_EQUAL( app->initialize<producer_plugin>( argv.size(), (char**) &argv[0]), rc );
}

// --read-only-thread not allowed on producer node
BOOST_AUTO_TEST_CASE(read_only_on_producer) {
std::vector<const char*> specific_args = {"-p", "eosio", "-e", "--read-only-threads", "2" };
error_handling_common(specific_args);
test_configs_common(specific_args, app_init_status::failed);
}

// read_window_time must be greater than max_transaction_time + 10ms
BOOST_AUTO_TEST_CASE(invalid_read_window_time) {
std::vector<const char*> specific_args = { "--read-only-threads", "2", "--max-transaction-time", "10", "--read-only-write-window-time-us", "50000", "--read-only-read-window-time-us", "20000" }; // 20000 not greater than --max-transaction-time (10ms) + 10000us (minimum margin)
error_handling_common(specific_args);
test_configs_common(specific_args, app_init_status::failed);
}

// if --read-only-threads is not configured, read-only trx related configs should
// not be checked
BOOST_AUTO_TEST_CASE(not_check_configs_if_no_read_only_threads) {
std::vector<const char*> specific_args = { "--max-transaction-time", "10", "--read-only-write-window-time-us", "50000", "--read-only-read-window-time-us", "20000" }; // 20000 not greater than --max-transaction-time (10ms) + 10000us (minimum margin)
test_configs_common(specific_args, app_init_status::succeeded);
}

void test_trxs_common(std::vector<const char*>& specific_args) {
Expand Down

0 comments on commit 31ae4cb

Please sign in to comment.