bitshares研究系列【ref_block_xxx】
在Bitshares交易后,会返回类似以下数据,知道与块hash相关,但一直没仔细看看是怎么来的,现在来看一看。
ref_block_xxx
{
"ref_block_num": 37095,
"ref_block_prefix": 836926066,
}
transaction.cpp
void transaction::set_reference_block( const block_id_type& reference_block )
{
ref_block_num = block_header::num_from_id(reference_block) & block_ref_mask;
ref_block_prefix = block_header::prefix_from_id(reference_block);
}
其中block_ref_mask定义为:
#define block_ref_mask 0xffff
block.cpp
uint64_t block_header::num_from_id(const block_id_type& id)
{
return fc::endian_reverse_u64((uint64_t(id._hash[0]) <<32) | id._hash[2]);
}
uint32_t block_header::prefix_from_id(const block_id_type& id)
{
return id._hash[1];
}
num_from_id()得到的就是块号。
block_id_type是fc::ripemd160类型,内部有一个长度为5的uint32数组,在ripemd160.hpp中定义如下:
uint32_t _hash[5];
也就是说ref_block_num是_hash[0]左移32位或上_hash[2]得到一个64位数,再将这个64位数按字节反转,取其低16位,而ref_block_prefix是_hash[1]。
set_reference_block()会在请求交易时调用,传入参数为动态全局中的"head_block_id",如下:
auto dyn_props = get_dynamic_global_properties();
tx.set_reference_block( dyn_props.head_block_id );
再取一下动态全局参数看一下:
get_dynamic_global_properties
{
"id": "2.1.0",
"head_block_number": 29397356,
"head_block_id": "01c0916cd1681322df0b066b4e8d0602d69e9f5e",
"time": "2018-08-07T06:07:09",
"current_witness": "1.6.20",
"next_maintenance_time": "2018-08-07T07:00:00",
"last_budget_time": "2018-08-07T06:00:00",
"witness_budget": 106000000,
"accounts_registered_this_interval": 2,
"recently_missed_count": 0,
"current_aslot": 29552903,
"recent_slots_filled": "340282366920938463463374607431768211455",
"dynamic_flags": 0,
"last_irreversible_block_num": 29397338
}
最前面那个json数据中,"ref_block_prefix"为836926066,就是块号29397223的“block_id”,能看出来吗?而"ref_block_num"就是块号29397223的低16位。
"block_id": "01c090e7727ae231faa00c9411415c5cd8f00775",
用在哪
在_apply_transaction()中,对ref_block_num有检查,如下:
if( BOOST_LIKELY(head_block_num() > 0) )
{
if( !(skip & skip_tapos_check) )
{
const auto& tapos_block_summary = block_summary_id_type( trx.ref_block_num )(*this);
//Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
FC_ASSERT( trx.ref_block_prefix == block_header::prefix_from_id(tapos_block_summary.block_id));
}
fc::time_point_sec now = head_block_time();
FC_ASSERT( trx.expiration <= now + chain_parameters.maximum_time_until_expiration, "",
("trx.expiration",trx.expiration)("now",now)("max_til_exp",chain_parameters.maximum_time_until_expiration));
FC_ASSERT( now <= trx.expiration, "", ("now",now)("trx.exp",trx.expiration) );
}
以上代码会从db中根据交易的ref_block_num找到对应的块,并检查ref_block_prefix是否一致。
再看看定义和建立summary的函数:
typedef object_id< implementation_ids, impl_block_summary_object_type, block_summary_object> block_summary_id_type;
void database::create_block_summary(const signed_block& next_block)
{
block_summary_id_type sid(next_block.block_num() & block_ref_mask );
modify( sid(*this), [&](block_summary_object& p) {
p.block_id = next_block.id();
});
}
而create_block_summary()函数也会在_apply_block()中调用,也就是说内存db中只需要保存最近的65535个块数据,也就是2天多的块数据,对交易来说应该是足够了。
Leave bitshares研究系列【ref_block_xxx】 to:
Read more #bitshares posts
Best Posts From 老鱼
We have not curated any of chaimyu's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.