eos交易同步过程和区块生产过程源码分析
交易同步過程
1 通過命令cleos調用 cleos transfer ${from_account} ${to_account} ${quantity} 發起交易
2 eos調用chain_plugin 的push_transaction,內部調用注冊好的方法。
| 1 | app().get_method<incoming::methods::transaction_async>(); |
?
代碼截圖如下
在producer_plugin插件的plugin_initialize函數中提前注冊了incoming::methods::transaction_async。
所以實際調用了producer_plugin_impl的on_incoming_transaction_async(trx, persist_until_expired, next )函數,
傳遞的參數分別是pretty_input,true,和一個lambda匿名函數
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | app().get_method<incoming::methods::transaction_async>()(pretty_input, true, [this, next](const fc::static_variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void{ if (result.contains<fc::exception_ptr>()) { next(result.get<fc::exception_ptr>()); } else { auto trx_trace_ptr = result.get<transaction_trace_ptr>(); try { chain::transaction_id_type id = trx_trace_ptr->id; fc::variant output; try { output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer_max_time ); } catch( chain::abi_exception& ) { output = *trx_trace_ptr; } next(read_write::push_transaction_results{id, output}); } CATCH_AND_CALL(next); } }); |
?
3 在producer_plugin_impl的on_incoming_transaction_async中調用controller的 push_transaction,并執行trx。
將交易插入_pending_incoming_transactions中
接下來調用了controller的push_transaction函數
4 controller的push_transaction函數中發送消息accepted_transaction,而目前常用的網絡插件為bnet_plugin,net_plugin目前已作為備用,
由于在bnet_plugin的startup函數中綁定了消息回調函數
| 1 2 3 4 | my->_on_appled_trx_handle = app().get_channel<channels::accepted_transaction>() .subscribe( [this]( transaction_metadata_ptr t ){ my->on_accepted_transaction(t); }); |
?
通過app().get_channel將channels::accepted_transaction信號和lambda表達式綁定起來,所以當controller發送信號accepted_transaction就會調用這個lambda表達式傳遞參數,從而調用bnet_plugin_impl中on_accepted_transaction函數。
5 bnet_plugin_impl通過on_accepted_transaction將消息廣播到其他節點
| 1 2 3 4 | void on_accepted_transaction( transaction_metadata_ptr trx ) { if( trx->implicit || trx->scheduled ) return; for_each_session( [trx]( auto ses ){ ses->on_accepted_transaction( trx ); } ); } |
?
6 其他節點收到消息后,進入on處理流程,發送transction消息
bnet_plugin處理消息函數
transaction消息處理
通過
| 1 | app().get_channel<incoming::channels::transaction>().publish(p); |
?
發送transaction消息。
7 producer_plugin綁定了消息處理的回調函數
收到消息后,調用on_incoming_transaction_async,調用controller的 push_transaction,并執行trx。
以上就是eos交易同步過程。
區塊生產過程
整體的區塊生產流程
1 檢查自己是否是生產者,一個生產者500ms出一次塊,共出12次之后切換生產者。
2 對上次確認的區塊到本次的區塊做BFT簽名,涉及函數set_confirmed和maybe_promote_pending,具體可以參看controller中start_block函數
3 等待一個出塊周期500ms
4 計算action的merkle root
5 計算transaction的merkle root
6 對區塊簽名
7 提交區塊到DB
8 遞歸調用schedule_production_loop
區塊同步過程
1 參考區塊生產過程,producer_plugin循環生產區塊,先start_block處理BFT簽名并確定不可逆的區塊數,之后produce_block調用controller
2 controller使用finalize_block計算merkle root,使用commit_block提交到fork database中,fork db會依據1中計算的不可逆區塊數,將不可逆的區塊刪除,并發送irreversible消息,controller綁定了該消息處理的回調函數
| 1 2 3 | fork_db.irreversible.connect( [&]( auto b ) { on_irreversible(b); }); |
?
3 controller收到消息后,調用on_irreversible處理發送irreversible_block消息。bnet注冊了該消息處理的回調函數
| 1 2 3 4 | my->_on_irb_handle = app().get_channel<channels::irreversible_block>() .subscribe( [this]( block_state_ptr s ){ my->on_irreversible_block(s); }); |
?
4 bnet_plugin 收到消息后,調用on_irreversible_block處理。并廣播給其他節點。
5 controller發送accepted_block_header和accepted_block消息。
6 producer_plugin收到消息后, 調用on_block,calc_dpos_last_irreversible計算不可逆塊。
7 bnet_plugin/net_plugin 收到之后廣播到其他節點。
8 其他節點的bnet_plugin/net_plugin收到P2P消息后,發送block消息
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void on( const signed_block_ptr& b ) { peer_ilog(this, "received signed_block_ptr"); if (!b) { peer_elog(this, "bad signed_block_ptr : null pointer"); EOS_THROW(block_validate_exception, "bad block" ); } status( "received block " + std::to_string(b->block_num()) ); //ilog( "recv block ${n}", ("n", b->block_num()) ); auto id = b->id(); mark_block_status( id, true, true ); app().get_channel<incoming::channels::block>().publish(b); mark_block_transactions_known_by_peer( b ); } |
?
9 Producer_plugin收到block消息后調用controller的push_block函數
10 Controller調用apply_block判斷如果新收到的block比原有的鏈長,則切換到新鏈上
11 Controller調用finalize_block計算merkle root,使用commit_block提交到DB
以上就是區塊同步過程。
感謝關注我的公眾號
轉載于:https://www.cnblogs.com/secondtonone1/p/10338918.html
總結
以上是生活随笔為你收集整理的eos交易同步过程和区块生产过程源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: webpack中跨域请求proxy代理(
- 下一篇: 最新版安全狗打狗棒法