前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >EOS实践篇(续) - 合约一键部署

EOS实践篇(续) - 合约一键部署

作者头像
陨石坠灭
发布2020-01-21 16:02:04
9080
发布2020-01-21 16:02:04
举报
文章被收录于专栏:全栈之路全栈之路

在调试合约的时候,发现部署合约是一件比较麻烦的事情,所以写了个脚本实现一键部署合约,写下这篇文章来介绍其中的一些命令。 想要一键部署合约,编写脚本是必不可少的,这里以Mac的Docker环境部署为例,脚本为shell脚本。本文将信息介绍部署的步骤,这样的话,在linux以及Windows上部署也可以作为参考。

前言

如果不了解EOS,可以先看:EOS实践篇

另外还有使用Scatter插件的教程:使用Scatter创建自己的账号

部署

步骤简介

  1. 下载docer
  2. 下载、启动以及配置keosd
  3. 创建钱包、导入密钥
  4. 打开钱包,结束钱包
  5. 创建账号
  6. 获取eos
  7. 购买cpu、net资源,购买ram资源
  8. 下载合约、将合约复制到docker实例目录下
  9. 设置合约
  10. 授权

步骤讲解

1. 下载docer

下载地址 https://www.docker.com/get-started

下载后根据提示进行安装,然后点击应用图标,即可启动docker服务

2. 下载、启动以及配置keosd

只有第一启动是需要执行一下步骤,下一次启动,只需要执行docker start keosd命令即可。

这里以shell脚本所在目录($curpath)为例,端口号为8900,也可以是其他的端口号:

代码语言:javascript
复制
docker pull eosio/eos
docker stop keosd
docker rm keosd

docker start keosd

curpath=$(cd "$(dirname "$0")"; pwd)

mkdir $curpath/eosio-wallet

docker run -d --restart=unless-stopped --name keosd   \
    -v $curpath/eosio-wallet:/opt/eosio/bin/data-dir  \
    -v $curpath/eosio-wallet:$home/eosio-wallet \
    -t eosio/eos /opt/eosio/bin/keosd  \
    --wallet-dir /opt/eosio/bin/data-dir \
    --http-server-address=127.0.0.1:8900

连接到测试网:

测试网接口可以为:https://jungle.eosn.io:443,同时接口可能会变动,可以访问如下网址,选择其中一个就行:

https://monitor.jungletestnet.io/#apiendpoints

另外,shopt -s expand_aliases这个命令的作用是使alias命令在脚本中也能生效。如果实在控制台下执行,就不需要改命令了。

alias命令设置后,就不需要每次执行命令都需要设置-u参数了,直接使用cleos命令即可。

代码语言:javascript
复制
docker start keosd
shopt  -s  expand_aliases
alias cleos="docker exec -i keosd /opt/eosio/bin/cleos  --wallet-url http://127.0.0.1:8900  -u <测试网接口>"

3. 创建钱包、导入密钥

这里需要提前生成私钥,可以使用命令cleos create key生成。另外创建钱包时,需要将生成的密码保存到文件中,以免忘记密码而导致钱包无法解锁。

代码语言:javascript
复制
wallet=<钱包名称>
pwd_file=<保存密码的文件>
private_key=<私钥>

cleos wallet create -n $wallet --to-console > $pwd_file

password=$(cat $pwd_file |grep "\"" |awk -F "\"" '{ print $2 }')
cat $password > $pwd_file

cleos wallet import -n $wallet $private_key

4. 打开钱包,解锁钱包

这是一个很烦恼的问题,每次交易的时候都会弹出需要解锁的提示,当你下一次交易时,你可以先解锁是,又会报错:提示已经解锁。虽然没什么,但是很烦。。。

以下是命令:

代码语言:javascript
复制
cleos wallet open -n <钱包名称>
cleos wallet unlock -n <钱包名称> --password <密码>

如果是默认(default)钱包,就不需要加-n参数了

5. 创建账号

https://monitor.jungletestnet.io/#account

进入网站后,只需要填写已注册的合约账号和公钥,然后验证,最后点击确认就可以

这里作为测试,owneractive的公钥可以填写为一样的。

当然,也可以通过命令来创建账号:

代码语言:javascript
复制
$ cleos system newaccount \
--stake-net '<网络资源要抵押的EOS数量> EOS' \
--stake-cpu 'cpu资源要抵押的EOS数量 EOS' \
--buy-ram-kbytes <要购买的ram字节数量> \
<金主账号> <新账号> <新账号公钥>

其中buy-ram-kbytes是字节,不需要带单位

6. 获取eos

https://monitor.jungletestnet.io/#faucet

进入网站后,只需要填写已注册的合约账号,然后验证,最后点击确认就可以获取EOS了,当然这是测试网的。

值得注意的是,同一个账号6小时内只有一次成功获取到EOS。这个可以提前获取,这样才能够已经部署合约,脚本执行过程中,不可能去获取EOS,这样就算不上是一键部署了。

7. 购买cpu、net资源,购买ram资源

如果要部署合约,需要购买cpu等资源,否则的话,会以部署失败告终,同时需要注意,购买的资源不够,同样会部署失败。

另外购买资源的账号与合约账号不一定是同一个账号,所以可以专门提供一个提供购买资源的账号,也就是金主,提前充值EOS到合约账号,这样就不需要中途去获取EOS,从而达到一键部署的目的。

购买cpu、net资源

如果只需要购买net资源,cpu资源抵押的EOS数量可为:0.0000,同理,只需要购买cpu资源类似。

代码语言:javascript
复制
$  cleos system delegatebw <金主账号> <新账号> "<网络资源要抵押的EOS数量> EOS" "<cpu资源要抵押的EOS数量> EOS"

购买ram

这里要提的一点是,填写的是bytes数量,所以不需要带单位。

代码语言:javascript
复制
$ cleos system buyram -k <金主账号> <新账号>  <bytes数量>

8. 下载和编译合约、将合约复制到docker实例目录下

下载合约:

如果合约在本地,就不需要下载合约了,这里以git为例:

代码语言:javascript
复制
if [ -d "<合约目录>" ];then
    cd <合约目录>/<合约名称>
    git pull
else
    mkdir <合约目录>
    cd <合约目录>
    git clone <git地址>
fi

如果需要切换分支:

这里的分支名称是指本地的分支名称

代码语言:javascript
复制
 git checkout <分支名称>

由于采用的是docker,所以需要考虑到合约路径的问题。需要将合约复制到docker目录下。

首先需要获取实例ID:

代码语言:javascript
复制
$ docker inspect -f '{{.ID}}'  keosd

复制合约:

代码语言:javascript
复制
doc_id=$(docker inspect -f '{{.ID}}'  keosd)
docker cp <当前合约路径> $doc_id:<实例目标合约路径>

9. 设置合约

设置新账号有一个关键的地方,就是合约路径。

这里的合约路径并不是本地的路径,而是docker实例中的路径,可以使用 docker exec -it keosd bash 命令,进入实例中查看合约所在的具体路径。

合约目录中需要包含*.wasm以及*.abi文件。

代码语言:javascript
复制
$ cleos set contract <新账号> <合约路径> -p <新账号>@active

10. 授权

这里的“授权”,是指使用户的账号能够拥有提现的权限。如果不需要提现功能的话,该步骤可以不做。

由于合约账号才拥有将EOS转出的权限,因此,合约如果要实现提现功能,似乎不可能,总不能把合约账号的私钥提供给用户吧。但是以下命令可以解决这个问题,合约提供提现的action方法,用户只需要自己的权限就可以提现。

代码语言:javascript
复制
$ cleos set account permission <新账号> active \
'{ \
  "threshold": 1, \
  "keys": [{"key": "<新账号>", "weight": 1}], \
  "accounts": [ \
      { \
          "permission": { "actor":"<新账号>","permission":"eosio.code" },
          "weight":1 \
      } \
  ] \
}' \
owner -p ${新账号}

脚本具体代码

代码放在github上了:

https://github.com/xiaoyifan6/soeth/blob/master/tools/eos/build.sh

另外介绍一下用法:

创建deploy.sh, 一下为空字符串的都是需要配置的变量,其中*_money为0,则表示不会进行此项购买或者抵押操作。

另外accountnew_account可以是同一个,前提是账号已经创建并且有充足的EOS。另外第二次部署合约,则为更新合约,若合约有改表或者action方法名称,可能需要消耗额外的ram,若abi文件没有变化,则不会消耗额外的ram。

contract_path这里是指合约的相对路径,相对于脚本所在目录的contracts目录。

代码语言:javascript
复制
#!/bin/bash
curpath=$(cd "$(dirname "$0")"; pwd)

account="" # 金主账号
new_account="" # 合约账号名称
contract_name="" # 合约名称

wallet="" # 钱包名称
ram_money="0" # 部署钱包需要的金额 1400
cpu_money="0" # 部署钱包需要的金额 4
net_money="0" # 部署钱包需要的金额 2
git_url="" # 合约git地址
private_key="" # 私钥
public_key="" # 公钥
contract_path="" # 合约相对路径
password="" #钱包密码
url="https://jungle.eosn.io:443"

# 切换到master分支
cd $curpath/contracts/$contract_name/
git checkout master

bash $curpath/build.sh \
    -a $account \
    -n $new_account \
    -g $git_url \
    -w $wallet \
    -C $contract_name \
    -P $password \
    -p $contract_path \
    -k $private_key \
    -K $public_key \
    -u $url \
    -r $ram_money \
    -c $cpu_money \
    -N $net_money 
    # -i #初始化

延伸

1. 获取chainId

以下命令可以直接得到当前节点的信息,其中包括chain_id

代码语言:javascript
复制
$ cleos get info

2. Scatter:切换账号

切换账号之前,需要先忘记账号。

代码语言:javascript
复制
var _scatter = window['scatter'];
_scatter && _scatter.forgetIdentity();
var defaultAccount = null;

var netwok = {
      blockchain: 'eos',
      host: <IP地址或url>,
      port: <端口号>,
      protocol: "<http|https>",
      chainId: "<ChainID>"
};

setTimeout(function () {
     _scatter.getIdentity({
          accounts: [netwok]
     }).then(res => {
           if (!res) return reject();
          var identity: Identity = res;
          var _account = identity.accounts.find((accound) => {
                return accound.blockchain == "eos";
          });
          defaultAccount = _account;
     }).catch(res => { });
}, 1000);

3. eosjs:获取账号信息,并计算netcpuram价格

首先初始化eos

代码语言:javascript
复制
var netwok = {
      blockchain: 'eos',
      host: <IP地址或url>,
      port: <端口号>,
      protocol: "<http|https>",
      chainId: "<ChainID>"
};

var eos =_scatter.eos(netwok, Eos, {}, <http|https>);

formatEos方法:

这里涉及到精度问题,这里只保留了6位小数。

代码语言:javascript
复制
function formatEos(value) {
    return parseFloat(parseFloat(value).toFixed(6));
}

getTableRows方法参考下面提到的分页查询。

计算net、cpu价格

account为账号,由于接收账号和付款账号可以是同一个,所以这里都填写为account。这里可以是defaultAccount.name

代码语言:javascript
复制
function async getNetResourceGetBandwidthPrice(account) {
    var res await eos.getAccount(account);
    var netPrice = 0;
    var cpuPrice = 0;
    if (res) {
        //1. 计算NET价格
        //抵押NET的EOS数量
        var netBalance = res.net_weight / 10000;
        //NET贷款的总量
        var netTotal = res.net_limit.max / 1024;
        //(netBalance / netTotal)获取到的是过去3天内的平均消耗量,除以3获取每天的平均消耗量,即价格
        netPrice = ((netBalance / netTotal) / 3);
        console.log(netBalance, netTotal, netPrice)

        //1. 计算CPU价格
        //抵押CPU的EOS数量
        var cpuBalance = res.cpu_weight / 10000;
        //CPU贷款的总量
        var cpuTotal = res.cpu_limit.max / 1024;
        //(cpuBalance / cpuTotal)获取到的是过去3天内的平均消耗量,除以3获取每天的平均消耗量,即价格
        cpuPrice = ((cpuBalance / cpuTotal) / 3);
    }

    return {
        netPrice: netPrice,
        cpuPrice: cpuPrice,
    };
}

计算ram价格

这里价格单位为:EOS/KB

代码语言:javascript
复制
function async getRamPrice() {
    var res = await getTableRows("eosio", "rammarket", "eosio",1,0);
    if (res && res.rows && res.rows.length > 0) {
        return formatEos(res.rows[0].quote.balance) / formatEos(res.rows[0].base.balance) * 1024;
    }
    return 0;
}

4. eosjs:购买netcpuram

首先,得写一个调用活动的方法:

defaultAccount:前面的账号切换提到defaultAccount的获取方法。

代码语言:javascript
复制
function doAction(contractName, actionName, ...param) {
    return new Promise((resolve, reject) => {
        const account = defaultAccount;
        const options = {
            authorization: [`${account.name}@${account.authority}`]
        };

       eos.contract(contractName).then(contract => {
            contract[actionName].apply(window, param.concat(options)).then(res2 => {
                resolve(res2);
            }).catch(err => {
                reject(err);
            });
        }).catch(err => {
            reject(err);
        });
    });
}

购买netcpu

这里的net_amount为购买网络资源需要抵押的EOS数量,cpu_amount为购买cpu资源需要抵押的EOS数量

account为账号,由于接收账号和付款账号可以是同一个,所以这里都填写为account。这里可以是defaultAccount.name

代码语言:javascript
复制
function async delegatebw(account, net_amount, cpu_amount) {
    let flag = true;
    try {
        var res = await doAction("eosio", "delegatebw", account, account, 
            `${net_amount.toFixed(4)} EOS`, `${cpu_amount.toFixed(4)} EOS`, 0);
      return res;
    } catch (e) {
        throw e;
    }
}

购买ram

这里ramAmount的单位是字节,即要购买的字节数量。

首先初始化eos:上面的获取账号信息有提到。

account为账号,由于接收账号和付款账号可以是同一个,所以这里都填写为account。这里可以是defaultAccount.name

代码语言:javascript
复制
function async buyRam(account, ramAmount) {
    let flag = true;
    try {
        var res = await doAction("eosio", "buyrambytes", account, account, ramAmount);
      return res;
    } catch (e) {
        throw e;
    } 
}

5. eosjs:关于分页获取合约表格数据

分页查询一般有两种方式,一个是知道第几页以及每页大小或者其起始索引以及每页大小。

而今天讲的是后者。

首先初始化eos:上面的获取账号信息有提到。

然后编写函数,其中limit为每页大小,index_position为起始位置

代码语言:javascript
复制
function async getTableRows(contractName, table, scope, limit, index_position) {
    try {
      var start = new Date().getTime();
      var flag = true;
      var param = {
         code: contractName,
         scope: scope,
         table: table,
        json: true,
        lower_bound: index_position,
     };
     limit && (param["limit"] = limit);
     if (!eos) {
       return {
          rows: [],
          more: false
       };
   }
   return await eos.getTableRows(param);
  } catch (e) {
      throw e;
  }
}

6. eosjs:关于uint64_t的编码与解码

uint64_t在合约中可以将字符串类型存储到表中,而这时候客户端获取到的是一个数值,通过解码后,可以得到相应的字符串。

代码语言:javascript
复制
function encode(value) {
      return Eos["modules"].format.encodeName(value, false);
}

function decode(value) {
    return Eos["modules"].format.decodeName(value.toString(), false)
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018/12/17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 部署
    • 步骤简介
      • 步骤讲解
        • 1. 下载docer
        • 2. 下载、启动以及配置keosd
        • 3. 创建钱包、导入密钥
        • 4. 打开钱包,解锁钱包
        • 5. 创建账号
        • 6. 获取eos
        • 7. 购买cpu、net资源,购买ram资源
        • 8. 下载和编译合约、将合约复制到docker实例目录下
        • 9. 设置合约
        • 10. 授权
    • 脚本具体代码
    • 延伸
      • 1. 获取chainId
        • 2. Scatter:切换账号
          • 3. eosjs:获取账号信息,并计算net、cpu、ram价格
            • 4. eosjs:购买net、cpu、ram
              • 5. eosjs:关于分页获取合约表格数据
                • 6. eosjs:关于uint64_t的编码与解码
                相关产品与服务
                访问管理
                访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档