进一步研究区块的id是如何生成的,以及如何通过id获得区块号。是在block_heade.cpp中定义:
namespace eosio { namespace chain { digest_type block_header::digest()const { return digest_type::hash(*this);// hash算法为sha256,然后使用fc::raw::pack打包获取结果 } uint32_t block_header::num_from_id(const block_id_type& id) { return fc::endian_reverse_u32(id._hash[0]);// 实际上是对区块id并入区块号的算法的逆向工程,获得区块号。 } // id的类型为block_id_type block_id_type block_header::id()const { // id不包括签名区块头属性,尤其是生产者签名除外。 block_id_type result = digest();//digest_type::hash(*this),this是id()的调用者。 result._hash[0] &= 0xffffffff00000000;//对结果进行位操作,并入一个十六进制头。 result._hash[0] += fc::endian_reverse_u32(block_num()); // 通过上一个区块id找到其区块号然后自增获得当前区块号。并入id数据成为其一部分。 return result; } } }get_block拼接好id、block_num、ref_block_prefix最后三个字段以后,返回的数据结构如下图所示:
注意与上面的get_block的实现区分,get_block_header_state是通过fetch_block_state_by_number或fetch_block_state_by_id函数获取到的是状态库中的区块对象,也就是说是可逆区块数据,而不是get_block通过fetch_block_by_number或fetch_block_by_id函数获取到的不可逆区块。
get_block_header_state获取到可逆区块以后,通过以下代码得到其区块头数据并返回。
这个功能的实现函数代码较长,但做的工作实际上并不复杂,可以采用从返回的account数据结构来逆向分析该功能的实现方法:
struct get_account_results { name account_name; // 账户名,入参的值。 uint32_t head_block_num = 0; // 头块号,controller的状态主库db获取 fc::time_point head_block_time; // 头块时间,controller的状态主库db获取 bool privileged = false; // 是否超级账户,默认false。controller的状态主库db获取账户的属性之一。 fc::time_point last_code_update; // 最后的code修改时间,例如给账户set contract的时间。controller的状态主库db获取账户的属性之一。 fc::time_point created; // 账户创建时间。controller的状态主库db获取账户的属性之一。 optional<asset> core_liquid_balance; // 主币的余额,在accounts状态表里查到的 int64_t ram_quota = 0; // 内存限额(资源相关部分有详细介绍),从controller的资源管理器获取 int64_t net_weight = 0; // 网络带宽资源权重,从controller的资源管理器获取 int64_t cpu_weight = 0; // cpu资源权重,从controller的资源管理器获取 account_resource_limit net_limit; // 网络带宽资源,包括已使用、剩余可用、总量。从controller的资源管理器获取 account_resource_limit cpu_limit; // cpu带宽资源,包括已使用、剩余可用、总量。从controller的资源管理器获取 int64_t ram_usage = 0; // 内存已使用量。从controller的资源管理器获取 vector<permission> permissions; // 账户的权限内容(账户多签名部分有详细介绍),在状态主库的表里查到的。 fc::variant total_resources; // 总资源量,包括网络、cpu、内存资源总量。在userres状态表里查到的 fc::variant self_delegated_bandwidth; // 自我抵押带宽。在delband状态表里查到的 fc::variant refund_request; // 退款请求。在refunds状态表里查到的 fc::variant voter_info; // 投票相关。在voters状态表里查到的 }; 5. 获取账户code信息 get_code注意该接口修改了源码,不支持返回wast数据了。因此在请求该接口的时候,要使用的参数如下:
{ "account_name": "eosio.token", "code_as_wasm": true }返回的数据将包括
该账户的名字。
code的hash值,先通过controller状态库查询到账户对象,然后将其code的data和size值做sha256哈希得到的值。
wasm的数据,就是完整的原始code的数据。