bitshares研究系列【ref_block_xxx】

in #bitshares6 years ago

在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 的帖子,期待您能留言交流!