寂寞如花落,窗前更無聲,故園舊影跡難尋,倚看數(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)存。