https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/eosio_contract.cpp#L301
void apply_eosio_linkauth(apply_context& context) {
// context.require_write_lock( config::eosio_auth_scope );
auto requirement = context.act.data_as<linkauth>();
try {
EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty");
context.require_authorization(requirement.account); // only here to mark the single authority on this action as used
auto& db = context.db;
const auto *account = db.find<account_object, by_name>(requirement.account);
EOS_ASSERT(account != nullptr, account_query_exception,
"Failed to retrieve account: ${account}", ("account", requirement.account)); // Redundant?
const auto *code = db.find<account_object, by_name>(requirement.code);
EOS_ASSERT(code != nullptr, account_query_exception,
"Failed to retrieve code for account: ${account}", ("account", requirement.code));
if( requirement.requirement != config::eosio_any_name ) {
const auto *permission = db.find<permission_object, by_name>(requirement.requirement);
EOS_ASSERT(permission != nullptr, permission_query_exception,
"Failed to retrieve permission: ${permission}", ("permission", requirement.requirement));
}
auto link_key = boost::make_tuple(requirement.account, requirement.code, requirement.type);
auto link = db.find<permission_link_object, by_action_name>(link_key);
if( link ) {
EOS_ASSERT(link->required_permission != requirement.requirement, action_validate_exception,
"Attempting to update required authority, but new requirement is same as old");
db.modify(*link, [requirement = requirement.requirement](permission_link_object& link) {
link.required_permission = requirement;
});
} else {
const auto& l = db.create<permission_link_object>([&requirement](permission_link_object& link) {
link.account = requirement.account;
link.code = requirement.code;
link.message_type = requirement.type;
link.required_permission = requirement.requirement;
});
context.add_ram_usage(
l.account,
(int64_t)(config::billable_size_v<permission_link_object>)
);
}
} FC_CAPTURE_AND_RETHROW((requirement))
}
void apply_eosio_unlinkauth(apply_context& context) {
// context.require_write_lock( config::eosio_auth_scope );
auto& db = context.db;
auto unlink = context.act.data_as<unlinkauth>();
context.require_authorization(unlink.account); // only here to mark the single authority on this action as used
auto link_key = boost::make_tuple(unlink.account, unlink.code, unlink.type);
auto link = db.find<permission_link_object, by_action_name>(link_key);
EOS_ASSERT(link != nullptr, action_validate_exception, "Attempting to unlink authority, but no link found");
context.add_ram_usage(
link->account,
-(int64_t)(config::billable_size_v<permission_link_object>)
);
db.remove(*link);
}
auto link_key = boost::make_tuple(requirement.account, requirement.code, requirement.type);
auto link = db.find<permission_link_object, by_action_name>(link_key);
父级可以把自己已有的action执行权限link给子级,同一子级只能有一个权限有同一action执行权限,赋值给同一级其他的,会把原先的删除掉。如果子级有某个action执行权限,那父级也有。如果子级unlink了某一action执行权限,将从此级追溯到顶父级active或者owner,顶父级之前的此action执行权限都会删除掉(因为active和owner为特殊账户,不会被删除)。
因为account,code,type
三个值加起来是查询索引,所以只有一条记录,记录着当前action执行权限link到哪个子权限了,并且子级有的话,父级就有。
新创建的权限,没link的话,没有任何action执行权限。