Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement DISABLE_DEFERRED_TRXS_STAGE_1 and DISABLE_DEFERRED_TRXS_STAGE_2 protocol features #1697

Merged
merged 27 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5523fd5
implement DISABLE_DEFERRED_TRXS_STAGE_1 and DISABLE_DEFERRED_TRXS_STA…
linh2931 Sep 29, 2023
d8f975a
make send_deferred, cancel_deferred and canceldelay no-op after DISAB…
linh2931 Sep 29, 2023
cb966dd
enforce deferred trxs retirement rules after disable_deferred_trxs_st…
linh2931 Sep 29, 2023
648b016
Exclude DISABLE_DEFERRED_TRXS_STAGE_1 and DISABLE_DEFERRED_TRXS_STAGE…
linh2931 Sep 29, 2023
83a7cd6
use a new setup_policy::full_but_disable_deferrd_trx for tests which …
linh2931 Sep 30, 2023
bdb607d
use centralized testers for setup_policy::full_but_disable_deferrd_trx
linh2931 Sep 30, 2023
28ef3ca
add tests for disable_deferred_trxs_stage_1 protocol feature
linh2931 Sep 30, 2023
5d61a8a
add tests for disable_deferred_trxs_stage_2
linh2931 Oct 1, 2023
015ff42
use tester_no_disable_deferrd_trx instead of validating_tester_no_dis…
linh2931 Oct 1, 2023
3a11565
enfore the rule of disable_deferred_trxs_stage_2 dependency on disabl…
linh2931 Oct 2, 2023
3a3e059
add a disable_deferred_trxs_stage_2 dependency test
linh2931 Oct 2, 2023
efb067a
add missing disable_deferred_trxs_stage_2's dependency to its definit…
linh2931 Oct 2, 2023
49bff9b
enfore deferred trx retirement rule correctly and add a test for it
linh2931 Oct 2, 2023
4e8e1a9
use system-contracts from main instead of release/3.1
linh2931 Oct 2, 2023
a515033
move is_builtin_activated( builtin_protocol_feature_t::disable_deferr…
linh2931 Oct 2, 2023
db52566
add cancelcall action to deferred_test contract to exercise cancel_de…
linh2931 Oct 3, 2023
391a992
add tests for cancel_deferred host function before and after disable_…
linh2931 Oct 3, 2023
779108a
use eos-system-contracts release/3.2 branch
linh2931 Oct 3, 2023
b344239
remove non-needed activation handler for disable_deferred_trxs_stage_…
linh2931 Oct 3, 2023
51bea7b
improve prototol features descriptions and update feature digests acc…
linh2931 Oct 3, 2023
7b3a7c5
fix typos in deferrd instances (should be deferred)
linh2931 Oct 3, 2023
cf15dd8
refactor preactivate_builtin_protocol_features and revert back to ori…
linh2931 Oct 3, 2023
28e9d3e
revert to use full protococol features for currency_tests not involve…
linh2931 Oct 3, 2023
058ed39
make sure all protocol features are activated in the same order such …
linh2931 Oct 3, 2023
da6ad0a
consistently activating protocol features in the same order
linh2931 Oct 3, 2023
4c38e86
make api_tests::transaction_tests for before and after disable_trxs_p…
linh2931 Oct 4, 2023
eb232a7
Merge branch 'main' into disable_deferred_trxs_prot_features
linh2931 Oct 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cicd/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"prerelease":false
},
"eossystemcontracts":{
"ref":"release/3.1"
"ref":"release/3.2"
}
}
10 changes: 10 additions & 0 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,11 @@ void apply_context::execute_context_free_inline( action&& a ) {


void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ) {
// no-op after DISABLE_DEFERRED_TRXS_STAGE_1 is activated
if( control.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) ) {
return;
}

EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot schedule a deferred transaction from within a readonly transaction" );
EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" );

Expand Down Expand Up @@ -624,6 +629,11 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
}

bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, account_name sender ) {
// no-op after DISABLE_DEFERRED_TRXS_STAGE_1 is activated
if( control.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) ) {
return false;
}

EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot cancel a deferred transaction from within a readonly transaction" );
auto& generated_transaction_idx = db.get_mutable_index<generated_transaction_multi_index>();
const auto* gto = db.find<generated_transaction_object,by_sender_id>(boost::make_tuple(sender, sender_id));
Expand Down
22 changes: 19 additions & 3 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ struct controller_impl {
set_activation_handler<builtin_protocol_feature_t::get_block_num>();
set_activation_handler<builtin_protocol_feature_t::crypto_primitives>();
set_activation_handler<builtin_protocol_feature_t::bls_primitives>();
set_activation_handler<builtin_protocol_feature_t::disable_deferred_trxs_stage_2>();

self.irreversible_block.connect([this](const block_state_ptr& bsp) {
wasmif.current_lib(bsp->block_num);
Expand Down Expand Up @@ -1302,8 +1303,11 @@ struct controller_impl {

fc::datastream<const char*> ds( gtrx.packed_trx.data(), gtrx.packed_trx.size() );

EOS_ASSERT( gtrx.delay_until <= self.pending_block_time(), transaction_exception, "this transaction isn't ready",
("gtrx.delay_until",gtrx.delay_until)("pbt",self.pending_block_time()) );
// check delay_until only before disable_deferred_trxs_stage_1 is activated.
if( !self.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) ) {
EOS_ASSERT( gtrx.delay_until <= self.pending_block_time(), transaction_exception, "this transaction isn't ready",
("gtrx.delay_until",gtrx.delay_until)("pbt",self.pending_block_time()) );
}

signed_transaction dtrx;
fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
Expand All @@ -1312,8 +1316,11 @@ struct controller_impl {
transaction_metadata::trx_type::scheduled );
trx->accepted = true;

// After disable_deferred_trxs_stage_1 is activated, a deferred transaction
// can only be retired as expired, and it can be retired as expired
// regardless of whether its delay_util or expiration times have been reached.
transaction_trace_ptr trace;
if( gtrx.expiration < self.pending_block_time() ) {
if( self.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1 ) || gtrx.expiration < self.pending_block_time() ) {
trace = std::make_shared<transaction_trace>();
trace->id = gtrx.trx_id;
trace->block_num = self.head_block_num() + 1;
Expand Down Expand Up @@ -3835,6 +3842,15 @@ void controller_impl::on_activation<builtin_protocol_feature_t::bls_primitives>(
} );
}

template<>
void controller_impl::on_activation<builtin_protocol_feature_t::disable_deferred_trxs_stage_2>() {
const auto& idx = db.get_index<generated_transaction_multi_index, by_trx_id>();
// remove all deferred trxs and refund their payers
for( auto itr = idx.begin(); itr != idx.end(); itr = idx.begin() ) {
remove_scheduled_transaction(*itr);
}
}

/// End of protocol feature activation handlers

} } /// eosio::chain
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ enum class builtin_protocol_feature_t : uint32_t {
crypto_primitives = 19,
get_block_num = 20,
bls_primitives = 21,
disable_deferred_trxs_stage_1 = 22,
disable_deferred_trxs_stage_2 = 23,
reserved_private_fork_protocol_features = 500000,
};

Expand Down
35 changes: 35 additions & 0 deletions libraries/chain/protocol_feature_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,41 @@ Adds new cryptographic host functions
*/
{}
} )
( builtin_protocol_feature_t::disable_deferred_trxs_stage_1, builtin_protocol_feature_spec{
"DISABLE_DEFERRED_TRXS_STAGE_1",
fc::variant("440c3efaaab212c387ce967c574dc813851cf8332d041beb418dfaf55facd5a9").as<digest_type>(),
// SHA256 hash of the raw message below within the comment delimiters (do not modify message below).
/*
Builtin protocol feature: DISABLE_DEFERRED_TRXS_STAGE_1
Once this first disabling deferred transactions protocol feature is activated,
the behavior of the send_deferred and cancel_deferred host functions and
canceldelay native action changes so that they become no-ops.
In addition, any block that retires a deferred transaction with a status other
than expired is invalid.
Also, a deferred transaction can only be retired as expired, and it can be
retired as expired regardless of whether its delay_util or expiration times
have been reached.
*/
{}
} )
( builtin_protocol_feature_t::disable_deferred_trxs_stage_2, builtin_protocol_feature_spec{
"DISABLE_DEFERRED_TRXS_STAGE_2",
fc::variant("a857eeb932774c511a40efb30346ec01bfb7796916b54c3c69fe7e5fb70d5cba").as<digest_type>(),
// SHA256 hash of the raw message below within the comment delimiters (do not modify message below).
/*
Builtin protocol feature: DISABLE_DEFERRED_TRXS_STAGE_2
Depends on: DISABLE_DEFERRED_TRXS_STAGE_1
On activation of this second disabling deferred transactions protocol feature,
all pending deferred transactions are removed from state and the RAM paid by
the sender of each deferred transaction is refunded. Also, any block that
retires a deferred transaction is invalid.
*/
{builtin_protocol_feature_t::disable_deferred_trxs_stage_1}
} )
;


Expand Down
17 changes: 17 additions & 0 deletions libraries/testing/include/eosio/testing/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ namespace eosio { namespace testing {
preactivate_feature_only,
preactivate_feature_and_new_bios,
old_wasm_parser,
full_except_do_not_disable_deferred_trx,
full
};

Expand Down Expand Up @@ -386,6 +387,7 @@ namespace eosio { namespace testing {
void preactivate_protocol_features(const vector<digest_type> feature_digests);
void preactivate_builtin_protocol_features(const std::vector<builtin_protocol_feature_t>& features);
void preactivate_all_builtin_protocol_features();
void preactivate_all_but_disable_deferred_trx();

static genesis_state default_genesis() {
genesis_state genesis;
Expand Down Expand Up @@ -445,6 +447,9 @@ namespace eosio { namespace testing {

public:
vector<digest_type> protocol_features_to_be_activated_wo_preactivation;

private:
std::vector<builtin_protocol_feature_t> get_all_builtin_protocol_features();
};

class tester : public base_tester {
Expand Down Expand Up @@ -512,6 +517,12 @@ namespace eosio { namespace testing {
bool validate() { return true; }
};

class tester_no_disable_deferred_trx : public tester {
public:
tester_no_disable_deferred_trx(): tester(setup_policy::full_except_do_not_disable_deferred_trx) {
}
};

class validating_tester : public base_tester {
public:
virtual ~validating_tester() {
Expand Down Expand Up @@ -657,6 +668,12 @@ namespace eosio { namespace testing {
bool skip_validate = false;
};

class validating_tester_no_disable_deferred_trx : public validating_tester {
public:
validating_tester_no_disable_deferred_trx(): validating_tester({}, nullptr, setup_policy::full_except_do_not_disable_deferred_trx) {
}
};

/**
* Utility predicate to check whether an fc::exception message is equivalent to a given string
*/
Expand Down
67 changes: 45 additions & 22 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,16 @@ namespace eosio { namespace testing {
set_bios_contract();
break;
}
case setup_policy::full: {
case setup_policy::full:
case setup_policy::full_except_do_not_disable_deferred_trx: {
schedule_preactivate_protocol_feature();
produce_block();
set_before_producer_authority_bios_contract();
preactivate_all_builtin_protocol_features();
if( policy == setup_policy::full ) {
preactivate_all_builtin_protocol_features();
} else {
preactivate_all_but_disable_deferred_trx();
}
produce_block();
set_bios_contract();
break;
Expand Down Expand Up @@ -1184,20 +1189,7 @@ namespace eosio { namespace testing {
}
}

void base_tester::preactivate_builtin_protocol_features(const std::vector<builtin_protocol_feature_t>& builtin_features) {
const auto& pfs = control->get_protocol_feature_manager().get_protocol_feature_set();

// This behavior is disabled by configurable_wasm_limits
std::vector<digest_type> features;
for(builtin_protocol_feature_t feature : builtin_features ) {
if( auto digest = pfs.get_builtin_digest( feature ) ) {
features.push_back( *digest );
}
}
preactivate_protocol_features(features);
}

void base_tester::preactivate_all_builtin_protocol_features() {
void base_tester::preactivate_builtin_protocol_features(const std::vector<builtin_protocol_feature_t>& builtins) {
const auto& pfm = control->get_protocol_feature_manager();
const auto& pfs = pfm.get_protocol_feature_set();
const auto current_block_num = control->head_block_num() + (control->is_building_block() ? 1 : 0);
Expand Down Expand Up @@ -1225,12 +1217,7 @@ namespace eosio { namespace testing {
preactivations.emplace_back( feature_digest );
};

std::vector<builtin_protocol_feature_t> ordered_builtins;
for( const auto& f : builtin_protocol_feature_codenames ) {
ordered_builtins.push_back( f.first );
}
std::sort( ordered_builtins.begin(), ordered_builtins.end() );
for( const auto& f : ordered_builtins ) {
for( const auto& f : builtins ) {
auto digest = pfs.get_builtin_digest( f);
if( !digest ) continue;
add_digests( *digest );
Expand All @@ -1239,6 +1226,42 @@ namespace eosio { namespace testing {
preactivate_protocol_features( preactivations );
}

std::vector<builtin_protocol_feature_t> base_tester::get_all_builtin_protocol_features() {
std::vector<builtin_protocol_feature_t> builtins;
for( const auto& f : builtin_protocol_feature_codenames ) {
builtins.push_back( f.first );
}

// Sorting is here to ensure a consistent order across platforms given that it is
// pulling the items from an std::unordered_map. This order is important because
// it impacts the block IDs generated and written out to logs for some tests such
// as the deep-mind tests.
std::sort( builtins.begin(), builtins.end() );

return builtins;
}

void base_tester::preactivate_all_builtin_protocol_features() {
preactivate_builtin_protocol_features( get_all_builtin_protocol_features() );
}

void base_tester::preactivate_all_but_disable_deferred_trx() {
std::vector<builtin_protocol_feature_t> builtins;
for( const auto& f : get_all_builtin_protocol_features() ) {
// Before deferred trxs feature is fully disabled, existing tests involving
// deferred trxs need to be exercised to make sure existing behaviors are
// maintained. Excluding DISABLE_DEFERRED_TRXS_STAGE_1 and DISABLE_DEFERRED_TRXS_STAGE_2
// from full protocol feature list such that existing tests can run.
if( f == builtin_protocol_feature_t::disable_deferred_trxs_stage_1 || f == builtin_protocol_feature_t::disable_deferred_trxs_stage_2 ) {
continue;
}
heifner marked this conversation as resolved.
Show resolved Hide resolved

builtins.push_back( f );
}

preactivate_builtin_protocol_features( builtins );
}

tester::tester(const std::function<void(controller&)>& control_setup, setup_policy policy, db_read_mode read_mode) {
auto def_conf = default_config(tempdir);
def_conf.first.read_mode = read_mode;
Expand Down
30 changes: 22 additions & 8 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
bool remove_expired_trxs(const fc::time_point& deadline);
bool remove_expired_blacklisted_trxs(const fc::time_point& deadline);
bool process_unapplied_trxs(const fc::time_point& deadline);
void retire_expired_deferred_trxs(const fc::time_point& deadline);
bool retire_deferred_trxs(const fc::time_point& deadline);
bool process_incoming_trxs(const fc::time_point& deadline, unapplied_transaction_queue::iterator& itr);

struct push_result {
Expand Down Expand Up @@ -1948,9 +1948,15 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
if (!process_unapplied_trxs(preprocess_deadline))
return start_block_result::exhausted;

// Hard-code the deadline to retire expired deferred trxs to 10ms
auto deferred_trxs_deadline = std::min<fc::time_point>(preprocess_deadline, fc::time_point::now() + fc::milliseconds(10));
retire_expired_deferred_trxs(deferred_trxs_deadline);
// after DISABLE_DEFERRED_TRXS_STAGE_2 is activated,
// no deferred trxs are allowed to be retired
if (!chain.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_2) ) {
// Hard-code the deadline to retire expired deferred trxs to 10ms
auto deferred_trxs_deadline = std::min<fc::time_point>(preprocess_deadline, fc::time_point::now() + fc::milliseconds(10));
if (!retire_deferred_trxs(deferred_trxs_deadline)) {
return start_block_result::failed;
}
}
}

repost_exhausted_transactions(preprocess_deadline);
Expand Down Expand Up @@ -2293,7 +2299,7 @@ bool producer_plugin_impl::process_unapplied_trxs(const fc::time_point& deadline
return !exhausted;
}

void producer_plugin_impl::retire_expired_deferred_trxs(const fc::time_point& deadline) {
bool producer_plugin_impl::retire_deferred_trxs(const fc::time_point& deadline) {
int num_applied = 0;
int num_failed = 0;
int num_processed = 0;
Expand All @@ -2304,10 +2310,13 @@ void producer_plugin_impl::retire_expired_deferred_trxs(const fc::time_point& de
const auto& expired_idx = chain.db().get_index<generated_transaction_multi_index, by_expiration>();
const auto expired_size = expired_idx.size();
auto expired_itr = expired_idx.begin();
bool stage_1_activated = chain.is_builtin_activated( builtin_protocol_feature_t::disable_deferred_trxs_stage_1);

while (expired_itr != expired_idx.end()) {
if (expired_itr->expiration >= pending_block_time) {
break; // not expired yet
// * Before disable_deferred_trxs_stage_1 is activated, retire only expired deferred trxs.
// * After disable_deferred_trxs_stage_1, retire any deferred trxs in any order
if (!stage_1_activated && expired_itr->expiration >= pending_block_time) { // before stage_1 and not expired yet
break;
}

if (exhausted || deadline <= fc::time_point::now()) {
Expand Down Expand Up @@ -2374,9 +2383,14 @@ void producer_plugin_impl::retire_expired_deferred_trxs(const fc::time_point& de
}

if (expired_size > 0) {
fc_dlog(_log, "Processed ${m} of ${n} expired scheduled transactions, Applied ${applied}, Failed/Dropped ${failed}",
fc_dlog(_log, "Processed ${m} of ${n} scheduled transactions, Applied ${applied}, Failed/Dropped ${failed}",
("m", num_processed)("n", expired_size)("applied", num_applied)("failed", num_failed));
}

if (stage_1_activated && num_failed > 0) {
return false;
heifner marked this conversation as resolved.
Show resolved Hide resolved
}
return true;
}

bool producer_plugin_impl::process_incoming_trxs(const fc::time_point& deadline, unapplied_transaction_queue::iterator& itr) {
Expand Down
Loading