Skip to content

Commit

Permalink
Merge pull request #1697 from AntelopeIO/disable_deferred_trxs_prot_f…
Browse files Browse the repository at this point in the history
…eatures

Implement DISABLE_DEFERRED_TRXS_STAGE_1 and DISABLE_DEFERRED_TRXS_STAGE_2 protocol features
  • Loading branch information
linh2931 authored Oct 4, 2023
2 parents 19f78f9 + eb232a7 commit 7efa226
Show file tree
Hide file tree
Showing 19 changed files with 594 additions and 158 deletions.
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;
}

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;
}
return true;
}

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

0 comments on commit 7efa226

Please sign in to comment.