国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

ernest.wang / 3532人閱讀

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

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

首先 read only 模式不能用于出塊節點,所以我們以一個同步節點的立場來講述。
寫一個持久化插件,我們必須要有數據源,也就是這幾個信號,我們從這里獲取數據,這里使用的是觀察者模式,每當信號源有新數據 emit 的時候就會調用我們定義的函數,具體觀察者模式的實現在這里就不描述了,參考 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;

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

我們會在 controller.push_transaction 發現這兩個函數的觸發。

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 執行了 2 次同樣的 trx 才會導致這2個信號 duplicate。

為什么會執行 2 次呢?

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

交易廣播
每個節點會接受全網上的交易,嘗試執行, 如果成功,則他繼續向其他節點廣播這個交易

// 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;
   }
   
   // ...

   // 接受交易, 并執行 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) {
   // 相當于往該節點 push transaction
   my->incoming_transaction_async_method(std::make_shared(trx), false, std::forward(next));
}

第一次 push_transaction 的執行找到啦。

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

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

      // 多線程簽名

      // ...

      transaction_trace_ptr trace;

      size_t packed_idx = 0;
      // 執行塊上的交易,更新該節點的狀態
      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

第二次執行 push transaction 也找到啦。

也就是一個 trx 在傳播到該節點的時候會被執行一次,trx 被打包后跟隨區塊到該節點又會被執行一次, 這就造成 accepted_transaction 和 applied_transaction 這兩個信號重復,導致重復數據的產生。

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

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

交易廣播有 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;
   }
   
   // ...

   // 接受交易, 并執行 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 即可。

總結:

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

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

轉載請注明來源:https://eos.live/detail/18718

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/24489.html

相關文章

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

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

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

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

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

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

    diabloneo 評論0 收藏0

發表評論

0條評論

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