Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Implementation of Auth Caching #113
Browse files Browse the repository at this point in the history
  • Loading branch information
bytemaster committed Jul 31, 2017
1 parent 603e034 commit 9b2259d
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 12 deletions.
1 change: 1 addition & 0 deletions contracts/eoslib/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ typedef __int128 int128_t;
typedef unsigned char uint8_t;

typedef uint64_t AccountName;
typedef uint64_t PermissionName;
typedef uint64_t TokenName;
typedef uint64_t TableName;
typedef uint32_t Time;
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/chain_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,7 @@ uint32_t chain_controller::last_irreversible_block_num() const {

void chain_controller::initialize_indexes() {
_db.add_index<account_index>();
_db.add_index<auth_cache_index>();
_db.add_index<permission_index>();
_db.add_index<action_permission_index>();
_db.add_index<key_value_index>();
Expand Down
29 changes: 29 additions & 0 deletions libraries/chain/include/eos/chain/account_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,38 @@ namespace eos { namespace chain {
>
>;


class auth_cache_object : public chainbase::object<auth_cache_object_type, auth_cache_object> {
OBJECT_CTOR(auth_cache_object)

id_type id;
AccountName scope;
AccountName code;
AccountName auth;
PermissionName permission;
};

struct by_scope_code_auth_permission;
using auth_cache_index = chainbase::shared_multi_index_container<
auth_cache_object,
indexed_by<
ordered_unique<tag<by_id>, member<auth_cache_object, auth_cache_object::id_type, &auth_cache_object::id>>,
ordered_unique<tag<by_scope_code_auth_permission>,
composite_key< auth_cache_object,
member<auth_cache_object, AccountName, &auth_cache_object::scope>,
member<auth_cache_object, AccountName, &auth_cache_object::code>,
member<auth_cache_object, AccountName, &auth_cache_object::auth>,
member<auth_cache_object, PermissionName, &auth_cache_object::permission>
>
>
>
>;


} } // eos::chain

CHAINBASE_SET_INDEX_TYPE(eos::chain::account_object, eos::chain::account_index)
CHAINBASE_SET_INDEX_TYPE(eos::chain::auth_cache_object, eos::chain::auth_cache_index)

FC_REFLECT(chainbase::oid<eos::chain::account_object>, (_id))

Expand Down
26 changes: 16 additions & 10 deletions libraries/chain/include/eos/chain/message_handling_contexts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@ class message_validate_context {
TransactionAuthorizationChecker* authChecker)
:controller(control),db(d),trx(t),msg(m),code(c),authChecker(authChecker){}

/**
* @brief Require @ref account to have approved of this message
* @param account The account whose approval is required
*
* This method will check that @ref account is listed in the message's declared authorizations, and marks the
* authorization as used. Note that all authorizations on a message must be used, or the message is invalid.
*
* @throws tx_missing_auth If no sufficient permission was found
*/
void require_authorization(const types::AccountName& account);
void require_scope(const types::AccountName& account)const;

const chain_controller& controller;
Expand Down Expand Up @@ -91,6 +81,22 @@ class apply_context : public precondition_validate_context {
bool has_recipient( const types::AccountName& account )const;
void require_recipient(const types::AccountName& account);


/**
* @brief Require @ref account to have approved of this message
* @param account The account whose approval is required
*
* This method will check that @ref account is listed in the message's declared authorizations, and marks the
* authorization as used. Note that all authorizations on a message must be used, or the message is invalid.
*
* @throws tx_missing_auth If no sufficient permission was found
*/
void require_authorization( AccountName account);
void require_authorization( AccountName account, PermissionName level );
void cache_auth( AccountName scope, AccountName account, PermissionName level );
void load_auth( AccountName scope, AccountName account, PermissionName level );
void clear_auth( AccountName scope, AccountName account, PermissionName level );

std::deque<AccountName> notified;
std::deque<ProcessedTransaction> sync_transactions; ///< sync calls made
std::deque<GeneratedTransaction> async_transactions; ///< async calls requested
Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/include/eos/chain/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ namespace eos { namespace chain {
producer_votes_object_type, ///< Defined by native_contract library
producer_schedule_object_type, ///< Defined by native_contract library
proxy_vote_object_type, ///< Defined by native_contract library
auth_cache_object_type,
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
};

Expand Down Expand Up @@ -221,6 +222,7 @@ FC_REFLECT_ENUM(eos::chain::object_type,
(producer_votes_object_type)
(producer_schedule_object_type)
(proxy_vote_object_type)
(auth_cache_object_type)
(OBJECT_TYPE_COUNT)
)
FC_REFLECT( eos::chain::void_t, )
39 changes: 38 additions & 1 deletion libraries/chain/message_handling_contexts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,50 @@

namespace eos { namespace chain {

void message_validate_context::require_authorization(const types::AccountName& account) {
using types::AccountName;
using types::PermissionName;

void apply_context::require_authorization(AccountName account) {
#warning TODO: Look up the permission_object that account has specified to use for this message type
if (authChecker)
EOS_ASSERT(authChecker->requirePermission({account, "active"}), tx_missing_auth,
"Transaction does not declare required authority '${auth}'", ("auth", account));
}

void apply_context::require_authorization( AccountName account, PermissionName level ) {
require_authorization(account);

#warning TODO: assert that account/level is on the current message auths list which
}

void apply_context::load_auth( AccountName scope, types::AccountName account, types::PermissionName level ) {
require_scope( scope );
db.get<auth_cache_object,by_scope_code_auth_permission>( boost::make_tuple( scope, code, account, level ) );
}

void apply_context::cache_auth( AccountName scope, types::AccountName account, types::PermissionName level ) {
require_scope( scope );
require_authorization( account, level );

auto existing = mutable_db.find<auth_cache_object,by_scope_code_auth_permission>( boost::make_tuple( scope, code, account, level ) );
if( !existing ) {
mutable_db.create<auth_cache_object>( [&]( auto& ac ) {
ac.scope = scope;
ac.code = code;
ac.auth = account;
ac.permission = level;
});
}
}

void apply_context::clear_auth( AccountName scope, AccountName account, PermissionName level ) {
require_scope( scope );
auto existing = db.find<auth_cache_object,by_scope_code_auth_permission>( boost::make_tuple( scope, code, account, level ) );
if( existing ) {
mutable_db.remove( *existing );
}
}

void message_validate_context::require_scope(const types::AccountName& account)const {
auto itr = boost::find_if(trx.scope, [&account](const auto& scope) {
return scope == account;
Expand Down
19 changes: 18 additions & 1 deletion libraries/chain/wasm_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
}

int32_t load_i128i128_object( uint64_t scope, uint64_t code, uint64_t table, int32_t valueptr, int32_t valuelen, load_i128i128_fnc function ) {
/// TODO: this should be updated to use a template lambda rather than a function pointer

static const uint32_t keylen = 2*sizeof(uint128_t);

Expand All @@ -50,6 +51,7 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
valuelen -= keylen;
value += keylen;

/// we should just call a lambda here
auto res = (wasm.current_validate_context->*function)(
Name(scope), Name(code), Name(table),
primary, secondary, value, valuelen
Expand All @@ -58,6 +60,21 @@ DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
if(res > 0) res += keylen;
return res;
}

DEFINE_INTRINSIC_FUNCTION3(env,cache_auth,cache_auth,none,i64,scope,i64,account,i64,level) {
auto& wasm = wasm_interface::get();
wasm.current_apply_context->cache_auth(scope,account,level);
}

DEFINE_INTRINSIC_FUNCTION3(env,load_auth,cache_auth,none,i64,scope,i64,account,i64,level) {
auto& wasm = wasm_interface::get();
wasm.current_apply_context->load_auth(scope,account,level);
}
DEFINE_INTRINSIC_FUNCTION3(env,clear_auth,cache_auth,none,i64,scope,i64,account,i64,level) {
auto& wasm = wasm_interface::get();
wasm.current_apply_context->clear_auth(scope,account,level);
}

DEFINE_INTRINSIC_FUNCTION3(env, assert_sha256,assert_sha256,none,i32,dataptr,i32,datalen,i32,hash) {
FC_ASSERT( datalen > 0 );

Expand Down Expand Up @@ -168,7 +185,7 @@ DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) {
}

DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) {
wasm_interface::get().current_validate_context->require_authorization( Name(account) );
wasm_interface::get().current_apply_context->require_authorization( Name(account) );
}

DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
Expand Down

0 comments on commit 9b2259d

Please sign in to comment.