EOSIO source code analysis - account and authority system

What is an EOSIO account

The account is the basis for accessing EOSIO, which is equivalent to the user name account in the general system. Its account is established according to the following rules

static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";

The EOSIO account is a string that can be freely combined in strict accordance with the above letters, the maximum length is 13, and the two ends cannot be "." characters. There are several
default accounts in EOSIO, which are used by the system.

const static name system_account_name    {
    
     "eosio"_n };
const static name null_account_name      {
    
     "eosio.null"_n };
const static name producers_account_name {
    
     "eosio.prods"_n };

Notice:

  • Among them, eosio is a system super account, which is equivalent to an administrator. It is created on the founding node with the node startup. The public and private keys used for creation are also the public and private keys of the founding node.
  • For accounts created starting with eosio., the creator must be eosio, which is a private rule reserved by the system
  • The specific implementation logic can be seen in the name class

The role of ESOIO account

After understanding what is an EOSIO account, what role does it play in the entire system? Looking at the various functions of the entire system, the account can be summed up as follows:

  • Authentication of transaction authority
  • Authorization authentication of internal chain Action
  • Smart contract, the carrier of ABI
  • producer name

Data structure of account permissions

// 最基础的账户表,记录账户名,创建时间,还有ABI数据块
class account_object : public chainbase::object<account_object_type, account_object> {
    
    
   OBJECT_CTOR(account_object,(abi))

   id_type              id;
   account_name         name; //< name should not be changed within a chainbase modifier lambda
   block_timestamp_type creation_date;
   shared_blob          abi;
};

// 账户元数据表,记录关于账号易变信息,或者一些统计信息
class account_metadata_object : public chainbase::object<account_metadata_object_type, account_metadata_object>
{
    
    
   OBJECT_CTOR(account_metadata_object);
   enum class flags_fields : uint32_t {
    
    
      privileged = 1
   };

   id_type               id;
   account_name          name; //< name should not be changed within a chainbase modifier lambda
   uint64_t              recv_sequence = 0;
   uint64_t              auth_sequence = 0;
   uint64_t              code_sequence = 0;
   uint64_t              abi_sequence  = 0;
   digest_type           code_hash;
   time_point            last_code_update;
   uint32_t              flags = 0;
   uint8_t               vm_type = 0;
   uint8_t               vm_version = 0;
};

// 合约数据表,保存用户的部署的合约
class code_object : public chainbase::object<code_object_type, code_object> {
    
    
   OBJECT_CTOR(code_object, (code))

   id_type      id;
   digest_type  code_hash; //< code_hash should not be changed within a chainbase modifier lambda
   shared_blob  code;
   uint64_t     code_ref_count;
   uint32_t     first_block_used;
   uint8_t      vm_type = 0; //< vm_type should not be changed within a chainbase modifier lambda
   uint8_t      vm_version = 0; //< vm_version should not be changed within a chainbase modifier lambda
};

// 权限基础表
class permission_object : public chainbase::object<permission_object_type, permission_object> {
    
    
   OBJECT_CTOR(permission_object, (auth) )

   id_type                           id;
   permission_usage_object::id_type  usage_id;
   id_type                           parent; ///< parent permission
   account_name                      owner; ///< the account this permission belongs to (should not be changed within a chainbase modifier lambda)
   permission_name                   name; ///< human-readable name for the permission (should not be changed within a chainbase modifier lambda)
   time_point                        last_updated; ///< the last time this authority was updated
   shared_authority                  auth; ///< authority required to execute this permission
};

// 权限链接表,记录和action进行绑定关系
class permission_link_object : public chainbase::object<permission_link_object_type, permission_link_object> {
    
    
   OBJECT_CTOR(permission_link_object)

   id_type        id;
   /// The account which is defining its permission requirements
   account_name    account;
   /// The contract which account requires @ref required_permission to invoke
   account_name    code; /// TODO: rename to scope
   /// The message type which account requires @ref required_permission to invoke
   /// May be empty; if so, it sets a default @ref required_permission for all messages to @ref code
   action_name       message_type;
   /// The permission level which @ref account requires for the specified message types
   /// all of the above fields should not be changed within a chainbase modifier lambda
   permission_name required_permission;
};
/****************************************************************************
在EOSIO中,账户的权限是作为整个数据块进行存储的
在authority结构中,主要记录了一下核心数据
threshold:阈值,所有权限之权重值之和, 最后的比较值
keys:记录公钥与权重数值
accounts:记录管理账户与权重值,新创建的账户一般没有这个数值
waits:延迟执行相关权限
****************************************************************************/
struct permission_level {
    
    
   account_name    actor;
   permission_name permission;
};

struct permission_level_weight {
    
    
   permission_level  permission;
   weight_type       weight;
};

struct key_weight {
    
    
   public_key_type key;
   weight_type     weight;
};

struct authority {
    
    
   authority( public_key_type k, uint32_t delay_sec = 0 )
   :threshold(1),keys({
    
    {
    
    k,1}})
   {
    
    
      if( delay_sec > 0 ) {
    
    
         threshold = 2;
         waits.push_back(wait_weight{
    
    delay_sec, 1});
      }
   }

   authority( permission_level p, uint32_t delay_sec = 0 )
   :threshold(1),accounts({
    
    {
    
    p,1}})
   {
    
    
      if( delay_sec > 0 ) {
    
    
         threshold = 2;
         waits.push_back(wait_weight{
    
    delay_sec, 1});
      }
   }

   authority( uint32_t t, vector<key_weight> k, vector<permission_level_weight> p = {
    
    }, vector<wait_weight> w = {
    
    } )
   :threshold(t),keys(move(k)),accounts(move(p)),waits(move(w)){
    
    }
   authority(){
    
    }

   uint32_t                          threshold = 0;
   vector<key_weight>                keys;
   vector<permission_level_weight>   accounts;
   vector<wait_weight>               waits;
};

From the above code structure, the following conclusions can be drawn directly

  • The account table value records the core account name
  • Accounts and permissions are deeply bound, and the entire permission data is stored as an overall data block
  • The same permission can correspond to multiple key_weight, permission_level_weight, wait_weight, which can make the permission more flexible and expandable
  • The authority directly acts on a single account, and the control is more detailed
  • The authority data block exists together, and the access is fast, but at the same time it also brings troubles in operation and inconvenient query
  • code and abi are stored separately, because the query frequency of abi is much higher than that of code, which will be described in detail later

Operation of account authority

In EOSIO, the operation of account permissions is done in the system contract eosio_contract. The eosio_contract contract is built-in and deployed on the eosio account. It is the most basic and important contract in eosio. It is directly compiled and deployed in the node and cannot be updated.
The action list of eosio_contract is as follows

  • newaccount: Create an account. When creating an account, the owner and active permissions are created by default.
    The parameters attached to the action are as follows:

    struct newaccount {
          
          
       account_name                     creator;
       account_name                     name;
       authority                        owner;
       authority                        active;
    };
    
  • updateauth: authorization update

    struct updateauth {
          
          
       account_name                      account;
       permission_name                   permission;
       permission_name                   parent;
       authority                         auth;
    };
    
  • deleteauth: delete account permissions

    struct deleteauth {
          
          
       account_name                      account;
       permission_name                   permission;
    };
    
  • linkauth: Binding of permissions and contract actions

    struct linkauth {
          
          
       account_name                      account;
       account_name                      code;
       action_name                       type;
       permission_name                   requirement;
    };
    
  • unlinkauth: Contact the binding relationship between the contract and the action

    struct unlinkauth {
          
          
       account_name                      account;
       account_name                      code;
       action_name                       type;
    };
    
  • setcode: deploy contract

    struct setcode {
          
          
       account_name                     account;
       uint8_t                          vmtype = 0;
       uint8_t                          vmversion = 0;
       bytes                            code;
    };
    
  • setabi: Department ABI

    struct setabi {
          
          
       account_name                     account;
       bytes                            abi;
    };
    
  • canceldelay: cancel delay

    struct canceldelay {
          
          
       permission_level      canceling_auth;
       transaction_id_type   trx_id;
    };
    

About the command line of the permission account in cleos

We said earlier that the interfaces provided by eosio for external access are all http interfaces, and cleos is just an encapsulation of these interfaces. Generally, in our projects, http interfaces are directly used, but in the initial stage of system deployment, we still inevitably meet Use the cleos command line, of course, you develop a command line yourself. In addition, in the author's project, we have developed a java version of the command line tool, as well as a wallet. This is mainly for background and Android use, which is very convenient. .

For specific command usage rules, you can refer to here, EOSIO Command Line Encyclopedia

Summarize

Relatively speaking, in EOSIO, the code about permissions is relatively unified and centralized, and its functions are relatively independent. It can encapsulate independent modules, or create an independent service that is only responsible for CA-related business logic.
However, at the same time, we also observed that in the public chain, the design of permissions is very different from the permissions in general systems. Then we will ask

  • What are the benefits of such designed permissions? Is it easy to operate and access? If not, what aspects can be optimized?
  • In the permission data structure, what is the relationship between account and key? Is it a one-to-one relationship?
  • In the transaction, how is the authority identified, and how is it identified in the contract by extension?
  • We observed that the definition of permission-related tables inherits chainbase::object, and how is it stored?

postscript

The account authority is a relatively independent but difficult to understand functional module in EOSIO, especially some concepts it introduces, such as threshold, weight, multi-signature, link binding, and code authority must be kept in mind before it can Understand the process and principle of its authority verification.
Therefore, by understanding the relevant data structure of account permissions, we can better understand its authentication process.

Guess you like

Origin blog.csdn.net/whg1016/article/details/128669267