eos交易同步过程和区块生产过程源码分析
交易同步過程
1 通過命令cleos調(diào)用 cleos transfer ${from_account} ${to_account} ${quantity} 發(fā)起交易
2 eos調(diào)用chain_plugin 的push_transaction,內(nèi)部調(diào)用注冊好的方法。
| 1 | app().get_method<incoming::methods::transaction_async>(); |
?
代碼截圖如下
在producer_plugin插件的plugin_initialize函數(shù)中提前注冊了incoming::methods::transaction_async。
所以實際調(diào)用了producer_plugin_impl的on_incoming_transaction_async(trx, persist_until_expired, next )函數(shù),
傳遞的參數(shù)分別是pretty_input,true,和一個lambda匿名函數(shù)
| 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中調(diào)用controller的 push_transaction,并執(zhí)行trx。
將交易插入_pending_incoming_transactions中
接下來調(diào)用了controller的push_transaction函數(shù)
4 controller的push_transaction函數(shù)中發(fā)送消息accepted_transaction,而目前常用的網(wǎng)絡(luò)插件為bnet_plugin,net_plugin目前已作為備用,
由于在bnet_plugin的startup函數(shù)中綁定了消息回調(diào)函數(shù)
| 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表達(dá)式綁定起來,所以當(dāng)controller發(fā)送信號accepted_transaction就會調(diào)用這個lambda表達(dá)式傳遞參數(shù),從而調(diào)用bnet_plugin_impl中on_accepted_transaction函數(shù)。
5 bnet_plugin_impl通過on_accepted_transaction將消息廣播到其他節(jié)點
| 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 其他節(jié)點收到消息后,進(jìn)入on處理流程,發(fā)送transction消息
bnet_plugin處理消息函數(shù)
transaction消息處理
通過
| 1 | app().get_channel<incoming::channels::transaction>().publish(p); |
?
發(fā)送transaction消息。
7 producer_plugin綁定了消息處理的回調(diào)函數(shù)
收到消息后,調(diào)用on_incoming_transaction_async,調(diào)用controller的 push_transaction,并執(zhí)行trx。
以上就是eos交易同步過程。
區(qū)塊生產(chǎn)過程
整體的區(qū)塊生產(chǎn)流程
1 檢查自己是否是生產(chǎn)者,一個生產(chǎn)者500ms出一次塊,共出12次之后切換生產(chǎn)者。
2 對上次確認(rèn)的區(qū)塊到本次的區(qū)塊做BFT簽名,涉及函數(shù)set_confirmed和maybe_promote_pending,具體可以參看controller中start_block函數(shù)
3 等待一個出塊周期500ms
4 計算action的merkle root
5 計算transaction的merkle root
6 對區(qū)塊簽名
7 提交區(qū)塊到DB
8 遞歸調(diào)用schedule_production_loop
區(qū)塊同步過程
1 參考區(qū)塊生產(chǎn)過程,producer_plugin循環(huán)生產(chǎn)區(qū)塊,先start_block處理BFT簽名并確定不可逆的區(qū)塊數(shù),之后produce_block調(diào)用controller
2 controller使用finalize_block計算merkle root,使用commit_block提交到fork database中,fork db會依據(jù)1中計算的不可逆區(qū)塊數(shù),將不可逆的區(qū)塊刪除,并發(fā)送irreversible消息,controller綁定了該消息處理的回調(diào)函數(shù)
| 1 2 3 | fork_db.irreversible.connect( [&]( auto b ) { on_irreversible(b); }); |
?
3 controller收到消息后,調(diào)用on_irreversible處理發(fā)送irreversible_block消息。bnet注冊了該消息處理的回調(diào)函數(shù)
| 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 收到消息后,調(diào)用on_irreversible_block處理。并廣播給其他節(jié)點。
5 controller發(fā)送accepted_block_header和accepted_block消息。
6 producer_plugin收到消息后, 調(diào)用on_block,calc_dpos_last_irreversible計算不可逆塊。
7 bnet_plugin/net_plugin 收到之后廣播到其他節(jié)點。
8 其他節(jié)點的bnet_plugin/net_plugin收到P2P消息后,發(fā)送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消息后調(diào)用controller的push_block函數(shù)
10 Controller調(diào)用apply_block判斷如果新收到的block比原有的鏈長,則切換到新鏈上
11 Controller調(diào)用finalize_block計算merkle root,使用commit_block提交到DB
以上就是區(qū)塊同步過程。
感謝關(guān)注我的公眾號
轉(zhuǎn)載于:https://www.cnblogs.com/secondtonone1/p/10338918.html
總結(jié)
以上是生活随笔為你收集整理的eos交易同步过程和区块生产过程源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: webpack中跨域请求proxy代理(
- 下一篇: 最新版安全狗打狗棒法