From 4057c4bd9a737fa31e6f750729dd12b194caae84 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 15 Sep 2023 12:10:06 -0500 Subject: [PATCH 1/5] GH-1614 Remove subjective max_nonprivileged_inline_action_size limit --- libraries/chain/apply_context.cpp | 13 ------------- libraries/chain/controller.cpp | 8 +------- libraries/chain/include/eosio/chain/config.hpp | 1 - libraries/chain/include/eosio/chain/controller.hpp | 2 -- libraries/chain/include/eosio/chain/exceptions.hpp | 3 +-- libraries/testing/include/eosio/testing/tester.hpp | 9 +++------ libraries/testing/tester.cpp | 4 ++-- plugins/chain_plugin/chain_plugin.cpp | 4 ---- 8 files changed, 7 insertions(+), 37 deletions(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index d4a067feb5..2c8c3e85e1 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -357,12 +357,6 @@ void apply_context::execute_inline( action&& a ) { control.check_actor_list( actors ); } - if( !privileged && control.is_speculative_block() ) { - const auto& chain_config = control.get_global_properties().configuration; - EOS_ASSERT( a.data.size() < std::min(chain_config.max_inline_action_size, control.get_max_nonprivileged_inline_action_size()), - inline_action_too_big_nonprivileged, - "inline action too big for nonprivileged account ${account}", ("account", a.account)); - } // No need to check authorization if replaying irreversible blocks or contract is privileged if( !control.skip_auth_check() && !privileged && !trx_context.is_read_only() ) { try { @@ -417,13 +411,6 @@ void apply_context::execute_context_free_inline( action&& a ) { EOS_ASSERT( a.authorization.size() == 0, action_validate_exception, "context-free actions cannot have authorizations" ); - if( !privileged && control.is_speculative_block() ) { - const auto& chain_config = control.get_global_properties().configuration; - EOS_ASSERT( a.data.size() < std::min(chain_config.max_inline_action_size, control.get_max_nonprivileged_inline_action_size()), - inline_action_too_big_nonprivileged, - "inline action too big for nonprivileged account ${account}", ("account", a.account)); - } - auto inline_receiver = a.account; _cfa_inline_actions.emplace_back( schedule_action( std::move(a), inline_receiver, true ) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 04e6bb8f01..045f4a8691 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1258,8 +1258,7 @@ struct controller_impl { || (code == contract_blacklist_exception::code_value) || (code == action_blacklist_exception::code_value) || (code == key_blacklist_exception::code_value) - || (code == sig_variable_size_limit_exception::code_value) - || (code == inline_action_too_big_nonprivileged::code_value); + || (code == sig_variable_size_limit_exception::code_value); } bool scheduled_failure_is_subjective( const fc::exception& e ) const { @@ -2747,11 +2746,6 @@ subjective_billing& controller::get_mutable_subjective_billing() { } -uint32_t controller::get_max_nonprivileged_inline_action_size()const -{ - return my->conf.max_nonprivileged_inline_action_size; -} - controller::controller( const controller::config& cfg, const chain_id_type& chain_id ) :my( new controller_impl( cfg, *this, protocol_feature_set{}, chain_id ) ) { diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index a1cf326c89..6d81272944 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -79,7 +79,6 @@ const static uint32_t default_sig_cpu_bill_pct = 50 * perc const static uint32_t default_block_cpu_effort_pct = 90 * percent_1; // percentage of block time used for producing block const static uint16_t default_controller_thread_pool_size = 2; const static uint32_t default_max_variable_signature_length = 16384u; -const static uint32_t default_max_nonprivileged_inline_action_size = 4 * 1024; // 4 KB const static uint32_t default_max_action_return_value_size = 256; const static uint32_t default_max_transaction_finality_status_success_duration_sec = 180; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 965f96628a..e25a201050 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -74,7 +74,6 @@ namespace eosio { namespace chain { uint64_t state_guard_size = chain::config::default_state_guard_size; uint32_t sig_cpu_bill_pct = chain::config::default_sig_cpu_bill_pct; uint16_t thread_pool_size = chain::config::default_controller_thread_pool_size; - uint32_t max_nonprivileged_inline_action_size = chain::config::default_max_nonprivileged_inline_action_size; bool read_only = false; bool force_all_checks = false; bool disable_replay_opts = false; @@ -198,7 +197,6 @@ namespace eosio { namespace chain { const protocol_feature_manager& get_protocol_feature_manager()const; const subjective_billing& get_subjective_billing()const; subjective_billing& get_mutable_subjective_billing(); - uint32_t get_max_nonprivileged_inline_action_size()const; const flat_set& get_actor_whitelist() const; const flat_set& get_actor_blacklist() const; diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 151021a284..50c322ff00 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -323,8 +323,7 @@ namespace eosio { namespace chain { 3050010, "Action attempts to increase RAM usage of account without authorization" ) FC_DECLARE_DERIVED_EXCEPTION( restricted_error_code_exception, action_validate_exception, 3050011, "eosio_assert_code assertion failure uses restricted error code value" ) - FC_DECLARE_DERIVED_EXCEPTION( inline_action_too_big_nonprivileged, action_validate_exception, - 3050012, "Inline action exceeds maximum size limit for a non-privileged account" ) + // Removed 3050012 - inline_action_too_big_nonprivileged, no longer needed FC_DECLARE_DERIVED_EXCEPTION( action_return_value_exception, action_validate_exception, 3050014, "action return value size too big" ) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 0037bc3127..5b0eb752d8 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -156,7 +156,7 @@ namespace eosio { namespace testing { virtual ~base_tester() {}; - void init(const setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}, std::optional config_max_nonprivileged_inline_action_size = std::optional{}); + void init(const setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}); void init(controller::config config, const snapshot_reader_ptr& snapshot); void init(controller::config config, const genesis_state& genesis); void init(controller::config config); @@ -395,7 +395,7 @@ namespace eosio { namespace testing { return genesis; } - static std::pair default_config(const fc::temp_directory& tempdir, std::optional genesis_max_inline_action_size = std::optional{}, std::optional config_max_nonprivileged_inline_action_size = std::optional{}) { + static std::pair default_config(const fc::temp_directory& tempdir, std::optional genesis_max_inline_action_size = std::optional{}) { controller::config cfg; cfg.blocks_dir = tempdir.path() / config::default_blocks_dir_name; cfg.state_dir = tempdir.path() / config::default_state_dir_name; @@ -419,9 +419,6 @@ namespace eosio { namespace testing { if (genesis_max_inline_action_size) { gen.initial_configuration.max_inline_action_size = *genesis_max_inline_action_size; } - if (config_max_nonprivileged_inline_action_size) { - cfg.max_nonprivileged_inline_action_size = *config_max_nonprivileged_inline_action_size; - } return {cfg, gen}; } @@ -453,7 +450,7 @@ namespace eosio { namespace testing { class tester : public base_tester { public: tester(setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}, std::optional config_max_nonprivileged_inline_action_size = std::optional{}) { - init(policy, read_mode, genesis_max_inline_action_size, config_max_nonprivileged_inline_action_size); + init(policy, read_mode, genesis_max_inline_action_size); } tester(controller::config config, const genesis_state& genesis) { diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 6bcc9d1b8d..bdd0d71f67 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -179,8 +179,8 @@ namespace eosio { namespace testing { return control->head_block_id() == other.control->head_block_id(); } - void base_tester::init(const setup_policy policy, db_read_mode read_mode, std::optional genesis_max_inline_action_size, std::optional config_max_nonprivileged_inline_action_size) { - auto def_conf = default_config(tempdir, genesis_max_inline_action_size, config_max_nonprivileged_inline_action_size); + void base_tester::init(const setup_policy policy, db_read_mode read_mode, std::optional genesis_max_inline_action_size) { + auto def_conf = default_config(tempdir, genesis_max_inline_action_size); def_conf.first.read_mode = read_mode; cfg = def_conf.first; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 7ac5d5400a..e4beb113da 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -368,7 +368,6 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip "'none' - EOS VM OC tier-up is completely disabled.\n") #endif ("enable-account-queries", bpo::value()->default_value(false), "enable queries to find accounts by various metadata.") - ("max-nonprivileged-inline-action-size", bpo::value()->default_value(config::default_max_nonprivileged_inline_action_size), "maximum allowed size (in bytes) of an inline action for a nonprivileged account") ("transaction-retry-max-storage-size-gb", bpo::value(), "Maximum size (in GiB) allowed to be allocated for the Transaction Retry feature. Setting above 0 enables this feature.") ("transaction-retry-interval-sec", bpo::value()->default_value(20), @@ -633,9 +632,6 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { if( options.count( "chain-state-db-guard-size-mb" )) chain_config->state_guard_size = options.at( "chain-state-db-guard-size-mb" ).as() * 1024 * 1024; - if( options.count( "max-nonprivileged-inline-action-size" )) - chain_config->max_nonprivileged_inline_action_size = options.at( "max-nonprivileged-inline-action-size" ).as(); - if( options.count( "transaction-finality-status-max-storage-size-gb" )) { const uint64_t max_storage_size = options.at( "transaction-finality-status-max-storage-size-gb" ).as() * 1024 * 1024 * 1024; if (max_storage_size > 0) { From 509c11f3bed0ae4bb0dae9941c24da8ddc695954 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 15 Sep 2023 12:13:28 -0500 Subject: [PATCH 2/5] GH-1614 Fix tests for removal of subjective max_nonprivileged_inline_action_size limit and add new test for 512k limit --- unittests/api_tests.cpp | 46 +++---------- .../test-contracts/test_api/test_action.cpp | 6 ++ .../test-contracts/test_api/test_api.cpp | 3 + .../test-contracts/test_api/test_api.hpp | 3 + .../test-contracts/test_api/test_api.wasm | Bin 83960 -> 84666 bytes .../test_api/test_transaction.cpp | 61 +++++++++++++++--- 6 files changed, 73 insertions(+), 46 deletions(-) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 3d3d773c0f..5cac8246e6 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -1435,10 +1435,16 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, validating_tester) { try { // test send_action_empty CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_empty", {}); - // test send_action_large - BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), inline_action_too_big_nonprivileged, + // test send_action_large (512k) + CALL_TEST_FUNCTION( *this, "test_transaction", "send_action_512k", {}); + + // test send_many_actions_512k (512k) + CALL_TEST_FUNCTION( *this, "test_transaction", "send_many_actions_512k", {}); + + // test send_action_large (512k + 1) + BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), inline_action_too_big, [](const fc::exception& e) { - return expect_assert_message(e, "inline action too big for nonprivileged account"); + return expect_assert_message(e, "inline action too big"); } ); @@ -1611,38 +1617,6 @@ BOOST_AUTO_TEST_CASE(inline_action_objective_limit) { try { } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit_failure) { try { - const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k}); - chain.produce_blocks(2); - chain.create_accounts( {"testapi"_n, "testapi2"_n, "alice"_n} ); - chain.set_code( "testapi"_n, test_contracts::test_api_wasm() ); - chain.set_code( "testapi2"_n, test_contracts::test_api_wasm() ); - chain.produce_block(); - - transaction_trace_ptr trace; - auto c = chain.control->applied_transaction.connect([&](std::tuple x) { - auto& t = std::get<0>(x); - if (t->scheduled) { trace = t; } - } ); - CALL_TEST_FUNCTION(chain, "test_transaction", "send_deferred_transaction_4k_action", {} ); - BOOST_CHECK(!trace); - BOOST_CHECK_EXCEPTION(chain.produce_block( fc::seconds(2) ), fc::exception, - [](const fc::exception& e) { - return expect_assert_message(e, "inline action too big for nonprivileged account"); - } - ); - - //check that it populates exception fields - BOOST_REQUIRE(trace); - BOOST_REQUIRE(trace->except); - BOOST_REQUIRE(trace->error_code); - - BOOST_REQUIRE_EQUAL(1, trace->action_traces.size()); - c.disconnect(); - -} FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit) { try { const uint32_t _4k = 4 * 1024; tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k + 1}); @@ -1674,7 +1648,7 @@ BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit) { try { //confirm printed message BOOST_TEST(!trace->action_traces.empty()); - BOOST_TEST(trace->action_traces.back().console == "exec 8"); + BOOST_TEST(trace->action_traces.back().console == "action size: 4096"); c.disconnect(); for (int n=0; n < 10; ++n) { diff --git a/unittests/test-contracts/test_api/test_action.cpp b/unittests/test-contracts/test_api/test_action.cpp index c390fb9198..98fc38fd1a 100644 --- a/unittests/test-contracts/test_api/test_action.cpp +++ b/unittests/test-contracts/test_api/test_action.cpp @@ -62,6 +62,12 @@ void test_action::test_dummy_action() { } } +void test_action::read_action() { + print("action size: " + std::to_string(action_data_size())); + void* p = malloc(action_data_size()); + read_action_data(p, action_data_size()); +} + void test_action::read_action_to_0() { read_action_data( (void *)0, action_data_size() ); } diff --git a/unittests/test-contracts/test_api/test_api.cpp b/unittests/test-contracts/test_api/test_api.cpp index d51d3dc71b..e318e63bdb 100644 --- a/unittests/test-contracts/test_api/test_api.cpp +++ b/unittests/test-contracts/test_api/test_api.cpp @@ -49,6 +49,7 @@ extern "C" { //test_action WASM_TEST_HANDLER ( test_action, read_action_normal ); + WASM_TEST_HANDLER ( test_action, read_action ); WASM_TEST_HANDLER ( test_action, read_action_to_0 ); WASM_TEST_HANDLER ( test_action, read_action_to_64k ); WASM_TEST_HANDLER_EX( test_action, require_notice ); @@ -118,6 +119,8 @@ extern "C" { WASM_TEST_HANDLER ( test_transaction, send_action_empty ); WASM_TEST_HANDLER ( test_transaction, send_action_large ); WASM_TEST_HANDLER ( test_transaction, send_action_4k ); + WASM_TEST_HANDLER ( test_transaction, send_action_512k ); + WASM_TEST_HANDLER ( test_transaction, send_many_actions_512k ); WASM_TEST_HANDLER ( test_transaction, send_action_recurse ); WASM_TEST_HANDLER ( test_transaction, test_read_transaction ); WASM_TEST_HANDLER ( test_transaction, test_transaction_size ); diff --git a/unittests/test-contracts/test_api/test_api.hpp b/unittests/test-contracts/test_api/test_api.hpp index cffdc30db8..c6bec87812 100644 --- a/unittests/test-contracts/test_api/test_api.hpp +++ b/unittests/test-contracts/test_api/test_api.hpp @@ -93,6 +93,7 @@ struct test_print { struct test_action { static void read_action_normal(); + static void read_action(); static void read_action_to_0(); static void read_action_to_64k(); static void test_dummy_action(); @@ -202,6 +203,8 @@ struct test_transaction { static void send_action_max(); static void send_action_large(); static void send_action_4k(); + static void send_action_512k(); + static void send_many_actions_512k(); static void send_action_recurse(); static void send_action_inline_fail(); static void test_read_transaction(); diff --git a/unittests/test-contracts/test_api/test_api.wasm b/unittests/test-contracts/test_api/test_api.wasm index 987a3559529d9bf9f7170e2244e0e4da8abbb5ae..e81d4151045071723e9155c2c5d91e210b9cdab7 100755 GIT binary patch delta 21924 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 z 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 diff --git a/unittests/test-contracts/test_api/test_transaction.cpp b/unittests/test-contracts/test_api/test_transaction.cpp index f56d435e9c..c311a84a4d 100644 --- a/unittests/test-contracts/test_api/test_transaction.cpp +++ b/unittests/test-contracts/test_api/test_transaction.cpp @@ -84,17 +84,15 @@ void test_transaction::send_action_empty() { } /** - * cause failure due to a large action payload + * cause failure due to a large action payload, larger than max_inline_action_size of 512K */ void test_transaction::send_action_large() { using namespace eosio; - static char large_message[8 * 1024]; - test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action_normal" )> test_action; - copy_data( large_message, 8*1024, test_action.data ); + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action" )> test_action; + test_action.data.resize(512*1024+1); std::vector permissions = { {"testapi"_n, "active"_n} }; - action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action_normal")}, test_action ); - + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); act.send(); eosio_assert( false, "send_message_large() should've thrown an error" ); } @@ -104,16 +102,59 @@ void test_transaction::send_action_large() { */ void test_transaction::send_action_4k() { using namespace eosio; - static char large_message[4 * 1024]; - test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "test_action_ordinal4" )> test_action; - copy_data( large_message, 4*1024, test_action.data ); + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action" )> test_action; + test_action.data.resize(4*1024); + + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); + + act.send(); +} + +/** + * send an inline action that is 512K (limit is < 512K) + * the limit includes the size of the action + */ +void test_transaction::send_action_512k() { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action" )> test_action; + test_action.data.resize(1); std::vector permissions = { {"testapi"_n, "active"_n} }; - action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "test_action_ordinal4")}, test_action ); + action temp_act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); + + size_t action_size = pack_size(temp_act); + test_action.data.resize(512*1024-action_size-2); // check is < 512K + + // send at limit (512K - 1) + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action")}, test_action ); + + if (pack_size(act) != 512*1024-1) { + std::string err = "send_action_512k action size is: " + std::to_string(action_size) + " not 512K-1"; + eosio_assert(false, err.c_str()); + } act.send(); } +/** + * send many inline actions that are 512K (limit is < 512K) + * the limit includes the size of the action + */ +void test_transaction::send_many_actions_512k() { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_transaction", "send_action_512k" )> test_action; + + test_action.data.resize(1); + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_transaction", "send_action_512k")}, test_action ); + + // 65 * 512K > wasm memory limit, which is ok because each gets their own wasm instantiation + for (size_t i = 0; i < 65; ++i) { + act.send(); + } +} + /** * cause failure due recursive loop */ From 1a7e37ac48c59384457d7465e418a9a171efdff6 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 15 Sep 2023 12:43:59 -0500 Subject: [PATCH 3/5] GH-1614 Remove max-nonprivileged-inline-action-size from docs --- docs/01_nodeos/03_plugins/chain_plugin/index.md | 4 ---- tests/PerformanceHarness/README.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/docs/01_nodeos/03_plugins/chain_plugin/index.md b/docs/01_nodeos/03_plugins/chain_plugin/index.md index 0b932e78ac..f417101b5e 100644 --- a/docs/01_nodeos/03_plugins/chain_plugin/index.md +++ b/docs/01_nodeos/03_plugins/chain_plugin/index.md @@ -190,10 +190,6 @@ Config Options for eosio::chain_plugin: --enable-account-queries arg (=0) enable queries to find accounts by various metadata. - --max-nonprivileged-inline-action-size arg (=4096) - maximum allowed size (in bytes) of an - inline action for a nonprivileged - account --transaction-retry-max-storage-size-gb arg Maximum size (in GiB) allowed to be allocated for the Transaction Retry diff --git a/tests/PerformanceHarness/README.md b/tests/PerformanceHarness/README.md index 3178aa9e51..29c84f5536 100644 --- a/tests/PerformanceHarness/README.md +++ b/tests/PerformanceHarness/README.md @@ -1365,8 +1365,6 @@ Finally, the full detail test report for each of the determined max TPS throughp "_enableAccountQueriesNodeosDefault": 0, "_enableAccountQueriesNodeosArg": "--enable-account-queries", "maxNonprivilegedInlineActionSize": null, - "_maxNonprivilegedInlineActionSizeNodeosDefault": 4096, - "_maxNonprivilegedInlineActionSizeNodeosArg": "--max-nonprivileged-inline-action-size", "transactionRetryMaxStorageSizeGb": null, "_transactionRetryMaxStorageSizeGbNodeosDefault": null, "_transactionRetryMaxStorageSizeGbNodeosArg": "--transaction-retry-max-storage-size-gb", @@ -2033,8 +2031,6 @@ The Performance Test Basic generates, by default, a report that details results "_enableAccountQueriesNodeosDefault": 0, "_enableAccountQueriesNodeosArg": "--enable-account-queries", "maxNonprivilegedInlineActionSize": null, - "_maxNonprivilegedInlineActionSizeNodeosDefault": 4096, - "_maxNonprivilegedInlineActionSizeNodeosArg": "--max-nonprivileged-inline-action-size", "transactionRetryMaxStorageSizeGb": null, "_transactionRetryMaxStorageSizeGbNodeosDefault": null, "_transactionRetryMaxStorageSizeGbNodeosArg": "--transaction-retry-max-storage-size-gb", From 3e3f8d0d20ce2a5ca3cb879ffbf808d078bb9677 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 15 Sep 2023 13:57:52 -0500 Subject: [PATCH 4/5] GH-1614 remove unused config_max_nonprivileged_inline_action_size option --- libraries/testing/include/eosio/testing/tester.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 5b0eb752d8..a85ed7f70d 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -449,7 +449,7 @@ namespace eosio { namespace testing { class tester : public base_tester { public: - tester(setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}, std::optional config_max_nonprivileged_inline_action_size = std::optional{}) { + tester(setup_policy policy = setup_policy::full, db_read_mode read_mode = db_read_mode::HEAD, std::optional genesis_max_inline_action_size = std::optional{}) { init(policy, read_mode, genesis_max_inline_action_size); } From d8f99d50d8e5f6c0047eab15aab26f323c481cea Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 15 Sep 2023 14:08:30 -0500 Subject: [PATCH 5/5] GH-1614 Cleanup inline action tests --- unittests/api_tests.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 5cac8246e6..673995ec18 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -1565,12 +1565,12 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, validating_tester) { try { } FC_LOG_AND_RETHROW() } /************************************************************************************* - * verify subjective limit test case + * verify objective limit test case *************************************************************************************/ -BOOST_AUTO_TEST_CASE(inline_action_subjective_limit) { try { +BOOST_AUTO_TEST_CASE(inline_action_with_over_4k_limit) { try { const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k + 1}); - tester chain2(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k}); + tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}); + tester chain2(setup_policy::full, db_read_mode::HEAD, {_4k + 100}); signed_block_ptr block; for (int n=0; n < 2; ++n) { block = chain.produce_block(); @@ -1597,7 +1597,7 @@ BOOST_AUTO_TEST_CASE(inline_action_subjective_limit) { try { *************************************************************************************/ BOOST_AUTO_TEST_CASE(inline_action_objective_limit) { try { const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k}, {_4k - 1}); + tester chain(setup_policy::full, db_read_mode::HEAD, {_4k}); chain.produce_blocks(2); chain.create_account( "testapi"_n ); chain.produce_blocks(100); @@ -1617,10 +1617,10 @@ BOOST_AUTO_TEST_CASE(inline_action_objective_limit) { try { } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(deferred_inline_action_subjective_limit) { try { +BOOST_AUTO_TEST_CASE(deferred_inline_action_limit) { try { const uint32_t _4k = 4 * 1024; - tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k + 1}); - tester chain2(setup_policy::full, db_read_mode::HEAD, {_4k + 100}, {_4k}); + tester chain(setup_policy::full, db_read_mode::HEAD, {_4k + 100}); + tester chain2(setup_policy::full, db_read_mode::HEAD, {_4k + 100}); signed_block_ptr block; for (int n=0; n < 2; ++n) { block = chain.produce_block();