在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天多的块数据,对交易来说应该是足够了。
感谢您阅读 @chaimyu 的帖子,期待您能留言交流!