成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

EOS 源碼解析 什么是 read only 模式

ernest.wang / 3537人閱讀

摘要:接下來我們來分析下為什么會出現(xiàn)這種情況,以及模式起到了什么作用。沒錯,模式的作用就是禁止途徑。模式不接受廣播交易接受交易,并執(zhí)行如果是模式即中斷嗯,問題來了,如何開啟模式呢。

??大家之前使用 mongodb_plugin 、mysql_plugin 或其他數(shù)據(jù)持久化插件的時候,可能會發(fā)現(xiàn) transaction 和 trace 的數(shù)據(jù)重復duplicate ( 多機環(huán)境下)。 在最初的時候只能在持久化的時候做去重處理,但 EOS 之后已經(jīng)推出了 read only 模式,可以避免數(shù)據(jù)出現(xiàn) duplicate 的情況, 但筆者發(fā)現(xiàn)很多人不知道有這種模式,也不清楚這種情況的發(fā)生由來。接下來我們來分析下為什么會出現(xiàn)這種情況,以及 read only 模式起到了什么作用。

首先 read only 模式不能用于出塊節(jié)點,所以我們以一個同步節(jié)點的立場來講述。
寫一個持久化插件,我們必須要有數(shù)據(jù)源,也就是這幾個信號,我們從這里獲取數(shù)據(jù),這里使用的是觀察者模式,每當信號源有新數(shù)據(jù) emit 的時候就會調(diào)用我們定義的函數(shù),具體觀察者模式的實現(xiàn)在這里就不描述了,參考 mongodb_plugin 代碼。
signal         pre_accepted_block;
signal          accepted_block_header;
signal          accepted_block;
signal          irreversible_block;
signal accepted_transaction;
signal    applied_transaction;
signal      accepted_confirmation;

出現(xiàn)重復的會是 accepted_transaction 和 applied_transaction 這個信號源,所以我們重點介紹它。

我們會在 controller.push_transaction 發(fā)現(xiàn)這兩個函數(shù)的觸發(fā)。

transaction_trace_ptr push_transaction( const transaction_metadata_ptr& trx,
                                        fc::time_point deadline,
                                        uint32_t billed_cpu_time_us,
                                        bool explicit_billed_cpu_time = false )
{
   // ...

         // call the accept signal but only once for this transaction
         if (!trx->accepted) {
            trx->accepted = true;
            emit( self.accepted_transaction, trx);
         }

         emit(self.applied_transaction, trace);

   // ...
} /// push_transaction

OK, 看到這一步我們就知道 push_transaction 執(zhí)行了 2 次同樣的 trx 才會導致這2個信號 duplicate。

為什么會執(zhí)行 2 次呢?

trx 是通過什么來廣播的呢, 塊廣播以及交易廣播, 那我們從這入手。

交易廣播
每個節(jié)點會接受全網(wǎng)上的交易,嘗試執(zhí)行, 如果成功,則他繼續(xù)向其他節(jié)點廣播這個交易

// net_plugin.cpp
void net_plugin_impl::handle_message( connection_ptr c, const packed_transaction &msg) {
   // ...

   // read only 模式不接受廣播交易
   if( cc.get_read_mode() == eosio::db_read_mode::READ_ONLY ) {
      fc_dlog(logger, "got a txn in read-only mode - dropping");
      return;
   }
   
   // ...

   // 接受交易, 并執(zhí)行 push  transaction
   spatcher->recv_transaction(c, tid);
   chain_plug->accept_transaction(msg, [=](const static_variant& result) {
      if (result.contains()) {
         peer_dlog(c, "bad packed_transaction : ${m}", ("m",result.get()->what()));
      } else {
         auto trace = result.get();
         if (!trace->except) {
            fc_dlog(logger, "chain accepted transaction");
            dispatcher->bcast_transaction(msg);
            return;
         }

         peer_elog(c, "bad packed_transaction : ${m}", ("m",trace->except->what()));
      }

      dispatcher->rejected_transaction(tid);
   });
}

// chain plugin.cpp
void chain_plugin::accept_transaction(const chain::packed_transaction& trx, next_function next) {
   // 相當于往該節(jié)點 push transaction
   my->incoming_transaction_async_method(std::make_shared(trx), false, std::forward(next));
}

第一次 push_transaction 的執(zhí)行找到啦。

塊廣播
接下來看塊廣播, 在網(wǎng)絡上廣播的交易,最終是會被出塊節(jié)點打包( 執(zhí)行失敗的例外),每個節(jié)點都要去同步塊, 接受一個打包好的區(qū)塊,執(zhí)行 apply_block 函數(shù)。

void apply_block( const signed_block_ptr& b, controller::block_status s ) { try {
   try {
      // ...

      // 多線程簽名

      // ...

      transaction_trace_ptr trace;

      size_t packed_idx = 0;
      // 執(zhí)行塊上的交易,更新該節(jié)點的狀態(tài)
      for( const auto& receipt : b->transactions ) {
         auto num_pending_receipts = pending->_pending_block_state->block->transactions.size();
         if( receipt.trx.contains() ) {
            trace = push_transaction( packed_transactions.at(packed_idx++), fc::time_point::maximum(), receipt.cpu_usage_us, true );
         } else if( receipt.trx.contains() ) {
            trace = push_scheduled_transaction( receipt.trx.get(), fc::time_point::maximum(), receipt.cpu_usage_us, true );
         } else {
            EOS_ASSERT( false, block_validate_exception, "encountered unexpected receipt type" );
         }

         // ...
      }

      //...
      return;
   } catch ( const fc::exception& e ) {
      edump((e.to_detail_string()));
      abort_block();
      throw;
   }
} FC_CAPTURE_AND_RETHROW() } /// apply_block

第二次執(zhí)行 push transaction 也找到啦。

也就是一個 trx 在傳播到該節(jié)點的時候會被執(zhí)行一次,trx 被打包后跟隨區(qū)塊到該節(jié)點又會被執(zhí)行一次, 這就造成 accepted_transaction 和 applied_transaction 這兩個信號重復,導致重復數(shù)據(jù)的產(chǎn)生。

解決問題
問題找到了,接下來解決問題。

出現(xiàn)兩次調(diào)用 push_transaction 的操作,那么肯定要禁掉其中一個,才會使信號只觸發(fā)一次,那同步區(qū)塊的步驟肯定不能禁掉, 塊廣播和交易廣播,我們只能選擇禁止交易廣播的執(zhí)行,所以為什么出塊節(jié)點不能用 read only 模式( ps: 交易廣播都被你禁掉了,我還怎么打包區(qū)塊???黑人問號臉)

交易廣播有 2 個途徑一個是接受鏈上的交易傳播, 一個是通過 chain_api_plugin 的 push_transaction API 推送,所以禁掉這兩個就可以了。沒錯, read only 模式的作用就是禁止 2 途徑。

// net_plugin.cpp
void net_plugin_impl::handle_message( connection_ptr c, const packed_transaction &msg) {
   // ...

   // read only 模式不接受廣播交易
   if( cc.get_read_mode() == eosio::db_read_mode::READ_ONLY ) {
      fc_dlog(logger, "got a txn in read-only mode - dropping");
      return;
   }
   
   // ...

   // 接受交易, 并執(zhí)行 push  transaction
   spatcher->recv_transaction(c, tid);
   chain_plug->accept_transaction(msg, [=](const static_variant& result) {
      if (result.contains()) {
         peer_dlog(c, "bad packed_transaction : ${m}", ("m",result.get()->what()));
      } else {
         auto trace = result.get();
         if (!trace->except) {
            fc_dlog(logger, "chain accepted transaction");
            dispatcher->bcast_transaction(msg);
            return;
         }

         peer_elog(c, "bad packed_transaction : ${m}", ("m",trace->except->what()));
      }

      dispatcher->rejected_transaction(tid);
   });
}

// controller.cpp
transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline, uint32_t billed_cpu_time_us ) {
   validate_db_available_size();
   // 如果是 read only 模式即中斷
   EOS_ASSERT( get_read_mode() != chain::db_read_mode::READ_ONLY, transaction_type_exception, "push transaction not allowed in read-only mode" );
   EOS_ASSERT( trx && !trx->implicit && !trx->scheduled, transaction_type_exception, "Implicit/Scheduled transaction not allowed" );
   return my->push_transaction(trx, deadline, billed_cpu_time_us, billed_cpu_time_us > 0 );
}

嗯,問題來了,如何開啟 read only 模式呢。

很簡單,在config.ini 加上read-mode = read-only 即可。

總結(jié):

accepted_transaction 和 applied_transaction 信號重復的原因在于 trx 被執(zhí)行了兩次,即塊廣播與交易廣播,所以禁止交易廣播即可, 但此時節(jié)點只供讀取數(shù)據(jù),不能寫入數(shù)據(jù)。所以如果節(jié)點要來提供 push_transaction 這個 http api 的話不能開啟此模式。
trx 通過交易廣播在非出塊節(jié)點執(zhí)行是為了驗證該 trx 是否能合法執(zhí)行,如果不能,則該節(jié)點不會向網(wǎng)絡傳播該交易
為什么單機模式不會出現(xiàn)信號重復,因為單機節(jié)點只有一個,不會出現(xiàn)塊傳播,只有交易傳播。
如果你要寫持久化插件,記得開啟 read only 模式,或者在持久化的時候去重。

有任何疑問或者想交流的朋友可以加 EOS LIVE 小助手,備注 eos開發(fā)者拉您進 EOS LIVE DAPP 開發(fā)者社區(qū)微信群哦。

轉(zhuǎn)載請注明來源:https://eos.live/detail/18718

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/24489.html

相關文章

  • EOS源碼解析 使用多線程從簽名生成對應公鑰

    摘要:區(qū)塊多線程簽名改動同步區(qū)塊時進行多線程簽名,過程中依然是單線程簽名。代碼解析塊簽名因為不適用多線程簽名,所以依舊沿用之前的簽名代碼,而同步則使用了新的部分。當大家比較關注的使用并沒有得到改善,因為多線程簽名無法應該在生產(chǎn)區(qū)塊上。 昨天早上,EOS 1.5.0 release 版本發(fā)布了。這次比較大改動點是在多線程簽名上面。它將同步區(qū)塊時的 block 簽名驗證和 trx 簽名驗證都使用...

    mist14 評論0 收藏0
  • EOS源碼解析 創(chuàng)建賬號的三種方式。

    摘要:第一種創(chuàng)建系統(tǒng)賬號的方式。的默認合約是來自源碼提前定義好的。具體的信息在,。判斷的合法性只有才能創(chuàng)建為前綴的賬號。第三種當部署合約時,創(chuàng)建賬號都必須使用該合約的的。值得一提的是用第三種方式創(chuàng)建時,第二種方式的也會執(zhí)行。 第一種:創(chuàng)建系統(tǒng)賬號eosio的方式。 直接調(diào)用create_native_account 方法直接進行創(chuàng)建。并將資源設置成無限。 void create_nat...

    Me_Kun 評論0 收藏0
  • EOS 源碼解析 區(qū)塊回滾對交易的影響

    摘要:在主網(wǎng)上玩耍的小伙伴們肯定遇到過區(qū)塊回滾導致自己的交易沒有上鏈。這種情況讓有些人誤以為區(qū)塊回滾會丟棄交易。其實區(qū)塊回滾并不是導致交易沒上鏈的主要原因,主要原因是交易過期了才導致交易被丟棄。源碼解析我們來看看區(qū)塊生產(chǎn)時是如何丟棄過期交易的。 ????在主網(wǎng)上玩耍的小伙伴們肯定遇到過區(qū)塊回滾導致自己的交易沒有上鏈。這種情況讓有些人誤以為區(qū)塊回滾會丟棄交易。 其實區(qū)塊回滾并不是導致交易沒上鏈...

    diabloneo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<