摘要:區塊多線程簽名改動同步區塊時進行多線程簽名,過程中依然是單線程簽名。代碼解析塊簽名因為不適用多線程簽名,所以依舊沿用之前的簽名代碼,而同步則使用了新的部分。當大家比較關注的使用并沒有得到改善,因為多線程簽名無法應該在生產區塊上。
昨天早上,EOS 1.5.0 release 版本發布了。這次比較大改動點是在多線程簽名上面。它將同步區塊時的 block 簽名驗證和 trx 簽名驗證都使用多線程簽名驗證,來節省同步所需要的時間, 但是生產區塊所需要的成本是不變的,但為什么生產區塊成本不變呢。接下來介紹一下具體的改動。 區塊多線程簽名改動:同步區塊時進行多線程簽名, replay 過程中依然是單線程簽名。因為區塊同步時需要回滾 pending block 的 trx 操作, 這塊時間剛好可以用來并行處理簽名, 但 replay 的時候沒有這一步,即使用多線程簽名也無法節省時間,反而會讓主線程阻塞等待異步結果返回。 trx 多線程簽名改動:同步區塊以及 replay 過程都會進行多線程簽名, 因為有多個 trx 要執行,所以執行 trx 的時間可以供其他 trx 的簽名并行進行。 但生產區塊的時候無法使用,因為執行 BP 接受到一個 廣播的 trx 就立馬去執行了,執行完之后才回去接受下一個廣播 trx, 所以無法使用多線程簽名。代碼解析: 塊簽名:
因為 replay 不適用多線程簽名, 所以 replay 依舊沿用之前的簽名代碼, 而同步則使用了新的部分。
// producer_plugin.cpp 接受到廣播塊 void on_incoming_block(const signed_block_ptr& block) { // ... // start processing of block // 調用一個線程去對塊進行簽名驗證 auto bsf = chain.create_block_state_future( block ); // abort the pending block // 回滾掉 pending block 的執行 trx, 這段時間剛好可以用來并發執行區塊簽名驗證 chain.abort_block(); // ... } // controller.cpp std::future交易簽名create_block_state_future( const signed_block_ptr& b ) { //驗證區塊是否存在。 EOS_ASSERT( b, block_validate_exception, "null block" ); auto id = b->id(); // no reason for a block_state if fork_db already knows about block auto existing = fork_db.get_block( id ); EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) ); auto prev = fork_db.get_block( b->previous ); EOS_ASSERT( prev, unlinkable_block_exception, "unlinkable block ${id}", ("id", id)("previous", b->previous) ); // 進行多線程簽名 return async_thread_pool( [b, prev]() { const bool skip_validate_signee = false; return std::make_shared ( *prev, move( b ), skip_validate_signee ); } ); } void push_block( std::future & block_state_future ) { controller::block_status s = controller::block_status::complete; EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); auto reset_prod_light_validation = fc::make_scoped_exit([old_value=trusted_producer_light_validation, this]() { trusted_producer_light_validation = old_value; }); try { // 獲取驗證結果, 當區塊驗證失敗時會拋出異常,中止 push block block_state_ptr new_header_state = block_state_future.get(); auto& b = new_header_state->block; emit( self.pre_accepted_block, b ); fork_db.add( new_header_state, false ); if (conf.trusted_producers.count(b->producer)) { trusted_producer_light_validation = true; }; emit( self.accepted_block_header, new_header_state ); if ( read_mode != db_read_mode::IRREVERSIBLE ) { maybe_switch_forks( s ); } } FC_LOG_AND_RETHROW( ) }
從改動得知,apply_block 的時候才會啟動交易的多線程驗證簽名,而 bcast_transaction 則不會,因為并沒有多余的動作可以與驗證簽名并行。
void apply_block( const signed_block_ptr& b, controller::block_status s ) { try { try { EOS_ASSERT( b->block_extensions.size() == 0, block_validate_exception, "no supported extensions" ); auto producer_block_id = b->id(); start_block( b->timestamp, b->confirmed, s , producer_block_id); // 按順序啟動每個 trx 的多線程驗證簽名,生產對應公鑰 std::vector總結packed_transactions; packed_transactions.reserve( b->transactions.size() ); for( const auto& receipt : b->transactions ) { if( receipt.trx.contains ()) { auto& pt = receipt.trx.get (); auto mtrx = std::make_shared ( pt ); if( !self.skip_auth_check() ) { std::weak_ptr mtrx_wp = mtrx; mtrx->signing_keys_future = async_thread_pool( [chain_id = this->chain_id, mtrx_wp]() { auto mtrx = mtrx_wp.lock(); return mtrx ? std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id ) ) : std::make_pair( chain_id, decltype( mtrx->trx.get_signature_keys( chain_id ) ){} ); } ); } packed_transactions.emplace_back( std::move( mtrx ) ); } } // 執行 trx // ... commit_block(false); return; } catch ( const fc::exception& e ) { edump((e.to_detail_string())); abort_block(); throw; } } FC_CAPTURE_AND_RETHROW() } /// apply_block // trx 執行時獲取簽名返回的公鑰 const flat_set & recover_keys( const chain_id_type& chain_id ) { // Unlikely for more than one chain_id to be used in one nodeos instance if( !signing_keys || signing_keys->first != chain_id ) { if( signing_keys_future.valid() ) { // 獲取公鑰,如果未簽名完則阻塞等待簽名完畢 signing_keys = signing_keys_future.get(); if( signing_keys->first == chain_id ) { return signing_keys->second; } } // 當沒開啟多線程簽名時, 直接驗證生成對應公鑰 signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id )); } return signing_keys->second; }
從這次的改動可以看出主要優化的地方是節點同步區塊的速度, 因為開啟了多線程簽名,所以在 block 驗證以及 apply_block 時節省了一定 CPU 時間, 可供其他地方使用。 例如 EOS 現在是當線程的,所以當你進行 RPC 訪問的時候,如果涉及到數據提取,主線程的同步時會暫停的,等待你的操作結束, 這樣就會影響節點的同步,所以 get_table_rows API 才會限制 10 ms。 現在同步所需時間減少,降低了節點既要同步數據也要提供 RPC API 的壓力。
當大家比較關注的 CPU 使用并沒有得到改善, 因為多線程簽名無法應該在生產區塊上。所以在生產區塊時, trx 執行所需要的 CPU 時間并不會減少,也就是 CPU 資源的使用并沒有得到改善。
EOS 開發的小伙伴有技術問題可以進群討論喲
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/24469.html
摘要:最后一步付款和比特幣以及以太坊不一樣的是,在創建賬戶是有成本的,這也就是為什么我們需要一個賬戶才能創建賬戶的原因找個人來買單。 之前我們學習了如何編譯EOS程序,以及如何連接到EOS主網,接下來我們要談一談大家最關心的,如何創建自己的EOS賬戶。 摘要 這篇我們會學習如何創建錢包、秘鑰對、主網賬戶,向大家介紹一些實用工具。最重要的是,我們會學習到在EOS里,公鑰和賬戶到底有什么區別。 ...
摘要:適用于最新的前言最近在研究的,但是由于官方文檔的不夠詳盡,新建賬號這一個操作就折騰了一個多星期。皇天不負有心人,終于調通了新建賬號,代幣轉賬也輕松解決。 適用于最新的 EOS Dawn 4.0/4.1 前言 最近在研究 EOS 的 RPC API,但是由于官方API文檔的不夠詳盡,新建賬號(new account)這一個操作就折騰了一個多星期。皇天不負有心人,終于調通了新建賬號,代幣轉...
摘要:的跟其他區塊鏈項目是類似的,都是一個基本功能本地儲存密鑰,僅此而已。公網上線后,一定要將存有密鑰的加密,并且將文件單獨備份好。字面意思是賬戶,但我覺得有個概念更適合法人。代幣就是由持有的。對于權限,則需要列表里至少兩個賬戶的授權才能行使。 如果你曾經嘗試在本地運行 EOS 測試節點,會發現編譯、運行并不是特別復雜,但官方教程里兩個概念很容易把人搞暈: Account(賬戶) 和 Wal...
摘要:,調用函數,重置標志位為,計時器關閉,打印關閉提示日志。設定計時器的異步定時任務,任務體直接調用函數,對函數的返回值進行處理,如果有報錯信息一般是服務中止則調用函數關閉插件。 原文鏈接:醒者呆的博客園,https://www.cnblogs.com/Evswa... 本文內容本屬于《【精解】EOS TPS 多維實測》的內容,但由于在編寫時篇幅過長,所以我決定將這一部分單獨成文撰寫,以便...
閱讀 2575·2021-10-11 10:58
閱讀 1156·2021-09-29 09:34
閱讀 1513·2021-09-26 09:46
閱讀 3837·2021-09-22 15:31
閱讀 740·2019-08-30 15:54
閱讀 1462·2019-08-30 13:20
閱讀 1257·2019-08-30 13:13
閱讀 1491·2019-08-26 13:52