EOS 当使用 eosio::singleton 时抱 Error 3010001: Invalid name

yufei       2 年 前       1158

在日常的 EOS 合约开发中,我们一般使用 multi_index 作为表来保存数据,这是一个多索引链表结构。在需要存储某个结构 ( struct )的多个实例的情况下是非常有用的。

但如果只有一个实例,比如配置,比如总的状态,那么使用 multi_index 则显得有点复杂了。

为了应对这种需求,官方推出了 eosio::singleton 单例表,这个表在文件 <eosiolib/singleton.hpp> 中定义。

如果你看了源代码,就会发现它只是对 multi_index 的一个简单的封装。

但是,这个 eosio::singleton 在生成的 ABI 是错误的。比如下面的代码

hh.cpp

#include <eosiolib/eosio.hpp>
#include <eosiolib/singleton.hpp>

using namespace eosio;

class [[eosio::contract]] hh : public contract {
public:
    using contract::contract;

    [[eosio::action]]
    void hi() {
       print("Hello World");
    }

    struct [[eosio::table]] tbl_config{
        uint64_t bonus_down;
        uint64_t bonus_up;
    };

    typedef eosio::singleton<"config"_n, tbl_config> config;
};
EOSIO_DISPATCH( hh, (hi))

编译后的 ABI 内容如下

{
    "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Sun Nov 18 12:25:49 2018",
    "version": "eosio::abi/1.1",
    "structs": [
        {
            "name": "hi",
            "base": "",
            "fields": []
        },
        {
            "name": "tbl_config",
            "base": "",
            "fields": [
                {
                    "name": "bonus_down",
                    "type": "uint64"
                },
                {
                    "name": "bonus_up",
                    "type": "uint64"
                }
            ]
        }
    ],
    "types": [],
    "actions": [
        {
            "name": "hi",
            "type": "hi",
            "ricardian_contract": ""
        }
    ],
    "tables": [
        {
            "name": "tbl_config",
            "type": "tbl_config",
            "index_type": "i64",
            "key_names": [],
            "key_types": []
        }
    ],
    "ricardian_clauses": [],
    "variants": [],
    "abi_extensions": []
}

粗看没什么错误。

但是,如果你使用过 multi_index 的版本,就会发现一个问题,"tables": 里的 name 是错误,正常应该是 config 才对

这种情况下,如果我们部署合约,就会报错

Reading WASM from ../hh/hh.wasm...
Skipping set code because the new code is the same as the existing code
Error 3010001: Invalid name
Name should be less than 13 characters and only contains the following symbol .12345abcdefghijklmnopqrstuvwxyz
Error Details:
Name not properly normalized (name: tbl_config, normalized: tbl.config)

这个

Error 3010001: Invalid name
Name should be less than 13 characters and only contains the following symbol .12345abcdefghijklmnopqrstuvwxyz

的错误,原因就是刚刚说的那个 "tables": 里的 name 导致的。

面对这个问题,目前只有一个解决方案,就是在添加一个多余的 multi_index 定义

typedef eosio::multi_index<"config"_n, tbl_config> dump_for_config;

完整的代码如下

#include <eosiolib/eosio.hpp>
#include <eosiolib/singleton.hpp>

using namespace eosio;

class [[eosio::contract]] hh : public contract {
public:
    using contract::contract;

    [[eosio::action]]
    void hi() {
       print("Hello World");
    }

    struct [[eosio::table]] tbl_config{
        uint64_t bonus_down;
        uint64_t bonus_up;
    };

    typedef eosio::singleton<"config"_n, tbl_config> config;
    typedef eosio::multi_index<"config"_n, tbl_config> dump_for_config;
};
EOSIO_DISPATCH( hh, (hi))

这样,生成的 ABI 文件才是正常的

{
    "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Sun Nov 18 12:27:26 2018",
    "version": "eosio::abi/1.1",
    "structs": [
        {
            "name": "hi",
            "base": "",
            "fields": []
        },
        {
            "name": "tbl_config",
            "base": "",
            "fields": [
                {
                    "name": "bonus_down",
                    "type": "uint64"
                },
                {
                    "name": "bonus_up",
                    "type": "uint64"
                }
            ]
        }
    ],
    "types": [],
    "actions": [
        {
            "name": "hi",
            "type": "hi",
            "ricardian_contract": ""
        }
    ],
    "tables": [
        {
            "name": "config",
            "type": "tbl_config",
            "index_type": "i64",
            "key_names": [],
            "key_types": []
        }
    ],
    "ricardian_clauses": [],
    "variants": [],
    "abi_extensions": []
}

部署时才不会失败

cleos set contract hh ../hh -p hh
Reading WASM from ../hh/hh.wasm...
Publishing contract...
executed transaction: 9d41655faff0df76948d4f2ed26d562834847858bc161abaa2b3dfdafdfeab98  1432 bytes  7580 us
#         eosio <= eosio::setcode               {"account":"hh","vmtype":0,"vmversion":0,"code":"0061736d0100000001300960017f006000017f60027f7f017f6...
#         eosio <= eosio::setabi                {"account":"hh","abi":"0e656f73696f3a3a6162692f312e31000202686900000a74626c5f636f6e66696700020a626f6...
2 回复  |  直到 Feb 19, 2019

carl

#1   •   1 年, 9 月 前   •  

其实只要表结构名和主网EOS命名规则一样就行了

yufei

#2   •   1 年, 9 月 前   •  

@carl 是的

简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2018 简单教程 twle.cn All Rights Reserved.