摘要:在每个交易中,我们都会看到和这个参数有什么作用呢。先讲下它的大致作用,再来对代码进行分析。这是白皮书对这个参数的作用描述他是用来防止有不包含区块引用的交易被重放到某个分叉上,这样能避免不是该分叉的区块被添加到该分叉。
在每个 trx 交易中,我们都会看到 ref_block_num 和 ref_block_prefix, 这2个参数有什么作用呢。
先讲下它的大致作用,再来对代码进行分析。
这是白皮书对这2个参数的作用描述
Transaction as Proof of Stake (TaPoS) The EOS.IO software requires every transaction to include part of the hash of a recent block header. This hash serves two purposes: 1. prevents a replay of a transaction on forks that do not include the referenced block; and 2. signals the network that a particular user and their stake are on a specific fork. Over time all users end up directly confirming the blockchain which makes it difficult to forge counterfeit chains as the counterfeit would not be able to migrate transactions from the legitimate chain. 1. 他是用来防止有不包含区块引用的交易被重放到某个分叉上, 这样能避免不是该分叉的区块被添加到该分叉。 2. 告诉用户该块是在哪个分支上面。
这样做有什么作用呢?
假设现在有2个用户 A 和 B, B 叫 A 说你转 2 个 EOS 给我, 我就送你 100 个 LIVE,A 说好啊。 然后 A 就转 2 个 EOS 给 B 了, 这个时候 A 的区块 a 还不是不可逆状态, 如果此时 B 转给 A 100 个 LIVE, 要是 区块 a 被回滚掉了怎么办,那么 B 就白白给了 A 100 个 LIVE 了。 这时候 ref-block 的作用就体现了,如果区块 a 被回滚了,那么 B 转给 A 100 个 LIVE 的区块 b 也会被丢弃掉。 所以 当区块 b ref-block 是 区块 a 的时候,只有 区块 a 被成功打包了, 区块 b 才会被成功打包。
所以很显然, 这两个参数是为了让链更稳固,也让用户交易更安全。
先看下 transaction_header 对这两个字段的描述。
struct transaction_header { // ... // 可以指定 head_block_num - 0xffff ~ head_block_num 之间的块。 uint16_t ref_block_num = 0U; ///< specifies a block num in the last 2^16 blocks. // block_id 的按 32 bits分割的第二个部分,也就是 block_id._hash[1]; uint32_t ref_block_prefix = 0UL; ///< specifies the lower 32 bits of the blockid at // ... };
再来看下该参数如何被验证。
// 在 trx 初始化的时候便回去验证 void transaction_context::init_for_input_trx( uint64_t packed_trx_unprunable_size, uint64_t packed_trx_prunable_size, uint32_t num_signatures, bool skip_recording ) { //... if (!control.skip_trx_checks()) { control.validate_expiration(trx); control.validate_tapos(trx); control.validate_referenced_accounts(trx); } //... } void controller::validate_tapos( const transaction& trx )const { try { const auto& tapos_block_summary = db().get((uint16_t)trx.ref_block_num); //Verify TaPoS block summary has correct ID prefix, and that this block"s time is not past the expiration EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception, "Transaction"s reference block did not match. Is this transaction from a different fork?", ("tapos_summary", tapos_block_summary)); } FC_CAPTURE_AND_RETHROW() } bool transaction_header::verify_reference_block( const block_id_type& reference_block )const { return ref_block_num == (decltype(ref_block_num))fc::endian_reverse_u32(reference_block._hash[0]) && ref_block_prefix == (decltype(ref_block_prefix))reference_block._hash[1]; }
从 block_summary_object 获取的 block 数据拿来跟 ref-block 的, 很奇怪为什么不直接用 get_block 那种方式取 block 的信息呢? 这样不用维护多一个多索引容器,而且还能获取全部的 block 。 来看看 block_summary_object 是如何创建和维护的。
// libraries/chain/include/eosio/chain/block_summary_object.hpp class block_summary_object : public chainbase::object{ OBJECT_CTOR(block_summary_object) id_type id; block_id_type block_id; }; struct by_block_id; using block_summary_multi_index = chainbase::shared_multi_index_container< block_summary_object, indexed_by< ordered_unique , BOOST_MULTI_INDEX_MEMBER(block_summary_object, block_summary_object::id_type, id)> // ordered_unique , BOOST_MULTI_INDEX_MEMBER(block_summary_object, block_id_type, block_id)> > >; // 创建了 id 从 0 ~ 65535 的数据 void contoller_impl::initialize_database() { // Initialize block summary index for (int i = 0; i < 0x10000; i++) db.create ([&](block_summary_object&) {}); // ... } // 每次添加新的区块的时候都回去更新 block_summary_object 的 索引表 void contoller_impl::finalize_block() { // ... auto p = pending->_pending_block_state; p->id = p->header.id(); create_block_summary(p->id); } FC_CAPTURE_AND_RETHROW() } void create_block_summary(const block_id_type& id) { auto block_num = block_header::num_from_id(id); // 从这里可以看出 block_summary_object 的 id 永远都是 0 ~ 65535。也就是说它只维护 head_block_num - 0xffff ~ head_block_num 的块, 你 ref-block 只能是这个区间的块, 如果 ref 更早的 block 就会验证出错。 auto sid = block_num & 0xffff; db.modify( db.get (sid), [&](block_summary_object& bso ) { bso.block_id = id; }); }
cleos 在 push transaction 的时候默认的 ref-block 是取 last_irreversible_block ,当head_block_num 跟 lib_num 相差超出 0xffff 个块的时候就会出现该错误:
Error 3040007: Invalid Reference Block
Ensure that the reference block exist in the blockchain!
Error Details:
Transaction"s reference block did not match. Is this transaction from a different fork?
如果你的私链出现问题,检查你链上有没 2/3 个 BP 在出块,如果没有则是因为没确认块,导致 head_block 和 lib 之间超过了 0xffff 个块而导致该错误。
结论: ref-block 的主要作用从白皮书可以看出,它是为了建立一条难以造假的链, 因为其他链违法从 合法链链直接迁移交易,只能添加交易。每个 block 都会 ref-block 前面的数据, 你也无法直接 ref-block 的早期的块,因为只能 ref-block 只能是从 head_block_num - 0xffff ~ head_block_num, 像比特币,只要你算力足够,你从第一个块重新建造一条链都可以。 并且他告诉用户当前交易是在哪个分叉上, 这样用户可以根据交易需要在哪条分叉上成功来指定分叉, 也就是我们上面举的例子。
原文: https://eos.live/detail/17094
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/24390.html
摘要:以太坊背后的主要人物是。以太坊通过在区块链上引入智能合约,彻底改变了加密世界。以太坊使用名为以太坊虚拟机的虚拟机执行其智能合约。以太坊最终将利用协议转向权益证明。截至目前,以太坊在可扩展性方面都失败了。 不同的区块链智能合约和区块链技术现在风靡一时。越来越多的人出于某种原因试图进入这个神奇的世界。如果你是这项技术的新手并正在寻找基于区块链的开发平台的快速入门,那么本指南非常适合你。我们...
前言 未来的公司形态会不断地演化,去中心化,分布式,强化合作,适应变化,直到彻底地被网络化。终极公司的形式将会变得与生物体相同,无缝地集成到生态圈中,成为其中的一个环节。—— 凯文·凯利《失控》 小剧场 小二: 糖糖,我爱你哦~ 糖糖: 你骗人!男人的话能信母猪能上树。 小二: 我可以向全世界证明,我说的是真的~ 糖糖: 那你怎么证明啊~ 小二: 我可以用 区块链 写下 糖糖我爱你哦~...
摘要:在以太坊出现后,进入了第二阶段。以太坊可以被视作区块链世界类似于和的底层操作系统。通证经济的设计方向模式的组织,是天然的生态型组织。区块链时代的生态组织,大致可以分成这几种类型。 简介 区块链最重要的应用就是将实物价值或虚拟资产映射成链上Token,通过资产上链,实现跨地域、低成本的进行资产交易与转移,本质上是权益再分配,核心是提高激励性和效益。 很多人把Token译为代币,我更...
摘要:所以想要实现真正实用的智能合约平台,就要脱离比特币系统的架构,寻找新的系统组织形式。比特币和以太坊之所以设计了手续费机制,就是防止大量垃圾交易使得系统拥堵。 区块链系统中,去中心化程度与效率之间天然地存在矛盾关系。 如果区块链智能合约系统想追求类似比特币的去中心化程度,理论上效率就会大打折扣。现实也是这样的:比特币每秒钟只能处理7笔左右的交易,每一笔交易要用至少30分钟才能确认,这种效...
阅读 1822·2021-11-25 09:43
阅读 3652·2021-11-24 10:32
阅读 1039·2021-10-13 09:39
阅读 2267·2021-09-10 11:24
阅读 3308·2021-07-25 21:37
阅读 3447·2019-08-30 15:56
阅读 818·2019-08-30 15:44
阅读 1391·2019-08-30 13:18