源代码解读 [EOS 源码分析] 23 - Action 的数据结构 & EOS 区块数据结构实例解析

Admin · 2019年12月21日 · 126 次阅读
本帖已被设为精华帖!

EOS 源码分析系列文章,由技术作者松果撰写。为帮助更多开发者了解,特获授权转载至此。感谢松果兄支持。

img

上一篇文章介绍了EOS中交易(Transaction)的数据结构,transaction数据结构的主要功能是保存Action列表,具有数据库事务的性质,内部包含的Action要么全部执行成功,要么全部执行失败。这篇文章来介绍Action的数据结构。

Action的数据结构

action

Action的数据结构定义在action.hpp(eos/libraries/chain/include/eosio/chain/action.hpp)中:

img

以下内容翻译自源码中的注释:

Action由一个actor执行,actor即账户,Action可以通过签名授权被显式地创建,也可以通过执行应用程序代码被隐式地创建;

Action遵循了React Flux的设计模式,Action被分发给action handlers,相当于React Flux中的Store。在EOS的上下文中,每个Action都被给由scope::name定义的handler,但默认的handler也可能将Action分发给任意数量的其他handler。任何应用程序(智能合约)都可以为scope::name编写一个handler,当且仅当此Action被分发到该应用程序时才会执行该handler。

每个Action都需要特定actor的权限许可(permission),actor可以定义任意数量的权限级别(permission levels)。在使用Action时声明actor和权限级别,应用程序(智能合约)在执行Action时会检查授权。

Action结构体包含如下成员变量:

1、account(账户名)

账户名即actor,实际是账户下的合约名,一般EOS合约使用同名账户进行部署。

account_name和下面的action_name、permission_name类型都是name类型的别名:

using account_name     = name;
using action_name      = name;
using permission_name  = name;

name类型可以实现uint64_t和string之间的类型转换。

2、name(Action名)

** **

3、authorization(权限集合)

authorization是一个权限级别(permission_level)的集合,permission_level的定义如下:

struct permission_level {
  account_name    actor;
  permission_name permission;
};

在调用Action时都会带上authorization,比如这条命令可以修改EOS账户的owner权限对应的密钥:

cleos -u https://api.eosnewyork.io push action eosio updateauth '["<account_name>","owner","",{"threshold":1,"keys":[{"key":"<public_key>","weight":1}],"accounts":[],"waits":[]}]' -p <account_name>@owner

参数-p @owner就是authorization,只有账户owner权限自己才有权修改。

4、data(Action数据)

bytes类型是一个别名:

using bytes               = vector<char>;

保存的是打包后的Action数据,action结构体中还定义了几个重载的构造函数和解包函数data_as

action_notice

action_notice继承自action,用于实现Action通知机制,通知其他EOS账户。

action_notice数据结构如下:

img

扩展了一个字段receiver,用来保存Action通知的接收者账户名。

一个典型的Action的数据结构如下:

img

EOS区块数据结构实例解析

上面的Action数据结构是通过如下命令获取的区块数据的例子中的一部分(主网此区块高度为76684894):

cleos -u https://api.eosnewyork.io get block 04921e5e35cee5df7df25e6ad01aeb0f611e764678c0ea60ecb5b7b61cbf3554

transactions在区块数据结构中的位置如下:

{
  "timestamp": "2019-08-30T04:47:09.000",
  "producer": "atticlabeosb",
  "confirmed": 0,
  "previous": "04921e5d88941da3a2db063249b1d9a937307acdadec65d3ef818a8cc202f7c0",
  "transaction_mroot": "777abdc1c2b33d2e7c1c8bcf98ae01afea46589ac88b7702638b8681f5e03cd1",
  "action_mroot": "30320fb5eefbe6422f2007d115a9323eecc6dc600523f95ae2494b7397abe9e3",
  "schedule_version": 1228,
  "new_producers": null,
  "header_extensions": [],
  "producer_signature": "SIG_K1_KgpXcM7aSM4KonHLjDwjP7fAePotMALzwTqC5D2VM3vP4LuJL2A31tDKEoxvV2rXf2NLUkN2LQTYQyWUBaZmGApsE7vywF",
  "transactions":[
    //交易列表
  ],
  "block_extensions": [],
  "id": "04921e5e35cee5df7df25e6ad01aeb0f611e764678c0ea60ecb5b7b61cbf3554",
  "block_num": 76684894,
  "ref_block_prefix": 1784607357
}

展开交易列表(transactions),具体的Transaction结构如下:

"transactions":[
  {
    "status": "executed",
    "cpu_usage_us": 100,
    "net_usage_words": 0,
    "trx": "102d2ddd17ccc8c41b77c202471d58ffc408e595d65f2be5fac7f788d84a1b22"
  },{
    "status": "executed",
    "cpu_usage_us": 219,
    "net_usage_words": 0,
    "trx": "d51cf4f4c5f6e5fad5350b35a9bad0a03c7d5504c8702c1feffd528c47055ddb"
  },
  //...
  {
    "status": "executed",
    "cpu_usage_us": 176,
    "net_usage_words": 15,
    "trx": {
      "id": "6247f81856e6926357858d02c793465958c7103eb2b118c540fea52a808d9d9a",
      "signatures": [
        "SIG_K1_KVjhcqScvPuoXaDhVXCYkpG84XAV47554M2CmoBmL7uZxrQGoJrB3vvnM8R9V7mWcJvCBwVbCFpnkRFHJjVp3tLrv6s9Uy"
      ],
      "compression": "none",
      "packed_context_free_data": "",
      "context_free_data": [],
      "packed_trx": "6aaa685d5c1edb2da4300000000001d01572096315d3540000001e221dbda901a0b0a60d6315d35400000000a8ed32321870b4c172d8fce66b010000000000000004454f530000000000",
      "transaction": {
        "expiration": "2019-08-30T04:47:38",
        "ref_block_num": 7772,
        "ref_block_prefix": 816066011,
        "max_net_usage_words": 0,
        "max_cpu_usage_ms": 0,
        "delay_sec": 0,
        "context_free_actions": [],
        "actions": [{
          "account": "endlessdicex",
          "name": "paylucky",
          "authorization": [{
            "actor": "endlesshouse",
            "permission": "active"
          }],
          "data": {
            "to": "hjnjtq3msaub",
            "quantity": "0.0001 EOS"
          },
          "hex_data": "70b4c172d8fce66b010000000000000004454f5300000000"
        }],
        "transaction_extensions": []
      }
    }
  }
],

每个Transaction对象在一个{ }中,使用的是上一篇文章中介绍的transaction_receipt数据结构,根据定义trx字段可以保存两种类型的数据:

fc::static_variant<transaction_id_type, packed_transaction> trx;

交易ID(transaction_id_type)打包后的交易(packed_transaction),这里的交易ID本质上就是交易的哈希值,类似的,区块ID也是区块的哈希值。

展开一个trx值为packed_transaction的交易数据:

"trx": {
  "id": "6247f81856e6926357858d02c793465958c7103eb2b118c540fea52a808d9d9a",
  "signatures": [
    "SIG_K1_KVjhcqScvPuoXaDhVXCYkpG84XAV47554M2CmoBmL7uZxrQGoJrB3vvnM8R9V7mWcJvCBwVbCFpnkRFHJjVp3tLrv6s9Uy"
  ],
  "compression": "none",
  "packed_context_free_data": "",
  "context_free_data": [],
  "packed_trx": "6aaa685d5c1edb2da4300000000001d01572096315d3540000001e221dbda901a0b0a60d6315d35400000000a8ed32321870b4c172d8fce66b010000000000000004454f530000000000",
  "transaction": {
    "expiration": "2019-08-30T04:47:38",
    "ref_block_num": 7772,
    "ref_block_prefix": 816066011,
    "max_net_usage_words": 0,
    "max_cpu_usage_ms": 0,
    "delay_sec": 0,
    "context_free_actions": [],
    "actions": [{
      "account": "endlessdicex",
      "name": "paylucky",
      "authorization": [{
        "actor": "endlesshouse",
        "permission": "active"
      }],
      "data": {
        "to": "hjnjtq3msaub",
        "quantity": "0.0001 EOS"
      },
      "hex_data": "70b4c172d8fce66b010000000000000004454f5300000000"
    }],
    "transaction_extensions": []
  }
}

trx的数据分为两部分,transaction以外的字段是交易的签名和打包信息,来自于packed_transaction类,它打包了signed_transaction类;

transaction字段是交易的原始数据,展开后如下:

"transaction": {
  "expiration": "2019-08-30T04:47:38",
  "ref_block_num": 7772,
  "ref_block_prefix": 816066011,
  "max_net_usage_words": 0,
  "max_cpu_usage_ms": 0,
  "delay_sec": 0,
  "context_free_actions": [],
  "actions": [{
    "account": "endlessdicex",
    "name": "paylucky",
    "authorization": [{
      "actor": "endlesshouse",
      "permission": "active"
    }],
    "data": {
      "to": "hjnjtq3msaub",
      "quantity": "0.0001 EOS"
    },
    "hex_data": "70b4c172d8fce66b010000000000000004454f5300000000"
  }],
  "transaction_extensions": []
}

其中前6个字段来自父类transaction_header,后3个字段来自子类transaction

这个例子中context_free_actions为空数组,actions字段保存了这笔交易中执行的Action,只有1个Action,展开它得到Action的数据结构:

{
  "account": "endlessdicex",
  "name": "paylucky",
  "authorization": [{
    "actor": "endlesshouse",
    "permission": "active"
  }],
  "data": {
    "to": "hjnjtq3msaub",
    "quantity": "0.0001 EOS"
  },
  "hex_data": "70b4c172d8fce66b010000000000000004454f5300000000"
}

相比于Action类的定义,增加了hex_data字段,它表示16进制的data,是Action数据生成的摘要。

从这个Action的结构看出是[email protected]权限调用endlessdicex::paylucky这个Action,传递的数据是:

{
  "to": "hjnjtq3msaub",
  "quantity": "0.0001 EOS"
}

可以还原出调用该Action的cleos命令:

cleos -u https://api.eosnewyork.io push action endlessdicex paylucky '["hjnjtq3msaub","0.0001 EOS"]' -p [email protected]

当然,我的本地keosd钱包里没有[email protected]权限对应的私钥,所以这条命令无法调用成功。

更多内容

币圈信息站开发目录

EOS开发系列目录

共收到 0 条回复
Admin 将本帖设为了精华贴 12月21日 17:49
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册