区块链 + 大数据:EOS存储 (2)

action_mroot是始终有值的,哪怕transaction_mroot是0,这是因为出块本身也是一个action动作onblock,这个动作调用的是system合约的onblock函数。TODO:源码分析

/** * At the start of each block we notify the system contract with a transaction that passes in * the block header of the prior block (which is currently our head block) */ signed_transaction get_on_block_transaction() { action on_block_act; on_block_act.account = config::system_account_name; on_block_act.name = N(onblock); on_block_act.authorization = vector<permission_level>{{config::system_account_name, config::active_name}}; on_block_act.data = fc::raw::pack(self.head_block_header()); signed_transaction trx; trx.actions.emplace_back(std::move(on_block_act)); trx.set_reference_block(self.head_block_id()); trx.expiration = self.pending_block_time() + fc::microseconds(999'999); // Round up to nearest second to avoid appearing expired return trx; } context_free_actions

通过对eosio.null账户的nouce动作,可以将无签名的数据打包进入context_free_action字段,结果区块信息如下:

evsward@evsward-TM1701:~/work/src/github.com/eos/tutorials/bios-boot-tutorial$ cleos --wallet-url :6666 --url :8000 get block 440 { "timestamp": "2018-08-14T08:47:09.000", "producer": "eosio", "confirmed": 0, "previous": "000001b760e4a6610d122c5aa5d855aa49e29f3052ac3e40b9e1ef78e0f1fd02", "transaction_mroot": "32cb43abd7863f162f4d8f3ab9026623ea99d3f8261d2c8b4d8bf920ab97e3d1", "action_mroot": "09afeaf40d6988a14e9e92817d2ccf4023b280075c99f13782a6535ccc58cbb0", "schedule_version": 0, "new_producers": null, "header_extensions": [], "producer_signature": "SIG_K1_K2eFDzbxCg3hmQzpzPuLYmiesrciPmTHdeNsQDyFgcHUMFeMC3PntXTqiup5VuNmyb7qmH18FBdMuNKsc7jgCm1TSPFbaj", "transactions": [{ "status": "executed", "cpu_usage_us": 290, "net_usage_words": 16, "trx": { "id": "d74843749d1e255f13572b7a3b95af9ddd6df23d1d0ad19d88e1496091d4be2b", "signatures": [ "SIG_K1_KVzwg3QRH6ZmempNsvAxpPQa42hF4tDpV5cqwqo7EY4oSU7NMrEFwG7gdSDCnUHHhmH1EwtVAmV1z9bqtTvvQNSXiSgaWG" ], "compression": "none", "packed_context_free_data": "", "context_free_data": [], "packed_trx": "8497725bb601973ea96f0000000100408c7a02ea3055000000000085269d000706686168616861010082c95865ea3055000000000000806b010082c95865ea305500000000a8ed3232080000000000d08cf200", "transaction": { "expiration": "2018-08-14T08:49:08", "ref_block_num": 438, "ref_block_prefix": 1873362583, "max_net_usage_words": 0, "max_cpu_usage_ms": 0, "delay_sec": 0, "context_free_actions": [{ "account": "eosio.null", "name": "nonce", "authorization": [], "data": "06686168616861" } ], "actions": [{ "account": "eosiotesta1", "name": "hi", "authorization": [{ "actor": "eosiotesta1", "permission": "active" } ], "data": { "user": "yeah" }, "hex_data": "0000000000d08cf2" } ], "transaction_extensions": [] } } } ], "block_extensions": [], "id": "000001b8d299602b289a9194bd698476c5d39c5ad88235460908e9d43d04edc8", "block_num": 440, "ref_block_prefix": 2492570152 }

正常的actions的内容是hi智能合约的调用,而context_free_action中包含了无签名的data数据,是已做数字摘要后的形态。源码中的操作:

// lets also push a context free action, the multi chain test will then also include a context free action ("context_free_actions", fc::variants({ fc::mutable_variant_object() ("account", name(config::null_account_name)) ("name", "nonce") ("data", fc::raw::pack(v)) }) ); EOS的StateDB

我们来设想一个场景:

A账户转账给B账户100个SYS,如何查看A账户的余额?

对于不知道以上动作何时发生的我们来讲,我们要如何做呢:

首先是从头扫描区块内的交易,交易内的action,直到找到A账户被创建的action所对应的区块号。

从这个区块号开始继续扫描,要将所有A账户的转账,包括收入和支出的所有action记录下来并统计。

算出A的当前余额。

以上步骤很容易出错且繁琐,每一次的余额查询都要重复这些操作实在是毫无意义,因此StateDB就诞生了,这个库顾名思义就是用来存储状态数据的,如果有了StateDB,上面的场景的解决办法就是:

从A账户被第一次收入SYS开始,为A账户在StateDB中建立一个table,存储A账户的余额,每当A账户发生转账的action,都会同步更新StateDB中相关table中A账户的余额的值,当我们需要知道A账户的余额时,我们可以直接查找这个余额state即可。

测试用例

这里为大家提供一个测试方法,也是我的命令history:

cleos create key cleos wallet import 5JA9oDotJHoKnjUV6NrAMx4g5gWTCVCRLybTnG1XVU3EKGZZeNY cleos wallet import --private-key 5JA9oDotJHoKnjUV6NrAMx4g5gWTCVCRLybTnG1XVU3EKGZZeNY cleos wallet keys cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 cleos wallet keys cleos create account eosio usertesta1 EOS761KfjhYy3FSypZGG5hePrR8K2wzmw75JCDXgypKt2DLXZoZPW cleos create account eosio eosio.token EOS761KfjhYy3FSypZGG5hePrR8K2wzmw75JCDXgypKt2DLXZoZPW cleos set contract eosio.token work/src/github.com/eos/build/contracts/eosio.token/ cleos push action eosio.token create '["eosio","100000000.0000 SYS"]' cleos push action eosio.token issue cleos push action eosio.token issue '["usertesta1","10000000.0000 SYS"]' -p eosio.token cleos push action eosio.token issue '["usertesta1","10000000.0000 SYS"]' -p eosio cleos get currency balance eosio.token usertesta1 cleos get table eosio.token usertesta1 accounts cleos get table eosio.token eosio accounts

可以看到当我想获得usertesta1账户的余额时,是通过查询StateDB的table来获取的,而不是最开始的那种扫块的笨方法。

链式存储和StateDB存储的区别

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygxyf.html