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

introduce new read-only transaction RPC end point #558

Merged
merged 43 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4e5a2cc
implement read-only transaction
linh2931 Dec 8, 2022
08e7e1c
check in missing read_only_trx_test.py
linh2931 Dec 8, 2022
4091091
check in missing read_only_trx_tests.cpp
linh2931 Dec 8, 2022
817f9f1
Fix a compile error on Ubuntu 22, do not use designated initializers …
linh2931 Dec 8, 2022
598a2c8
Merge branch 'main' into send_read_only_trx
linh2931 Dec 9, 2022
367123b
restructure unit tests so they are modularized
linh2931 Dec 9, 2022
110303d
Refactor cleos main and chain_plugin to remove duplicate code
linh2931 Dec 10, 2022
f5ac3f7
do not check authorization for read-only transactions; do not allow c…
linh2931 Dec 10, 2022
059330e
restructure transaction init and finalize; add is_transient() to simp…
linh2931 Dec 10, 2022
53caa49
Do not undo_session for read-only transaction, prevent chainbase read…
linh2931 Dec 10, 2022
30e77a1
revert the changes for elpased and net_usage for non-read-only transa…
linh2931 Dec 12, 2022
bf92e33
use make_scoped_exit to protect chainbase from being stuck in read_on…
linh2931 Dec 12, 2022
864e31e
finish changeing is_read_only() to is_transient() for deep-mind logging
linh2931 Dec 13, 2022
79e387e
use is_transient in producer_plugin; refine unit tests
linh2931 Dec 13, 2022
525055f
bump chainbase version to main which contains final changes for read-…
linh2931 Dec 16, 2022
7adb00b
Merge branch 'main' into send_read_only_trx
linh2931 Dec 20, 2022
789d077
fix a merge from main error
linh2931 Dec 21, 2022
97b28b6
fix merge error, do not enforce block_cpu_limit or on-chain max_trans…
linh2931 Dec 21, 2022
18f4ce2
remove duplicate code from merging, improve deadline calculation for …
linh2931 Dec 22, 2022
372005e
Merge branch 'main' into send_read_only_trx
linh2931 Dec 22, 2022
842fa04
honor block_deadline, set deadline_exception_code, and split a large …
linh2931 Dec 22, 2022
290fc7a
Merge branch 'main' into send_read_only_trx
linh2931 Dec 22, 2022
2e9de77
Add configurable max-read-only-transaction-time; add node_configured_…
linh2931 Dec 26, 2022
1c667f7
Add transaction execution mode to controller for better managing dry-…
linh2931 Dec 27, 2022
eacc66d
simplify and streamline deep-mind logging for dry-run and read-only t…
linh2931 Dec 27, 2022
5e5a2c6
add test for max_read_only_transaction_time deadline exception
linh2931 Jan 1, 2023
b646c92
improve max-read-only-transaction-time description, fix a comment typ…
linh2931 Jan 5, 2023
e990619
do not perform key recovery if there are no signatures
linh2931 Jan 5, 2023
9380de4
rework to make sure deep-mind loggins is not generated for dry-run an…
linh2931 Jan 5, 2023
92f751d
revert the trx_execution_mode changes
linh2931 Jan 5, 2023
0148c8d
Merge branch 'main' into send_read_only_trx
linh2931 Jan 5, 2023
5260e4c
use single get_deep_mind_logger method from control and pass trx_is_t…
linh2931 Jan 6, 2023
654aade
completely review deep mind logging to make sure no deep mind logging…
linh2931 Jan 9, 2023
1b18206
Merge branch 'main' into send_read_only_trx
linh2931 Feb 3, 2023
4365542
add no_auth_table to new unittests/test_contracts.hpp.in due to chang…
linh2931 Feb 3, 2023
717685c
change contracts to test_contracts
linh2931 Feb 3, 2023
251c2a3
Merge branch 'main' into send_read_only_trx
linh2931 Feb 21, 2023
b160db9
Merge branch 'main' into send_read_only_trx
linh2931 Feb 22, 2023
a7df2e7
Merge branch 'main' into send_read_only_trx
linh2931 Mar 2, 2023
d0c8046
do not allow state-changing readonly privilege, schedualing and cance…
linh2931 Mar 2, 2023
5aecde2
correct add_pending_ram_usage's handling of deep-mind logging
linh2931 Mar 2, 2023
4a3b81c
set global_action_sequence and recv_sequence to 0 for read-only trans…
linh2931 Mar 2, 2023
2ae98cb
correct bad comments about dm logging and improve error message for s…
linh2931 Mar 2, 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
80 changes: 48 additions & 32 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void apply_context::exec_one()
print_debug(receiver, trace);
}

if (auto dm_logger = control.get_deep_mind_logger())
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
{
dm_logger->on_end_action();
}
Expand Down Expand Up @@ -289,7 +289,7 @@ void apply_context::require_recipient( account_name recipient ) {
schedule_action( action_ordinal, recipient, false )
);

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_require_recipient();
}
}
Expand Down Expand Up @@ -354,7 +354,7 @@ void apply_context::execute_inline( action&& a ) {
"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 ) {
if( !control.skip_auth_check() && !privileged && !trx_context.is_read_only() ) {
try {
control.get_authorization_manager()
.check_authorization( {a},
Expand All @@ -363,7 +363,7 @@ void apply_context::execute_inline( action&& a ) {
control.pending_block_time() - trx_context.published,
std::bind(&transaction_context::checktime, &this->trx_context),
false,
trx_context.is_dry_run(),
trx_context.is_dry_run(), // check_but_dont_fail
inherited_authorizations
);

Expand Down Expand Up @@ -394,7 +394,7 @@ void apply_context::execute_inline( action&& a ) {
schedule_action( std::move(a), inline_receiver, false )
);

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_send_inline();
}
}
Expand All @@ -419,13 +419,14 @@ void apply_context::execute_context_free_inline( action&& a ) {
schedule_action( std::move(a), inline_receiver, true )
);

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_send_context_free_inline();
}
}


void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ) {
EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot schedule a readonly deferred transaction" );
EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" );

bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_speculative_block()
Expand Down Expand Up @@ -557,7 +558,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
subjective_block_production_exception,
"Replacing a deferred transaction is temporarily disabled." );

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", ptr->id)), "deferred_trx", "cancel", "deferred_trx_cancel");
}

Expand All @@ -575,7 +576,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
trx_id_for_new_obj = ptr->trx_id;
}

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_cancel_deferred(deep_mind_handler::operation_qualifier::modify, *ptr);
}

Expand All @@ -592,7 +593,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a

trx_size = gtx.set( trx );

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_send_deferred(deep_mind_handler::operation_qualifier::modify, gtx);
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gtx.id)), "deferred_trx", "update", "deferred_trx_add");
}
Expand All @@ -609,7 +610,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a

trx_size = gtx.set( trx );

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_send_deferred(deep_mind_handler::operation_qualifier::none, gtx);
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gtx.id)), "deferred_trx", "add", "deferred_trx_add");
}
Expand All @@ -626,10 +627,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 ) {
EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot cancel a readonly deferred 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));
if ( gto ) {
if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_cancel_deferred(deep_mind_handler::operation_qualifier::none, *gto);
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gto->id)), "deferred_trx", "cancel", "deferred_trx_cancel");
}
Expand Down Expand Up @@ -670,7 +672,7 @@ const table_id_object& apply_context::find_or_create_table( name code, name scop
return *existing_tid;
}

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
std::string event_id = RAM_EVENT_ID("${code}:${scope}:${table}",
("code", code)
("scope", scope)
Expand All @@ -687,14 +689,14 @@ const table_id_object& apply_context::find_or_create_table( name code, name scop
t_id.table = table;
t_id.payer = payer;

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_create_table(t_id);
}
});
}

void apply_context::remove_table( const table_id_object& tid ) {
if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
std::string event_id = RAM_EVENT_ID("${code}:${scope}:${table}",
("code", tid.code)
("scope", tid.scope)
Expand All @@ -705,7 +707,7 @@ void apply_context::remove_table( const table_id_object& tid ) {

update_db_usage(tid.payer, - config::billable_size_v<table_id_object>);

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_remove_table(tid);
}

Expand Down Expand Up @@ -778,11 +780,13 @@ int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t b
}

int apply_context::db_store_i64( name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot store a db record when executing a readonly transaction" );
return db_store_i64( receiver, scope, table, payer, id, buffer, buffer_size);
}

int apply_context::db_store_i64( name code, name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
// require_write_lock( scope );
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot store a db record when executing a readonly transaction" );
const auto& tab = find_or_create_table( code, scope, table, payer );
auto tableid = tab.id;

Expand All @@ -801,7 +805,7 @@ int apply_context::db_store_i64( name code, name scope, name table, const accoun

int64_t billable_size = (int64_t)(buffer_size + config::billable_size_v<key_value_object>);

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
std::string event_id = RAM_EVENT_ID("${table_code}:${scope}:${table_name}:${primkey}",
("table_code", tab.code)
("scope", tab.scope)
Expand All @@ -813,7 +817,7 @@ int apply_context::db_store_i64( name code, name scope, name table, const accoun

update_db_usage( payer, billable_size);

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_db_store_i64(tab, obj);
}

Expand All @@ -822,6 +826,7 @@ int apply_context::db_store_i64( name code, name scope, name table, const accoun
}

void apply_context::db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ) {
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot update a db record when executing a readonly transaction" );
const key_value_object& obj = keyval_cache.get( iterator );

const auto& table_obj = keyval_cache.get_table( obj.t_id );
Expand All @@ -836,7 +841,7 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char*
if( payer == account_name() ) payer = obj.payer;

std::string event_id;
if (control.get_deep_mind_logger() != nullptr) {
if (control.get_deep_mind_logger(trx_context.is_transient()) != nullptr) {
event_id = RAM_EVENT_ID("${table_code}:${scope}:${table_name}:${primkey}",
("table_code", table_obj.code)
("scope", table_obj.scope)
Expand All @@ -847,27 +852,27 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char*

if( account_name(obj.payer) != payer ) {
// refund the existing payer
if (auto dm_logger = control.get_deep_mind_logger())
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
{
dm_logger->on_ram_trace(std::string(event_id), "table_row", "remove", "primary_index_update_remove_old_payer");
}
update_db_usage( obj.payer, -(old_size) );
// charge the new payer
if (auto dm_logger = control.get_deep_mind_logger())
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
{
dm_logger->on_ram_trace(std::move(event_id), "table_row", "add", "primary_index_update_add_new_payer");
}
update_db_usage( payer, (new_size));
} else if(old_size != new_size) {
// charge/refund the existing payer the difference
if (auto dm_logger = control.get_deep_mind_logger())
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
{
dm_logger->on_ram_trace(std::move(event_id) , "table_row", "update", "primary_index_update");
}
update_db_usage( obj.payer, new_size - old_size);
}

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_db_update_i64(table_obj, obj, payer, buffer, buffer_size);
}

Expand All @@ -878,14 +883,15 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char*
}

void apply_context::db_remove_i64( int iterator ) {
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot remove a db record when executing a readonly transaction" );
const key_value_object& obj = keyval_cache.get( iterator );

const auto& table_obj = keyval_cache.get_table( obj.t_id );
EOS_ASSERT( table_obj.code == receiver, table_access_violation, "db access violation" );

// require_write_lock( table_obj.scope );

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
std::string event_id = RAM_EVENT_ID("${table_code}:${scope}:${table_name}:${primkey}",
("table_code", table_obj.code)
("scope", table_obj.scope)
Expand All @@ -897,7 +903,7 @@ void apply_context::db_remove_i64( int iterator ) {

update_db_usage( obj.payer, -(obj.value.size() + config::billable_size_v<key_value_object>) );

if (auto dm_logger = control.get_deep_mind_logger()) {
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
dm_logger->on_db_remove_i64(table_obj, obj);
}

Expand Down Expand Up @@ -1029,17 +1035,27 @@ int apply_context::db_end_i64( name code, name scope, name table ) {

uint64_t apply_context::next_global_sequence() {
const auto& p = control.get_dynamic_global_properties();
db.modify( p, [&]( auto& dgp ) {
++dgp.global_action_sequence;
});
return p.global_action_sequence;
if ( trx_context.is_read_only() ) {
// To avoid confusion of duplicated global sequence number, hard code to be 0.
return 0;
} else {
db.modify( p, [&]( auto& dgp ) {
++dgp.global_action_sequence;
});
return p.global_action_sequence;
}
}

uint64_t apply_context::next_recv_sequence( const account_metadata_object& receiver_account ) {
db.modify( receiver_account, [&]( auto& ra ) {
++ra.recv_sequence;
});
return receiver_account.recv_sequence;
if ( trx_context.is_read_only() ) {
// To avoid confusion of duplicated receive sequence number, hard code to be 0.
return 0;
} else {
db.modify( receiver_account, [&]( auto& ra ) {
++ra.recv_sequence;
});
return receiver_account.recv_sequence;
}
}
uint64_t apply_context::next_auth_sequence( account_name actor ) {
const auto& amo = db.get<account_metadata_object,by_name>( actor );
Expand Down
16 changes: 9 additions & 7 deletions libraries/chain/authorization_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ namespace eosio { namespace chain {
permission_name name,
permission_id_type parent,
const authority& auth,
bool is_trx_transient,
time_point initial_creation_time
)
{
Expand All @@ -158,7 +159,7 @@ namespace eosio { namespace chain {
p.last_updated = creation_time;
p.auth = auth;

if (auto dm_logger = _control.get_deep_mind_logger()) {
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
dm_logger->on_create_permission(p);
}
});
Expand All @@ -169,6 +170,7 @@ namespace eosio { namespace chain {
permission_name name,
permission_id_type parent,
authority&& auth,
bool is_trx_transient,
time_point initial_creation_time
)
{
Expand All @@ -193,20 +195,20 @@ namespace eosio { namespace chain {
p.last_updated = creation_time;
p.auth = std::move(auth);

if (auto dm_logger = _control.get_deep_mind_logger()) {
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
dm_logger->on_create_permission(p);
}
});
return perm;
}

void authorization_manager::modify_permission( const permission_object& permission, const authority& auth ) {
void authorization_manager::modify_permission( const permission_object& permission, const authority& auth, bool is_trx_transient ) {
for(const key_weight& k: auth.keys)
EOS_ASSERT(k.key.which() < _db.get<protocol_state_object>().num_supported_key_types, unactivated_key_type,
"Unactivated key type used when modifying permission");

_db.modify( permission, [&](permission_object& po) {
auto dm_logger = _control.get_deep_mind_logger();
auto dm_logger = _control.get_deep_mind_logger(is_trx_transient);

std::optional<permission_object> old_permission;
if (dm_logger) {
Expand All @@ -216,21 +218,21 @@ namespace eosio { namespace chain {
po.auth = auth;
po.last_updated = _control.pending_block_time();

if (auto dm_logger = _control.get_deep_mind_logger()) {
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
dm_logger->on_modify_permission(*old_permission, po);
}
});
}

void authorization_manager::remove_permission( const permission_object& permission ) {
void authorization_manager::remove_permission( const permission_object& permission, bool is_trx_transient ) {
const auto& index = _db.template get_index<permission_index, by_parent>();
auto range = index.equal_range(permission.id);
EOS_ASSERT( range.first == range.second, action_validate_exception,
"Cannot remove a permission which has children. Remove the children first.");

_db.get_mutable_index<permission_usage_index>().remove_object( permission.usage_id._id );

if (auto dm_logger = _control.get_deep_mind_logger()) {
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
dm_logger->on_remove_permission(permission);
}

Expand Down
Loading