gxchain / gxb-core

GXChain Blockchain implementation
https://www.gxchain.org
GNU General Public License v3.0
226 stars 78 forks source link

multi_index中的一些疑问 #185

Closed zonxin closed 5 years ago

zonxin commented 5 years ago

1、看到有些合约的 table 结构如下, pool 的 类型是 contract_asset 如何作为主键?

 {
      "name": "prizepool", "index_type": "i64",
      "key_names": [ "pool" ],  "key_types": ["contract_asset" ],
      "type": "prizepool"
    }

在 EOS 里可以 return pool.asset_id 使用 pool.asset_id 作为主键,但是 GXC 里不行。 我想知道在 GXC 如何实现,以及使用 multi_index::find 该如何查找。 即如下代码该怎么写?

// @abi table  prizepool i64
struct prizepool {
   contract_asset pool; 
   // ....
  uint64_t primary_key() const { return pool.asset_id;/* 这里该怎么写?*/ }
}

2. 合约内转调用withdraw_asset账有手续费吗? 跟普通转账价格相同还是少?

3. 合约的 action 一次执行的时间限制时多少?

RootkitKiller commented 5 years ago

你好,以下是您上述问题的回复,如果有疑问可以继续在下面交流

第一个问题,使用uint64_t primary_key() const { return pool.asset_id; } 是可以的,主键只支持uint64_t类型,请问是遇到什么错误了吗?编译错误还是使用multi_index::find错误?

第二个问题,使用withdraw_asset转账是不消耗手续费的,从合约账户提现资产到指定账户。

第三个问题,合约的 action 一次执行的时间限制是10ms

zonxin commented 5 years ago

@RootkitKiller 谢谢! 我又研究了一下, 第一个错误我知道了,是我//@abi table name i64 的注释写错了。 原因是我之前写的注释忘记加 i64 了, 所以如果写成return pool.asset_id; 会导致编译时出现Unable to guess index type 错误。 但是,如果只是return asset_id; 即使不加i64也不会出问题。

麻烦您了! 非常感谢!

zonxin commented 5 years ago

@RootkitKiller 不好意思又要麻烦您了

1、遇到一个特别奇怪的问题。 在官方测试网上,我部署了一个合约,合约中有个表,大概是:

    // @abi table prizepool i64
    struct prizepool {
        uint64_t asset_id;
        int64_t  prize_pool;
        int64_t  unissued_prize;
        // .......
        uint64_t primary_key() const { return asset_id; }
        // ... GRAPHENE_SERIALIZE
    };
    typedef graphene::multi_index<N(prizepool), prizepool> prizepool_index;
    prizepool_index prizepool_idx;

{_self,_self}初始化, 然后合约里有一个action

    // @abi action
    void withdraw(contract_asset amount)
    { 
       /*  这一部分即使注释掉也会出错
        auto it = prizepool_idx.find(asset_id);
        if(it != prizepool_idx.end()) {
       // .....
      }
        */
        withdraw_asset(_self, OWNER_ID, amount.asset_id, amount.amount);
    }

合约的表本身没有问题,问题是如果一个资产的asset_id出现在表中,那么,调用该action中的withdraw_asset转出该资产会大概率的出错,错误提示是:{type: "un_def_error", message: "graphene_assert_message assertion failure: assertion failure with message: different asset_id", code: 433}如果您需要我可以提供更详细的错误信息。 如果把该资产的对应的asset_id从这个表中删掉,则一切正常了。另外在合约其他action中的withdraw_asset时正常的。

  1. 几个简单的关于API的问题, 因为我不太确定GXC,对 boost::multi_index的接口进行了多大的修改 1) 次级索引(正常迭代器)是按照所以升序排列,重复值再按主键升序排序? 2) low_bound返回: 不小于查询值,并且主键索引最小的迭代器? 3) upper_bound返回: 不大于查询值,并且主键最大的迭代器? (JSON_RPC里 get_table_row_ex中返回的是不包括上界的,所以这个很不确定)
RootkitKiller commented 5 years ago

你好,以上问题回复如下: 1 可以把详细的合约代码发来看看。 2.1 是的 2.2 和2.3关于lower_bound 和 upper_bound,这两个接口与multi_index接口是一致的 假设存在元素 [2,3,4,5,6,7] 使用lower_bound(2),返回的迭代器为元素2. 使用upper_bound(2),返回的迭代器元素为3.
2.3 get_table_row_ex 返回的结果为左闭右开区间,包含下界,不包含上界

zonxin commented 5 years ago

关于第一个问题,我又试了一下

当一个合约直接部署,从来都没有更新的时候就不会出现问题,如果更新过就有可能出问题。 另外一个现象是, 为了确定问题, 我一点一点的删除代码,然后重新部署,发现有时会出现以前版本中已经删掉的graphene_assert失败出现的信息。 这个可能是同步问题,也有可能是:

现在在测试网上合约更新的逻辑是不是有变动,我看合约更新不是按合约大小定价的,而是看合约增大了多少,如果没有增大则收 1 GXC。 (我只是猜测, 可能性比较小,这句几乎可以忽略) 如果合约变小了,合约更新之后会残留部分之前的代码,当程序不小心跑飞,就会执行到残留的代码。

其他的我再试试看。