2019-04-29

作者: BTCwalker | 来源:发表于2019-04-29 14:53 被阅读0次

EOCS 最低资源保障机制

 为满足普通用户日常的转账等基本需求,无需再为较少的初始资源抵押担心无法使用链上功能。EOCS可以通过链的参数来调整分配给每个用户免费的资源额度,相当于EOCS链上的最低资源保障机制。

系统合约中最低资源保障代码

----------------------------------------------------------------------------------

void system_contract::setmrs( int64_t cpu_us, int64_t net_bytes, int64_t ram_bytes){

require_auth(_self);

set_minimum_resource_security(ram_bytes, net_bytes, cpu_us);

}

其中privileged_api::set_minimum_resource_security是主链提供的供智能合约调用的接口,该函数参数很简单,分别为要设置的cpu,net,和ram的资源,privileged_api::get_resource_limits为获取账户资源状态的接口。函数在头文件eosiolib/privileged.h中声明。

----------------------------------------------------------------------------------

下面为set_minimum_resource_security函数的实现

void set_minimum_resource_security(int64_t ram_bytes, int64_t net_bytes, int64_t cpu_us) {

   EOS_ASSERT(cpu_us >= 0, wasm_execution_error, "cpu_us must be >= 0");

   EOS_ASSERT(net_bytes >= 0, wasm_execution_error, "net_bytes must be >= 0");

   EOS_ASSERT(ram_bytes >= 0, wasm_execution_error, "ram_bytes must be >= 0");

   auto& resource_limits = context.control.get_mutable_resource_limits_manager();

   int64_t x, y, current_ram_bytes;

   resource_limits.get_mrs_parameters(current_ram_bytes, x, y);

   EOS_ASSERT(ram_bytes >= current_ram_bytes, wasm_execution_error,

           "ram_bytes cannot be reduced, current_ram_bytes: '${current_ram_bytes}', set_ram_bytes: '${set_ram_bytes}'",

              ("current_ram_bytes", current_ram_bytes)("set_ram_bytes", ram_bytes));

   resource_limits.set_mrs_parameters(ram_bytes, net_bytes, cpu_us);

}

----------------------------------------------------------------------------------

函数中通过resource_limits_manager::get_mrs_parameters()和

resource_limits_manager::set_mrs_parameters()分别去获取和设置最低资源保障

最低资源保障定义在resource_limits_config_object类中

class resource_limits_config_object : public chainbase::object<resource_limits_config_object_type, resource_limits_config_object> {

   OBJECT_CTOR(resource_limits_config_object);

   id_type id;

   …

   …

   …

   // Minimal Resource Security (MRS)

   int64_t mrs_cpu_us = config::default_mrs_cpu_us;// 200 microseconds

   int64_t mrs_net_bytes = config::default_mrs_net_bytes;// 10 KB

   int64_t mrs_ram_bytes = config::default_mrs_ram_bytes;// 0 KB

};

----------------------------------------------------------------------------------

设置了最低资源保障后可以通过privileged_api::get_resource_limits->resource_limits_manager::get_account_limits查询

//所以返回的账户资源是否加上最低资源保障根据includes_mrs_ram

void resource_limits_manager::get_account_limits( const account_name& account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight, bool includes_mrs_ram ) const {

   const auto* pending_buo = _db.find<resource_limits_object,by_owner>( boost::make_tuple(true, account) );

   const auto& config = _db.get<resource_limits_config_object>();

   if (pending_buo) {

      ram_bytes  = pending_buo->ram_bytes;

      net_weight = pending_buo->net_weight;

      cpu_weight = pending_buo->cpu_weight;

   } else {

      const auto& buo = _db.get<resource_limits_object,by_owner>( boost::make_tuple( false, account ) );

      ram_bytes  = buo.ram_bytes;

      net_weight = buo.net_weight;

      cpu_weight = buo.cpu_weight;

   }

   if (includes_mrs_ram) {

      ram_bytes += config.mrs_ram_bytes;

   }

}

----------------------------------------------------------------------------------

CPU和NET通过抵押EOC获得,每个账户所能获得的资源为:系统总资源* 抵押代币/ 总的抵押代币+ 最低资源保障

// 获取账户当前可用的虚拟CPU

int64_t resource_limits_manager::get_account_cpu_limit( const account_name& name, bool elastic ) const {

   auto arl = get_account_cpu_limit_ex(name, elastic);

   return arl.available;

}

----------------------------------------------------------------------------------

// 获取账户的虚拟CPU限制

account_resource_limit resource_limits_manager::get_account_cpu_limit_ex( const account_name& name, bool elastic) const {

   const auto& state = _db.get<resource_limits_state_object>();

   const auto& usage = _db.get<resource_usage_object, by_owner>(name);

   const auto& config = _db.get<resource_limits_config_object>();

   int64_t cpu_weight, x, y;

   get_account_limits( name, x, y, cpu_weight );

   if( cpu_weight < 0 || state.total_cpu_weight == 0 ) {

      return { -1, -1, -1 };

   }

   account_resource_limit arl;

   uint128_t window_size = config.account_cpu_usage_average_window;

----------------------------------------------------------------------------------

// 计算窗口期(在这里为24h)内的虚拟计算能力

uint128_t virtual_cpu_capacity_in_window = (uint128_t)(elastic ? state.virtual_cpu_limit : config.cpu_limit_parameters.max) * window_size;

   uint128_t user_weight= (uint128_t)cpu_weight;

   uint128_t all_user_weight = (uint128_t)state.total_cpu_weight;

----------------------------------------------------------------------------------

// 每个账户所能获得的资源为:系统总资源* 抵押代币/ 总的抵押代币+ 最低资源保障cpu资源

  auto max_user_use_in_window = (virtual_cpu_capacity_in_window * user_weight) / all_user_weight + config.mrs_cpu_us;

   auto cpu_used_in_window  = impl::integer_divide_ceil((uint128_t)usage.cpu_usage.value_ex * window_size, (uint128_t)config::rate_limiting_precision);

   if( max_user_use_in_window <= cpu_used_in_window )

      arl.available = 0;

   else

      arl.available = impl::downgrade_cast<int64_t>(max_user_use_in_window - cpu_used_in_window);

   arl.used = impl::downgrade_cast<int64_t>(cpu_used_in_window);

   arl.max = impl::downgrade_cast<int64_t>(max_user_use_in_window);

   return arl;

}

----------------------------------------------------------------------------------

EOCS对CPU、NET和RAM资源进行统一管理,对系统可用资源和账户可用资源集中记账。

// 将交易消耗的CPU和NET资源计入账户,并且加到块消耗的CPU和NET资源内,通常在交易验证后调用

void resource_limits_manager::add_transaction_usage(const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t time_slot ) {

   const auto& state = _db.get<resource_limits_state_object>();

   const auto& config = _db.get<resource_limits_config_object>();

   for( const auto& a : accounts ) {

      const auto& usage = _db.get<resource_usage_object,by_owner>( a );

      int64_t unused;

      int64_t net_weight;

      int64_t cpu_weight;

      get_account_limits( a, unused, net_weight, cpu_weight );

      _db.modify( usage, [&]( auto& bu ){

          bu.net_usage.add( net_usage, time_slot, config.account_net_usage_average_window );

          bu.cpu_usage.add( cpu_usage, time_slot, config.account_cpu_usage_average_window );

      });

      if( cpu_weight >= 0 && state.total_cpu_weight > 0 ) {

         uint128_t window_size = config.account_cpu_usage_average_window;

         auto virtual_network_capacity_in_window = (uint128_t)state.virtual_cpu_limit * window_size;

         auto cpu_used_in_window= ((uint128_t)usage.cpu_usage.value_ex * window_size) / (uint128_t)config::rate_limiting_precision;

         uint128_t user_weight     = (uint128_t)cpu_weight;

         uint128_t all_user_weight = state.total_cpu_weight;

----------------------------------------------------------------------------------

 //此处每个账户所获得的资源需要加上最低资源保障

 auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight + config.mrs_cpu_us;

         EOS_ASSERT( cpu_used_in_window <= max_user_use_in_window,

                     tx_cpu_usage_exceeded,

                     "authorizing account '${n}' has insufficient cpu resources for this transaction",

                     ("n", name(a))

                     ("cpu_used_in_window",cpu_used_in_window)

                     ("max_user_use_in_window",max_user_use_in_window) );

      }

      if( net_weight >= 0 && state.total_net_weight > 0) {

         uint128_t window_size = config.account_net_usage_average_window;

         auto virtual_network_capacity_in_window = (uint128_t)state.virtual_net_limit * window_size;

         auto net_used_in_window= ((uint128_t)usage.net_usage.value_ex * window_size) / (uint128_t)config::rate_limiting_precision;

         uint128_t user_weight     = (uint128_t)net_weight;

         uint128_t all_user_weight = state.total_net_weight;

----------------------------------------------------------------------------------

        //此处每个账户所获得的资源需要加上最低资源保障

 auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight + config.mrs_net_bytes;

         EOS_ASSERT( net_used_in_window <= max_user_use_in_window,

                     tx_net_usage_exceeded,

                     "authorizing account '${n}' has insufficient net resources for this transaction",

                     ("n", name(a))

                     ("net_used_in_window",net_used_in_window)

                     ("max_user_use_in_window",max_user_use_in_window) );

      }

   }

   // account for this transaction in the block and do not exceed those limits either

   _db.modify(state, [&](resource_limits_state_object& rls){

      rls.pending_cpu_usage += cpu_usage;

      rls.pending_net_usage += net_usage;

   });

   EOS_ASSERT( state.pending_cpu_usage <= config.cpu_limit_parameters.max, block_resource_exhausted, "Block has insufficient cpu resources" );

   EOS_ASSERT( state.pending_net_usage <= config.net_limit_parameters.max, block_resource_exhausted, "Block has insufficient net resources" );

}

----------------------------------------------------------------------------------

以上即为EOCS最低资源保障代码分析,此处稍微提一下,EOS引入了虚拟资源,实现动态调节,virtual_block_cpu_limit和virtual_block_net_limit的总资源的初始值分别为block_cpu_limit和block_net_limit,也就是说,虚拟资源一开始等于实际资源,然后随着系统忙闲不断调整,最低值等于实际资源,最高值等于实际资源的1000倍。

详细细节,大家可以下载源码仔细参阅,本期小E为大家带来的EOCS 最低资源保障机制就介绍到这里,欢迎大家关注EOCS官方微信公众号及添加EOCS小秘书共同探讨交流更多技术。

EOCS官网:https://www.eocs.io

GitHub:https://github.com/eocschain

Reddit:https://www.reddit.com/user/eocschain

Twitter:https://twitter.com/eocschain

Telegram:https://t.me/eocschain

相关文章

网友评论

    本文标题:2019-04-29

    本文链接:https://www.haomeiwen.com/subject/uwuynqtx.html