diff --git a/libraries/chain/authorization_manager.cpp b/libraries/chain/authorization_manager.cpp index a6eef5807b9794b6de5cff549f9bb15866b61821..5f7f4d659a9d54d8c1e03a741c8999f63bc87b7e 100644 --- a/libraries/chain/authorization_manager.cpp +++ b/libraries/chain/authorization_manager.cpp @@ -336,6 +336,9 @@ namespace eosio { namespace chain { fc::microseconds max_delay; + map permissions_to_satisfy; + // bool value indicates whether the delay encountered in the check should not contribute to max_delay. + for( const auto& act : actions ) { bool special_case = false; bool ignore_delay = false; @@ -383,19 +386,32 @@ namespace eosio { namespace chain { } } - //if( should_check_signatures() ) { - if( ignore_delay ) - checker.get_permission_visitor().pause_delay_tracking(); - EOS_ASSERT( checker.satisfied(declared_auth), tx_missing_sigs, - "transaction declares authority '${auth}', but does not have signatures for it.", - ("auth", declared_auth) ); - if( ignore_delay ) - checker.get_permission_visitor().resume_delay_tracking(); - //} + auto res = permissions_to_satisfy.emplace( declared_auth, ignore_delay ); + if( !res.second && res.first->second ) { // if the declared_auth was already in the map and without delay tracking specified + res.first->second = ignore_delay; + } } } - if( !allow_unused_keys ) { //&& should_check_signatures() ) { + // Now verify that all the declared authorizations are satisfied: + + // Although this can be made parallel (especially for input transactions) with the optimistic assumption that the + // CPU limit is not reached, because of the CPU limit the protocol must officially specify a sequential algorithm + // for checking the set of declared authorizations. + // The permission_levels are traversed in ascending order, which is: + // ascending order of the actor name with ties broken by ascending order of the permission name. + for( const auto& p : permissions_to_satisfy ) { + checktime( config::base_authority_checker_cpu_per_permission ); // TODO: this should eventually move into authority_checker instead + if( p.second ) + checker.get_permission_visitor().pause_delay_tracking(); + EOS_ASSERT( checker.satisfied(p.first), tx_missing_sigs, + "transaction declares authority '${auth}', but does not have signatures for it.", + ("auth", p.first) ); + if( p.second ) + checker.get_permission_visitor().resume_delay_tracking(); + } + + if( !allow_unused_keys ) { EOS_ASSERT( checker.all_keys_used(), tx_irrelevant_sig, "transaction bears irrelevant signatures from these keys: ${keys}", ("keys", checker.unused_keys()) ); diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 8566b6e6496ca2cde7546f61acdf66b62329b379..f4e7e1d667c52df9c13a5b3e92d9a781a38ff922 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -84,6 +84,7 @@ const static uint16_t default_max_auth_depth = 6; const static uint32_t default_max_gen_trx_count = 16; const static uint32_t base_check_authorization_cpu_per_authorization = 64; // TODO: is this reasonable? +const static uint32_t base_authority_checker_cpu_per_permission = 128; // TODO: is this reasonable? const static uint32_t resource_processing_cpu_overhead_per_billed_account = 256; // TODO: is this reasonable? const static uint32_t determine_payers_cpu_overhead_per_authorization = 64; // TODO: is this reasonable? const static uint32_t ram_usage_validation_overhead_per_account = 64; // TODO: is this reasonable?