亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

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

ernest.wang / 3603人閱讀

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

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

首先 read only 模式不能用于出塊節(jié)點(diǎn),所以我們以一個(gè)同步節(jié)點(diǎn)的立場(chǎng)來(lái)講述。
寫(xiě)一個(gè)持久化插件,我們必須要有數(shù)據(jù)源,也就是這幾個(gè)信號(hào),我們從這里獲取數(shù)據(jù),這里使用的是觀察者模式,每當(dāng)信號(hào)源有新數(shù)據(jù) emit 的時(shí)候就會(huì)調(diào)用我們定義的函數(shù),具體觀察者模式的實(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)重復(fù)的會(huì)是 accepted_transaction 和 applied_transaction 這個(gè)信號(hào)源,所以我們重點(diǎn)介紹它。

我們會(huì)在 controller.push_transaction 發(fā)現(xiàn)這兩個(gè)函數(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 才會(huì)導(dǎo)致這2個(gè)信號(hào) duplicate。

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

trx 是通過(guò)什么來(lái)廣播的呢, 塊廣播以及交易廣播, 那我們從這入手。

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

// 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) {
   // 相當(dāng)于往該節(jié)點(diǎn) push transaction
   my->incoming_transaction_async_method(std::make_shared(trx), false, std::forward(next));
}

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

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

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

      // 多線(xiàn)程簽名

      // ...

      transaction_trace_ptr trace;

      size_t packed_idx = 0;
      // 執(zhí)行塊上的交易,更新該節(jié)點(diǎn)的狀態(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 也找到啦。

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

解決問(wèn)題
問(wèn)題找到了,接下來(lái)解決問(wèn)題。

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

交易廣播有 2 個(gè)途徑一個(gè)是接受鏈上的交易傳播, 一個(gè)是通過(guò) chain_api_plugin 的 push_transaction API 推送,所以禁掉這兩個(gè)就可以了。沒(méi)錯(cuò), 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 );
}

嗯,問(wèn)題來(lái)了,如何開(kāi)啟 read only 模式呢。

很簡(jiǎn)單,在config.ini 加上read-mode = read-only 即可。

總結(jié):

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

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

轉(zhuǎn)載請(qǐng)注明來(lái)源:https://eos.live/detail/18718

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/24489.html

相關(guān)文章

  • EOS源碼解析 使用多線(xiàn)程從簽名生成對(duì)應(yīng)公鑰

    摘要:區(qū)塊多線(xiàn)程簽名改動(dòng)同步區(qū)塊時(shí)進(jìn)行多線(xiàn)程簽名,過(guò)程中依然是單線(xiàn)程簽名。代碼解析塊簽名因?yàn)椴贿m用多線(xiàn)程簽名,所以依舊沿用之前的簽名代碼,而同步則使用了新的部分。當(dāng)大家比較關(guān)注的使用并沒(méi)有得到改善,因?yàn)槎嗑€(xiàn)程簽名無(wú)法應(yīng)該在生產(chǎn)區(qū)塊上。 昨天早上,EOS 1.5.0 release 版本發(fā)布了。這次比較大改動(dòng)點(diǎn)是在多線(xiàn)程簽名上面。它將同步區(qū)塊時(shí)的 block 簽名驗(yàn)證和 trx 簽名驗(yàn)證都使用...

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

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

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

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

    diabloneo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<