摘要:在每個交易中,我們都會看到和這個參數有什么作用呢。先講下它的大致作用,再來對代碼進行分析。這是白皮書對這個參數的作用描述他是用來防止有不包含區塊引用的交易被重放到某個分叉上,這樣能避免不是該分叉的區塊被添加到該分叉。
在每個 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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/24390.html
摘要:以太坊背后的主要人物是。以太坊通過在區塊鏈上引入智能合約,徹底改變了加密世界。以太坊使用名為以太坊虛擬機的虛擬機執行其智能合約。以太坊最終將利用協議轉向權益證明。截至目前,以太坊在可擴展性方面都失敗了。 不同的區塊鏈智能合約和區塊鏈技術現在風靡一時。越來越多的人出于某種原因試圖進入這個神奇的世界。如果你是這項技術的新手并正在尋找基于區塊鏈的開發平臺的快速入門,那么本指南非常適合你。我們...
前言 未來的公司形態會不斷地演化,去中心化,分布式,強化合作,適應變化,直到徹底地被網絡化。終極公司的形式將會變得與生物體相同,無縫地集成到生態圈中,成為其中的一個環節。—— 凱文·凱利《失控》 小劇場 小二: 糖糖,我愛你哦~ 糖糖: 你騙人!男人的話能信母豬能上樹。 小二: 我可以向全世界證明,我說的是真的~ 糖糖: 那你怎么證明啊~ 小二: 我可以用 區塊鏈 寫下 糖糖我愛你哦~...
摘要:在以太坊出現后,進入了第二階段。以太坊可以被視作區塊鏈世界類似于和的底層操作系統。通證經濟的設計方向模式的組織,是天然的生態型組織。區塊鏈時代的生態組織,大致可以分成這幾種類型。 簡介 ??區塊鏈最重要的應用就是將實物價值或虛擬資產映射成鏈上Token,通過資產上鏈,實現跨地域、低成本的進行資產交易與轉移,本質上是權益再分配,核心是提高激勵性和效益。??很多人把Token譯為代幣,我更...
摘要:所以想要實現真正實用的智能合約平臺,就要脫離比特幣系統的架構,尋找新的系統組織形式。比特幣和以太坊之所以設計了手續費機制,就是防止大量垃圾交易使得系統擁堵。 區塊鏈系統中,去中心化程度與效率之間天然地存在矛盾關系。 如果區塊鏈智能合約系統想追求類似比特幣的去中心化程度,理論上效率就會大打折扣。現實也是這樣的:比特幣每秒鐘只能處理7筆左右的交易,每一筆交易要用至少30分鐘才能確認,這種效...
閱讀 1846·2021-11-25 09:43
閱讀 3688·2021-11-24 10:32
閱讀 1076·2021-10-13 09:39
閱讀 2328·2021-09-10 11:24
閱讀 3344·2021-07-25 21:37
閱讀 3464·2019-08-30 15:56
閱讀 858·2019-08-30 15:44
閱讀 1448·2019-08-30 13:18