eos源碼解析(九):延時交易

寂寞如花落,窗前更無聲,故園舊影跡難尋,倚看數(shù)點殘紅,已是夢中人。
今天,來講講eos中一個有關(guān)于約定的故事。
有兩個問題:
1,transaction中的delay字段的含義是什么?
2,抵押交易的撤回,3天之后怎么就自動到賬了?

其實,以上兩個問題,本質(zhì)上是一個問題,下面是系統(tǒng)合約中創(chuàng)建延時交易的部分:

            eosio::transaction out;
            out.actions.emplace_back( permission_level{ from, N(active) }, _self, N(refund), from );
            out.delay_sec = refund_delay;
            cancel_deferred( from ); // TODO: Remove this line when replacing deferred trxs is fixed
            out.send( from, from, true );

可以看到:out.delay_sec = refund_delay; refund_delay的值為三天。三天之后,交易自動進行。
那么這個交易是在合約中創(chuàng)建的,要不要簽名什么的呢?
答案是,在合約中創(chuàng)建的交易不需要簽名,但會驗證權(quán)限:

   ......... 
  bool check_auth = false;
      for( const auto& act : trx.actions ) {
         if( act.account != receiver ) {
            check_auth = true;
            break;
         }
      }
      if( check_auth ) {
         control.get_authorization_manager()
                .check_authorization( trx.actions,
                                      {},
                                      {{receiver, config::eosio_code_name}},
                                      delay,
                                      std::bind(&transaction_context::checktime, &this->trx_context),
                                      false
                                    );
      }
   .........

上面的代碼的意思是:
1,如果是延時交易的執(zhí)行對象是自己,那么就不用驗證權(quán)限了。
2,如果延時交易的的執(zhí)行對象不是自己,那么就會提供自己的code權(quán)限。
3,上文中的"自己"是指的當前合約。

這里做一個延伸,“合約”與“賬戶”的區(qū)別。合約是一段代碼,賬戶是eos上的身份。合約不可以單獨存在與eos中,合約是一個賬戶對外提供的功能。多個賬戶可以部署同一份合約代碼。

然后,將交易放入數(shù)據(jù)庫里面:

   auto& d = control.db();
   if ( auto ptr = d.find<generated_transaction_object,by_sender_id>(boost::make_tuple(receiver, sender_id)) ) {
      EOS_ASSERT( replace_existing, deferred_tx_duplicate, "deferred transaction with the same sender_id and payer already exists" );

      // TODO: Remove the following subjective check when the deferred trx replacement RAM bug has been fixed with a hard fork.
      EOS_ASSERT( !control.is_producing_block(), subjective_block_production_exception,
                  "Replacing a deferred transaction is temporarily disabled." );

      // TODO: The logic of the next line needs to be incorporated into the next hard fork.
      // trx_context.add_ram_usage( ptr->payer, -(config::billable_size_v<generated_transaction_object> + ptr->packed_trx.size()) );

      db.modify<generated_transaction_object>( *ptr, [&]( auto& gtx ) {
            gtx.sender      = receiver;
            gtx.sender_id   = sender_id;
            gtx.payer       = payer;
            gtx.published   = control.pending_block_time();
            gtx.delay_until = gtx.published + delay;
            gtx.expiration  = gtx.delay_until + fc::seconds(control.get_global_properties().configuration.deferred_trx_expiration_window);

            trx_size = gtx.set( trx );
         });
   } else {
      d.create<generated_transaction_object>( [&]( auto& gtx ) {
            gtx.trx_id      = trx.id();
            gtx.sender      = receiver;
            gtx.sender_id   = sender_id;
            gtx.payer       = payer;
            gtx.published   = control.pending_block_time();
            gtx.delay_until = gtx.published + delay;
            gtx.expiration  = gtx.delay_until + fc::seconds(control.get_global_properties().configuration.deferred_trx_expiration_window);

            trx_size = gtx.set( trx );
         });
   }

在producer_plugin.cpp中,生產(chǎn)完區(qū)塊后
如果是生產(chǎn)節(jié)點,直接在producer_plugin.cpp中:

。。。。
//得到所有的延遲交易
auto scheduled_trxs = chain.get_scheduled_transactions();
。。。。
//提交延遲交易
auto trace = chain.push_scheduled_transaction(trx, deadline);
。。。。。
//    刪除延時交易在內(nèi)存里記錄
       remove_scheduled_transaction(gto);
。。。。
// 執(zhí)行transaction
      try {
         trx_context.init_for_deferred_trx( gtrx.published );
         trx_context.exec();
         trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful


         auto restore = make_block_restore_point();
// 回執(zhí)
         trace->receipt = push_receipt( gtrx.trx_id,
                                        transaction_receipt::executed,
                                        trx_context.billed_cpu_time_us,
                                        trace->net_usage );
。。。。。。

區(qū)塊中的交易是以receipt形式存在的

   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
                                            uint64_t cpu_usage_us, uint64_t net_usage ) {
      uint64_t net_usage_words = net_usage / 8;
      EOS_ASSERT( net_usage_words*8 == net_usage, transaction_exception, "net_usage is not divisible by 8" );
      pending->_pending_block_state->block->transactions.emplace_back( trx );
      transaction_receipt& r = pending->_pending_block_state->block->transactions.back();
      r.cpu_usage_us         = cpu_usage_us;
      r.net_usage_words      = net_usage_words;
      r.status               = status;
      return r;
   }

見證節(jié)點在接受一個區(qū)塊的時候,apply_block的時候?qū)鶕?jù)不同的回執(zhí)執(zhí)行不同的交易。

void apply_block( const signed_block_ptr& b, controller::block_status s ) { try {
      try {
         EOS_ASSERT( b->block_extensions.size() == 0, block_validate_exception, "no supported extensions" );
         start_block( b->timestamp, b->confirmed, s );

         transaction_trace_ptr trace;

         for( const auto& receipt : b->transactions ) {
            auto num_pending_receipts = pending->_pending_block_state->block->transactions.size();
            if( receipt.trx.contains<packed_transaction>() ) {
               auto& pt = receipt.trx.get<packed_transaction>();
               auto mtrx = std::make_shared<transaction_metadata>(pt);
               trace = push_transaction( mtrx, fc::time_point::maximum(), receipt.cpu_usage_us, true );
            } else if( receipt.trx.contains<transaction_id_type>() ) {
               trace = push_scheduled_transaction( receipt.trx.get<transaction_id_type>(), fc::time_point::maximum(), receipt.cpu_usage_us, true );
            } else {
               EOS_ASSERT( false, block_validate_exception, "encountered unexpected receipt type" );
            }
.......
.......

綜上,延遲交易發(fā)起后,會先判斷權(quán)限,如果權(quán)限驗證通過,則把交易存放在內(nèi)存里面,如果不通過,則直接拒絕,此外,net資源的使用也是在schedule_deferred_transaction函數(shù)中進行的,使用的是當前調(diào)用合約對象的內(nèi)存。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容