BCSkill (Block chain skill )
区块链中文技术社区

只讨论区块链底层技术
遵守一切相关法律政策!

零基础部署测试合约(三)---合约部署

下面开始编译合约


进入合约目录 /License

  1. 生成ABI
    eosiocpp -g License.abi License.cpp
  2. 生成WAST
    eosiocpp -o License.wast License.cpp

    执行完成后


开始部署合约

部署测试合约(一)---前准备中,已经创建dapp.token,dapp.exec账号

下面开始在dapp.token账户部署合约

cleos set contract dapp.token License/ -p dapp.token


开始执行合约
  1. 执行合约setuserinfo 修改用户信息
    cleos push action dapp.token setuserinfo '["dapp.exec","区块链技能学习", "bcskill.com"]' -p dapp.exec

  2. 查看用户信息
    cleos get table dapp.token dapp.token accounts

  3. 执行合约makeproject 创建项目
    cleos push action dapp.token makeproject '["dapp.exec","testcontract"]' -p dapp.exec

  4. 查看项目信息
    cleos get table dapp.token dapp.token projecttable

  5. 执行合约 buylicense购买项目授权
    cleos push action dapp.token buylicense '["dapp.exec","testcontract"]' -p dapp.exec

  6. 查看项目信息
    cleos get table dapp.token dapp.token projecttable

零基础部署测试合约(二)---合约编译

下面演示EOS智能合约编写,实例将涉及对链上多索引(multi_index)的增删改查。

实例为License合约,主要功能为

  • 客户设置自己的信息
  • 客户创建自己的项目
  • 客户购买项目授权
  • 验证项目授权
    (由于演示二级索引,项目名称为索引唯一,所以实例为用户单项目)
    上面的权限都是基于客户自身的权限验证,创建是创建的系统子账户,可用于系统币转账

合约代码基于C++语言,源代码分为源文件(.cpp)和头文件(.hpp)
//License.hpp

#include <eosiolib/asset.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>

class License : public eosio::contract {
    public:
        License( account_name self )
        :eosio::contract(self)
        ,accounts(_self, _self)
        ,projecttable(_self, _self){}

        void setuserinfo(account_name owner, const std::string& company_name, const std::string& contact_info);
        void makeproject(account_name owner, const std::string& project_name);
        void buylicense(account_name owner, const std::string& project_name);
        void testlicense(account_name owner, const std::string& project_name);

    private:
        //@abi table accounts i64
        struct account{
            account_name name;
            std::string company_name;
            std::string contact_info;
            uint8_t level;
            uint64_t primary_key()const { return name; }
            EOSLIB_SERIALIZE(account, (name)(company_name)(contact_info)(level))
        };

        typedef eosio::multi_index<N(accounts),account> account_table;
        account_table accounts;

        //@abi table projecttable i64
        struct project{
            uint32_t pkey;
            account_name owner_name;
            std::string project_name;
            std::string company_name;
            std::string contact_info;
            uint8_t      status;

            uint64_t primary_key()const { return pkey; }
            uint64_t getowner_name() const{return owner_name;}
            EOSLIB_SERIALIZE(project, (pkey)(owner_name)(project_name)(company_name)(contact_info)(status))
        };
        //contracts/eosiolib/multi_index.hpp
        //multi_index用于封装智能合约对数据库的管理,增、删、改、查
        //eosio::multi_index<N(表名),数据类型> 
        //一个multi_index最多支持16个二级索引
        //定义二级索引使用eosio::indexed_by模板。N(byowner_name)为索引的名称
        //project表数据类型,uint64_t索引类型即索引函数返回的类型(只支持uint64_t,uint128_t,double,long double,key256类型),&project::getowner_name索引函数。
        typedef eosio::multi_index<N(projecttable),project, eosio::indexed_by<N(byowner_name), eosio::const_mem_fun<project, account_name, &project::getowner_name> >> projecttable_type;
        projecttable_type projecttable;
};
EOSIO_ABI(License, (setuserinfo)(makeproject)(buylicense)(testlicense))

//License.cpp

#include <License.hpp>

void License::setuserinfo(account_name owner, const std::string& company_name, const std::string& contact_info){
    eosio::print("License::setuserinfo line 4");
    require_auth(owner);
    auto account_itr = accounts.find(owner);
    if(account_itr == accounts.end()){
        account_itr = accounts.emplace(_self, [&](auto& account){
            account.name = owner;
            account.company_name = company_name;
            account.contact_info = contact_info;
        });
    }
    else{
        accounts.modify(account_itr, 0, [&](auto& account) {
            account.company_name = company_name;
            account.contact_info = contact_info;
        });
    }
}

void License::makeproject(account_name owner, const std::string& project_name){
    require_auth(owner);
    //二级索引查找
    auto customer_index = projecttable.template get_index<N(byowner_name)>();
    account_name customer_acct = owner; //如果是string 可以用 eosio::string_to_name 转换
    auto cust_itr = customer_index.find(customer_acct);
    if (cust_itr != customer_index.end() && cust_itr->owner_name == customer_acct) {
        customer_index.modify(cust_itr, 0, [&](auto& project) {
            project.project_name = project_name;
            project.status = cust_itr->status; //初始化未授权,须另购买
            auto account_itr = accounts.find(owner);
            if(account_itr != accounts.end()){
                project.project_name = project_name;
                project.company_name = account_itr->company_name;
                project.contact_info = account_itr->contact_info;

            }
        });
    } 
    else{
        auto project_itr = projecttable.emplace(_self, [&](auto& project){
                project.owner_name = owner;
                project.project_name = project_name;
                auto account_itr = accounts.find(owner);
                if(account_itr != accounts.end()){
                    project.company_name = account_itr->company_name;
                    project.contact_info = account_itr->contact_info;
                    project.status = 0; //初始化未授权,须另购买
                }
            });
    }
}

void License::buylicense(account_name owner, const std::string& project_name){
    require_auth(owner);
    bool bFind = false;
    //二级索引查找
    auto customer_index = projecttable.template get_index<N(byowner_name)>();
    account_name customer_acct = owner; //如果是string 可以用 eosio::string_to_name 转换
    auto cust_itr = customer_index.find(customer_acct);
    while (cust_itr != customer_index.end() && cust_itr->owner_name == customer_acct) {
        if(cust_itr->project_name == project_name){
            if(cust_itr->status == 0){
                //TODO 判断当前账户余额,购买转账等操作
                customer_index.modify(cust_itr, 0, [&](auto& project) {
                    project.status = 1;
                });
            }
            else{
                eosio_assert(false, "The current project is authorized" );
            }
            bFind = true;
            break;
        }
        cust_itr++;
    } 
    eosio_assert(bFind, "owner with project not exists" );
}

void License::testlicense(account_name owner, const std::string& project_name){
    require_auth(owner);
    bool bFind = false;
    for( const auto& project : projecttable ) {
        if(project.project_name == project_name && project.owner_name == owner){
            eosio_assert((project.status == 1), "The current project is not authorized" );
            bFind = true;
            break;
        }
    }
    eosio_assert(bFind, "owner with project not exists" );
}

Github

零基础部署测试合约(一)---前准备

经过前面的三步

EOS 节点部署,BP出块(一)-->前期准备
EOS 节点部署,BP出块(二)-->节点连接
EOS 节点部署,BP出块(三)-->开始部署
已经完成了EOS链服务器相关配置,下面开始部署合约相关配置

  1. 打开eosio节点终端,创建dapp.token,dapp.exec账号
账号 公钥 私钥
dapp.token EOS7STj8j1LDXBVhttRm9FiyME1fDDn77UfjsFu1XQ2ybF2sYpwAM 5J87thFoJVD9fNos9i9QvLYFxZqCWMX4xJ3gGUGkweDbEn5WY2d
dapp.exec EOS5rzFj2sd4hmpAco8ujmDMDxZwWWTSvcS5BJYWpCcen6YbtNFAN 5JC9FdRjX3c3fsB62S5Tz22LgTuRHegb1XEV16uft8u3njmm9E5
//导入私钥
cleos wallet import 5J87thFoJVD9fNos9i9QvLYFxZqCWMX4xJ3gGUGkweDbEn5WY2d
cleos wallet import 5JC9FdRjX3c3fsB62S5Tz22LgTuRHegb1XEV16uft8u3njmm9E5
//创建账号
cleos system newaccount eosio dapp.token EOS7STj8j1LDXBVhttRm9FiyME1fDDn77UfjsFu1XQ2ybF2sYpwAM EOS7STj8j1LDXBVhttRm9FiyME1fDDn77UfjsFu1XQ2ybF2sYpwAM  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS' --buy-ram-kbytes 10000
cleos system newaccount eosio dapp.exec EOS5rzFj2sd4hmpAco8ujmDMDxZwWWTSvcS5BJYWpCcen6YbtNFAN EOS5rzFj2sd4hmpAco8ujmDMDxZwWWTSvcS5BJYWpCcen6YbtNFAN  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS' --buy-ram-kbytes 10000
//如果提示 Error 3080001: account using more than allotted RAM usage
cleos system buyram eosio dapp.token '100000.0000 SYS' -p eosio

部署测试合约(二)---合约编译
部署测试合约(三)---合约部署

零基础EOS 节点部署,BP出块(一)-->前期准备

事前准备

  1. 部署3台主机,账户名为(eosio,eosio.bp1,eosio.bp2),系统为Ubuntu 16.04以上版本
  2. 生成15个EOS地址 (10个系统预留账户,2个节点,3个用于投票)(在线生成
eosio eosio.token eosio.bpay eosio.msig eosio.names
eosio.ram eosio.ramfee eosio.saving eosio.stake eosio.upay
eosio.bp1 eosio.bp2 voter1 voter2 voter3
账户名 私钥 公钥
eosio 5KeqsXty9Sa8GfJgNfkckYxKKGcAWE4AWmUHiw6ifDcn3jjUg2i EOS5DkKbBZnSKNSV1iu27ovnygGhoCA99eH69KyNNkSkNrrbBoiRe
eosio.token 5JvL5wbJeQdgpKDDLRFUyWmHwBpRDgvARn99cS4pXoxZt8p7p4w EOS5M2sNqDPZtQoBcRMnPQEnY1MJaVtdWWPx7A3UpcLgtzdLusFVW
eosio.bpay 5KS9q4MPwmcpEM3rX96zR4A4FvLJZC9y1BZxvidaEwqfb4MWREx EOS5iezVa6bsmvZ3HNxdqgyX6GFRMWzE7FsjS3cui8Foavxnj8CfR
eosio.msig 5HsbhVhjtzeuzxdWKQv2MWBtbHzgjxEtYKQg9XB3cxPRYaC7r4m EOS8K1wkfCzPmxAjjfqvqw6zQ1Dbc82YsQyR8MmwNFLcRHcJtth89
eosio.names 5JrEru2K7FKLrwfLQ6B55PRWj2MXVkuXrLiurfn2osSatRsEmj6 EOS5ps938c5zj6UqhdCfssyAy7WSbHgfZoraqD6HrnbpmpEwPwX7S
eosio.ram 5HqNyZgePkdSZLuhz9YTi36L7HuhxpPeEEppNaB49Z7WcJWVsed EOS7DA8jGA6HfZXYcGSGJNsWJL5Q6t5bWcvm4zNykN3Jw7tASzBCR
eosio.ramfee 5KdYWerC5XnqfDhVV5igoyjuNFrT78McrErvbUMd36Wje77t6kJ EOS7R1Ds4zLMPN6onVXjL8XGgKHHCMWjLT7wn3bHcHnQX3dVLErjE
eosio.saving 5JN3GEXZVKYWAgbfdppvGU3hSpiu9BUcpEwpqMMp1NA6gvUsGF9 EOS6BDfFaFZgvx889BQbdaGTMYSn5tUuxaynGQDhpDGD662eBGwkF
eosio.upay 5Kgqr6jB6mfMjNv4vX1Hwj3KqiCxYUhPCnuxTK1mVN118fok4oG EOS7zS7sHctU54oD6is2oPfq11duCMSWfda3HXJAghSfqqr2BZZnV
eosio.bp1 5JzWCZ9W7VNWLYroQpjYG2z6H6UjJUkKdinZpumf6Ru2xoxSrKT EOS7mcXeVUSLCZxEf8eBPm2MbmiswNovoB6rk71pPqaZoxwSAeK7b
eosio.bp2 5HragVTsSmmAg1mznNMDSeAp2ZezcNBw6SbczrNpNtUqRcx4vhh EOS6hfh1yup4tZjbjhD3oPuZwMFqL4iUVehgMsukuvx5ojTWuurtT
voter1 5Jb2DtzYFU9c3LSEP5PPAfN7Je8d8yLGdDN42n561zy34UFwzTN EOS6wLrhcEQDZJvfZSCgVkFzsKcv34XTsTTjXXQZajWaBbEhvLPMg
voter2 5JsFet6W3Xmp3DvcHJsJ6GVcksSZJunGhmjpQaE9Np2ZtK4JYbc EOS6u8i7rknHyAd7AdziWSnEsAbyJHA3U9So4R8p2z58cA1KeEDv2
voter3 5JdQRPPCXtVLKBj5qhg6QtVq5PHuKoKnrcpePG6CsryPuYkiWX6 EOS8LyieKTsMAZGp7DSEhBPEPmPXvQKT5c3EXgEvACcdRwwRwDzoy

EOS 节点部署,BP出块(二)-->节点连接
EOS 节点部署,BP出块(三)-->开始部署

零基础EOS 节点部署,BP出块(三)-->开始部署

1.进入eosio主机终端

//eosio节点创建钱包
cleos wallet create
//保存解锁密钥
PW5K2Rg4rSYanfdcjnMcPhLUKZoBd2rq1W9mDZSoebgmKG55JXugU
//导入eosio帐号私钥
cleos wallet import 5KeqsXty9Sa8GfJgNfkckYxKKGcAWE4AWmUHiw6ifDcn3jjUg2i
//创建 eosio.token
cleos create account eosio eosio.token EOS5M2sNqDPZtQoBcRMnPQEnY1MJaVtdWWPx7A3UpcLgtzdLusFVW EOS5M2sNqDPZtQoBcRMnPQEnY1MJaVtdWWPx7A3UpcLgtzdLusFVW
//导入eosio.token私钥
cleos wallet import 5JvL5wbJeQdgpKDDLRFUyWmHwBpRDgvARn99cS4pXoxZt8p7p4w
//创建系统预留账户
cleos create account eosio eosio.bpay EOS5iezVa6bsmvZ3HNxdqgyX6GFRMWzE7FsjS3cui8Foavxnj8CfR EOS5iezVa6bsmvZ3HNxdqgyX6GFRMWzE7FsjS3cui8Foavxnj8CfR
cleos create account eosio eosio.msig EOS8K1wkfCzPmxAjjfqvqw6zQ1Dbc82YsQyR8MmwNFLcRHcJtth89 EOS8K1wkfCzPmxAjjfqvqw6zQ1Dbc82YsQyR8MmwNFLcRHcJtth89
cleos create account eosio eosio.names EOS5ps938c5zj6UqhdCfssyAy7WSbHgfZoraqD6HrnbpmpEwPwX7S EOS5ps938c5zj6UqhdCfssyAy7WSbHgfZoraqD6HrnbpmpEwPwX7S
cleos create account eosio eosio.ram EOS7DA8jGA6HfZXYcGSGJNsWJL5Q6t5bWcvm4zNykN3Jw7tASzBCR EOS7DA8jGA6HfZXYcGSGJNsWJL5Q6t5bWcvm4zNykN3Jw7tASzBCR
cleos create account eosio eosio.ramfee EOS7R1Ds4zLMPN6onVXjL8XGgKHHCMWjLT7wn3bHcHnQX3dVLErjE EOS7R1Ds4zLMPN6onVXjL8XGgKHHCMWjLT7wn3bHcHnQX3dVLErjE
cleos create account eosio eosio.saving EOS4uDMpca1dAK7HZZRQ1SqWZHvJNnakzsSuTmM12crvzwRorwQcQ EOS4uDMpca1dAK7HZZRQ1SqWZHvJNnakzsSuTmM12crvzwRorwQcQ
cleos create account eosio eosio.stake EOS6BDfFaFZgvx889BQbdaGTMYSn5tUuxaynGQDhpDGD662eBGwkF EOS6BDfFaFZgvx889BQbdaGTMYSn5tUuxaynGQDhpDGD662eBGwkF
cleos create account eosio eosio.upay EOS7zS7sHctU54oD6is2oPfq11duCMSWfda3HXJAghSfqqr2BZZnV EOS7zS7sHctU54oD6is2oPfq11duCMSWfda3HXJAghSfqqr2BZZnV
//切换到contracts目录
cd /eos/build/contracts
//部署eosio.token合约
cleos set contract eosio.token eosio.token
//创建代币 (BM将线上代码EOS 改成了SYS,之后上线后还是EOS)
cleos push action eosio.token create '["eosio","10000000000.0000 SYS",0,0,0]' -p eosio.token
//发布代币
cleos push action eosio.token issue '["eosio","10000000000.0000 SYS","issue"]' -p eosio
//查询代币数量
cleos get currency balance eosio.token eosio
//部署eosio.bios合约
cleos set contract eosio eosio.bios/ -p eosio
//部署eosio.system合约
cleos set contract eosio eosio.system -p eosio
//创建BP节点账户
cleos system newaccount eosio eosio.bp1 EOS7mcXeVUSLCZxEf8eBPm2MbmiswNovoB6rk71pPqaZoxwSAeK7b EOS7mcXeVUSLCZxEf8eBPm2MbmiswNovoB6rk71pPqaZoxwSAeK7b  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS'  --buy-ram-kbytes 10000
cleos system newaccount eosio eosio.bp2 EOS6hfh1yup4tZjbjhD3oPuZwMFqL4iUVehgMsukuvx5ojTWuurtT EOS6hfh1yup4tZjbjhD3oPuZwMFqL4iUVehgMsukuvx5ojTWuurtT  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS'  --buy-ram-kbytes 10000

//创建Voter账户
cleos system newaccount eosio voter1 EOS6wLrhcEQDZJvfZSCgVkFzsKcv34XTsTTjXXQZajWaBbEhvLPMg  EOS6wLrhcEQDZJvfZSCgVkFzsKcv34XTsTTjXXQZajWaBbEhvLPMg  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS'  --buy-ram-kbytes 10000
cleos system newaccount eosio voter2 EOS6u8i7rknHyAd7AdziWSnEsAbyJHA3U9So4R8p2z58cA1KeEDv2  EOS6u8i7rknHyAd7AdziWSnEsAbyJHA3U9So4R8p2z58cA1KeEDv2  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS'  --buy-ram-kbytes 10000
cleos system newaccount eosio voter3 EOS8LyieKTsMAZGp7DSEhBPEPmPXvQKT5c3EXgEvACcdRwwRwDzoy  EOS8LyieKTsMAZGp7DSEhBPEPmPXvQKT5c3EXgEvACcdRwwRwDzoy  --stake-net '50.00 SYS' --stake-cpu '50.00 SYS'  --buy-ram-kbytes 10000
//导入Voter私钥
cleos wallet import 5Jb2DtzYFU9c3LSEP5PPAfN7Je8d8yLGdDN42n561zy34UFwzTN
cleos wallet import 5JsFet6W3Xmp3DvcHJsJ6GVcksSZJunGhmjpQaE9Np2ZtK4JYbc
cleos wallet import 5JdQRPPCXtVLKBj5qhg6QtVq5PHuKoKnrcpePG6CsryPuYkiWX6

//给Voter账户转账
cleos push action eosio.token transfer '["eosio", "voter1","100000000.0000 SYS","vote"]' -p eosio
cleos push action eosio.token transfer '["eosio", "voter2","100000000.0000 SYS","vote"]' -p eosio
cleos push action eosio.token transfer '["eosio", "voter3","100000000.0000 SYS","vote"]' -p eosio
//锁定Voter账户需要投票的代币
cleos system delegatebw voter1 voter2 '25000000.0000 SYS' '25000000.0000 SYS' --transfer
cleos system delegatebw voter2 voter3 '25000000.0000 SYS' '25000000.0000 SYS' --transfer
cleos system delegatebw voter3 voter1 '25000000.0000 SYS' '25000000.0000 SYS' --transfer

2.进入eosio.bp1 主机终端

//BP1节点创建钱包
cleos wallet create
//保存解锁密钥
PW5HsYdyQdQfTgHJnpaiGRjFVDLs7Cb48A6PzeneaDNdSf8UnrntT
//导入私钥
cleos wallet import 5JzWCZ9W7VNWLYroQpjYG2z6H6UjJUkKdinZpumf6Ru2xoxSrKT
//BP1节点申请BP
cleos system regproducer eosio.bp1 EOS7mcXeVUSLCZxEf8eBPm2MbmiswNovoB6rk71pPqaZoxwSAeK7b http://eosio.bp1.ip:8888

3.进入eosio.bp2 主机终端

//BP2节点创建钱包
cleos wallet create
//保存私钥
PW5JaB4WtawXWE6wmDymsprEdh9xPiL5EakY83JDywdvpFbK9fWpG
//导入私钥
cleos wallet import 5HragVTsSmmAg1mznNMDSeAp2ZezcNBw6SbczrNpNtUqRcx4vhh
//BP2申请BP
cleos system regproducer eosio.bp2 EOS6hfh1yup4tZjbjhD3oPuZwMFqL4iUVehgMsukuvx5ojTWuurtT http://eosio.bp2.ip:8888

4.回到eosio主机终端

//BP节点申请BP
cleos system regproducer eosio EOS5DkKbBZnSKNSV1iu27ovnygGhoCA99eH69KyNNkSkNrrbBoiRe http://eosio.eosio.ip:8888

//开始投票
cleos system voteproducer prods voter1 eosio.bp1
cleos system voteproducer prods voter2 eosio.bp1
cleos system voteproducer prods voter3 eosio.bp1
cleos system voteproducer prods voter1 eosio.bp2
cleos system voteproducer prods voter2 eosio.bp2
cleos system voteproducer prods voter3 eosio.bp2

cleos system voteproducer prods voter1 eosio
cleos system voteproducer prods voter2 eosio
cleos system voteproducer prods voter3 eosio

此时 eosio, eosio.bp1, eosio.bp2 已出块