您正在查看: Surou 发布的文章

Transaction exceeded the current CPU usage limit imposed on the transaction

最近链发送交易过大时容易发生一下错误

{
    "message": "Internal Service Error",
    "code": "500",
    "error": {
        "code": "3080004",
        "name": "tx_cpu_usage_exceeded",
        "what": "Transaction exceeded the current CPU usage limit imposed on the transaction",
        "details": [{
            "message": "transaction was executing for too long",
            "file": "transaction_context.cpp",
            "line_number": 488,
            "method": "checktime"
        }, {
            "message": "pending console output: ",
            "file": "apply_context.cpp",
            "line_number": 113,
            "method": "exec_one"
        }]
    }
}

根据错误信息,定位源代码位置 (github

由于now > _deadline并且 deadline_exception_code == tx_cpu_usage_exceeded::code_value 走到此断言逻辑
倒推到函数调用位置(github

checktime(); // Fail early if deadline has already been exceeded

提示信息为:如果已超过截止日期,则提早失败
继续反推代码
由于(github)交易组装时trx.max_cpu_usage_ms固定设置的0。所以,判断逻辑出自(github

// Possibly lower objective_duration_limit to the maximum cpu usage a transaction is allowed to be billed
if( cfg.max_transaction_cpu_usage <= objective_duration_limit.count() ) {
    objective_duration_limit = fc::microseconds(cfg.max_transaction_cpu_usage);
    billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
    _deadline = start + objective_duration_limit;
}
auto& rl = control.get_mutable_resource_limits_manager();
objective_duration_limit = fc::microseconds( rl.get_block_cpu_limit() );
_deadline = start + objective_duration_limit;
if(now > _deadline) {
    // 报异常
}

get_mutable_resource_limits_manager(github

resource_limits_manager&         controller::get_mutable_resource_limits_manager()
{
   return my->resource_limits;
}

get_block_cpu_limit(github

uint64_t resource_limits_manager::get_block_cpu_limit() const {
   const auto& state = _db.get<resource_limits_state_object>();
   const auto& config = _db.get<resource_limits_config_object>();
   return config.cpu_limit_parameters.max - state.pending_cpu_usage;
}

跟进停止

发现是由于合约中使用了std::vector<std::string> 持续存储大量数据,导致单次CPU运算执行耗时持续增长。

结论

当合约中Table单条记录中,如果使用vector不要存储过多数据,以及数据结构过于复杂的struct
如有对应需求,可以拆分子表,然后使用子表记录id索引对应。

WSL tail -f 命令失效

tail -f命令可以查看文件更新的记录,但是在wsl中,可能无法正常工作。

经查找发现,Linux是通过inotify来获取文件变动的,但是不知道是bug还是什么原因,感知不到文件变动,造成此问题。

解决方案:

tail -f ---disable-inotify info.log

转载自:http://www.txllive.top/?p=30

cleos查询账户RAM总购量与实际购买不一致

cleos get account

通过cleos 查询账户RAM余额

cleos -u http://127.0.0.1:8888 get account zer41iyhahwp
...
memory:
     quota:     9.366 KiB    used:     3.078 KiB

但实际创建账户时,RAM购买量为8192byte

cleos get table

通过查询用户资源表

cleos -u http://127.0.0.1:8888 get table bitconch zer41iyhahwp userres
$ cleos -u http://127.0.0.1:8888 get table eosio zer41iyhahwp userres
{
  "rows": [{
      "owner": "zer41iyhahwp",
      "net_weight": "10.00000000 EOS",
      "cpu_weight": "10.00000000 EOS",
      "ram_bytes": 8191
    }
  ],
  "more": false
}

ram_bytes的数据与创建时RAM数据基本(所差1byte是因为,购买RAM通过Bancor估价代币购买,会与实际少许误差)一致。那cleos查出的数据差距在哪?下面跟下系统合约源代码

系统合约源码

查看RAM购买后,设置资源的位置(跳转GitHub)

set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu );

发现设置资源的位置加上附加的ram_gift_bytes

查看ram_gift_bytes具体数值(跳转github

static constexpr int64_t  ram_gift_bytes        = 1400;

所以,查询账户RAM比实际购买多的部分为合约设置时赠送的部分(忽略运算误差)。

9.366 KiB = 8191 byte + 1400 byte

EOS Table 倒序删除

数据库中只保留最新的100条记录,旧纪录删除

// 最多100条
besthistory_tables besthistory_table(_self, _self.value);
total_count = 0;
auto itr_besthistory = besthistory_table.rbegin();
while(itr_besthistory != besthistory_table.rend()){
    if(total_count >= 99){
        auto itr = besthistory_table.erase(--itr_besthistory.base());
        itr_besthistory = std::reverse_iterator(itr);
    } else {
        total_count++;
        itr_besthistory++;
    }
}

error: use of undeclared identifier 'current_time_point'

包含头文件

#include <eosio/system.hpp>

https://github.com/EOSIO/eosio.cdt/issues/470