编译部署智能合约

想看原汁原味的英文文档可移步至(https://kauri.io/#communities/Getting%20started%20with%20dapp%20development/understanding-smart-contract-compilation-and-depl),本文做了一些简单翻译,且只针对ubuntu系统

要开发dapp,有很多事情要做,如:

  • 代码编译
  • 生成abis
  • 测试
  • 部署

步骤

  • 编译,生成 字节码函数描述符 (Application Binary Interface,简称ABI)
  • 字节码参数 打包到一个 事务
  • 部署合同的账户签署事务
  • 将已签署的事务发送到链上,并挖矿

编译

编译智能合约需要solc编译器,通常情况下,我们都是使用框架开发,而一般的框架都是预先内置了solc编译器。
常用框架有:

这里我们使用原生的方式编译,所以需要手动安装solc。

安装solc编译器

add-apt-repository ppa:ethereum/ethereum
apt update
apt install solc

更多安装细节可去查看官方文档(http://solidity.readthedocs.io/en/latest/installing-solidity.html)
安装成功后,可通过下面命令查看solc版本

solc --version

安装jq

jq是linux系统下一个格式化输出json的工具,这里安装jq只是为了更好的查看json文件而已,并非必须

apt install jq

更多安装jq的细节移步至(https://stedolan.github.io/jq/download)

编译solidity文件

通过编译solidity文件,我们会得到:

  • 字节码
  • ABI(通过ABI可与已经部署的合约进行交互)

创建工作目录/文件

mkdir dapp-series-bounties
cd dapp-series-bounties
touch Bounties.sol

编写sol文件

将(https://github.com/kauri-io/kauri-fullstack-dapp-tutorial-series/blob/master/manual-compilation-and-deploy/Bounties.sol)中的文件内容拷贝下来写到自己的Bounties.sol文件中
这里要注意文件中的solidity编译器版本需要和你本地安装solidity编译器版本保持一致

执行编译

执行编译的命令如下:

solc --combined-json abi,bin Bounties.sol > Bounties.json

上述命令会将编译生成的 字节码abi 写入到Bounties.json文件中

部署

所谓部署,就是上链,上哪个链?即 需要一个以太坊环境进行部署。
为此,我们将使用 Ganache-CLI 运行本地开发区块链环境。

安装ganache-cli

npm install -g ganache-cli

由于我使用的是ubuntu,会报没有npm命令,所以执行下述命令安装npm

安装npm

sudo apt install npm

配置npm源

npm config set registry http://registry.npm.taobao.org

更新npm

npm install npm -g

个人理解ganache-cli就是区块链的本地开发环境

安装geth(go-etherenum)

什么是geth

文档翻译过来的意思是:一个以太坊节点的Go实现
太难理解,下述来自(https://www.jianshu.com/p/9eb600f0e0e4)的通俗解释

  • Geth可以当客户端来使用

打开Geth,用户可以创建自己的以太坊私有链、管理账户、挖矿、交易、部署执行智能合约等,用户还可以下载以太坊主链、解析主链上任意交易数据等。

  • Geth可以当服务器来使用

Geth提供很多服务和丰富的API,用户可以开发程序通过调用Geth服务,实现自己想要的功能,比如获取一段时间内以太币的所有交易账户。

安装命令

apt install software-properties-common
add-apt-repository -y ppa:ethereum/ethereum
apt update
apt install ethereum

更多安装细节参考(https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)

启动ganache-cli 并连接geth控制台

启动ganache-cli区块链本地开发环境

ganache-cli

启动后,会给到你一些东西

  • 账号(Available Accounts)
  • 私钥(Private Keys)
  • 钱包(HD Wallet)
  • Gas Price
  • Gas Limit
  • 启动服务(监听8545端口)

连接geth控制台到环境

geth attach http://localhost:8545

部署前的准备(获取字节码和abi)

要准备好 字节码abi,在编译的时候,已经将这些东西写入到Bounties.json文件中了,所以需要将编译好json文件加载到geth控制台

准备js文件

因为(可能)geth控制台不能加载json文件,所以需要将json文件的内容写入到一个js文件(Bounties.js)中
在js文件中定义一个变量,其值等于sol文件编译的结果

echo "var bountiesOuput=" > Bounties.js
cat Bounties.json >> Bounties.js

geth控制台加载js文件

通过加载js文件,可以把变量加载到控制台环境中
在geth控制台中运行

> loadScript('Bounties.js')
true
> bountiesOutput
{
contracts: {
Bounties.sol:Bounties: {
abi: "[{\"constant\":false,\"inputs\":[{\"name\":\"_bountyId\",\"type\":\"uint256\..."}]"}],
bin: "608060405234801561001057600080fd5b506..."
}
},
version: "0.4.24+commit.e67f0147.Darwin.appleclang"
}

geth获取abi

因为abi是字符串格式,所以需要先解析

查看abi类型

> typeof bountiesOutput.contracts["Bounties.sol:Bounties"].abi
"string"

解析abi

> var bountiesContract = eth.contract(JSON.parse(bountiesOutput.contracts["Bounties.sol:Bounties"].abi));
undefined

查看解析后的abi

> bountiesContract
{
abi: [{
constant: false,
inputs: [{...}, {...}],
name: "fulfillBounty",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [{...}, {...}],
name: "issueBounty",
outputs: [{...}],
payable: true,
stateMutability: "payable",
type: "function"
}, {
....
at: function(address, callback),
getData: function(),
new: function()

geth控制台获取字节码

将bin(已编译的二进制字节码)准备为变量。 注意,为了获得期望的十六进制值,我们需要在开头添加“ 0x”。

> var bountiesBin = "0x" + bountiesOutput.contracts["Bounties.sol:Bounties"].bin
undefined

开始部署

构造交易对象

  • 从coinbase账户发送
  • 交易数据
  • gas值
> var deployTransationObject = { from: eth.coinbase, data: bountiesBin, gas: 3000000 };
undefined

通过new构造交易实例(使用交易对象作为参数)

> var bountiesInstance = bountiesContract.new(deployTransationObject);
> bountiesInstance
{
abi: [{
constant: false,
inputs: [{...}, {...}],
name: "fulfillBounty",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [{...}, {...}],
name: "issueBounty",
outputs: [{...}],
payable: true,
stateMutability: "payable",
type: "function"
}, {
...}],
address: undefined,
transactionHash: "0xbeee5a5db59504c289e30a9843d8bf05bd0dcd66831993fde6a3986e2f022a52"
}

几段看不懂的翻译(对以太坊还不太熟)

因此,bountiesInstance是一个web3对象,代表部署到我们的开发环境中的bounties合同实例。

根据所用Geth版本的不同,合同实例中可能会或可能不会设置地址字段。 通常,这将在挖掘部署合同的事务时设置。

如果没有,因为上述地址字段设置为undefined,我们将必须手动设置合同地址

设置合同地址

如果合约中address为空,则需要手动设置合同地址

查看合同地址

我们可以通过查看部署合同交易的交易收据来找到合同地址。 我们的bountiesInstance对象将具有对transactionHash的引用。

eth.getTransactionReceipt(bountiesInstance.transactionHash);
{
blockHash: "0x565c4ebb83d9036518c33634d425f37b9ef3aa125e9b09386fbbdd44099892d9",
blockNumber: 1,
contractAddress: "0x1f81f1dd0de1670eac0bfa9e00a854733470d646",
cumulativeGasUsed: 911612,
gasUsed: 911612,
logs: [],
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
status: "0x1",
transactionHash: "0xbeee5a5db59504c289e30a9843d8bf05bd0dcd66831993fde6a3986e2f022a52",
transactionIndex: 0
}

上述可知,合同地址是0x565c4ebb83d9036518c33634d425f37b9ef3aa125e9b09386fbbdd44099892d9

创建指向正确合约地址的合约对象

> var bountiesAddress =  eth.getTransactionReceipt(bountiesInstance.transactionHash).contractAddress
> var bountiesInstance = bountiesContract.at(bountiesAddress)
undefined
> bountiesInstance
{
abi: [{
constant: false,
inputs: [{...}, {...}],
name: "fulfillBounty",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [{...}, {...}],
name: "issueBounty",
outputs: [{...}],
payable: true,
stateMutability: "payable",
type: "function"
}, {
...}],
address: "0x1f81f1dd0de1670eac0bfa9e00a854733470d646",
transactionHash: null,
BountyCancelled: function(),
BountyFulfilled: function(),
BountyIssued: function(),
FulfillmentAccepted: function(),
acceptFulfillment: function(),
allEvents: function(),
bounties: function(),
cancelBounty: function(),
fulfillBounty: function(),
issueBounty: function()

可见,合约地址已经设置成功

与合约交互

实则是合约部署好后,通过abi设置一个触发条件,用于自动执行合约
通过合约对象的 issueBounty 方法来设置触发条件,其参数有:

  • string_data:
  • unit64_deadline: 合约结束时间
  • data

命令类似如下:

> bountiesInstance.issueBounty("some requirements","1691452800",{ from: eth.accounts[0], value: web3.toWei(1, "ether"), gas: 3000000 });
"0xb3a41fa36c09010abbfa9bf80c3cd11242e4476506d6bf8b363b8feeb3cf946d"

> eth.getTransactionReceipt("0xb3a41fa36c09010abbfa9bf80c3cd11242e4476506d6bf8b363b8feeb3cf946d")
{
blockHash: "0x8acd35b251c3f1c23a6276540e73b958de28686a89367ed108bef9f614771099",
blockNumber: 5,
contractAddress: null,
cumulativeGasUsed: 133594,
gasUsed: 133594,
logs: [{
address: "0x1f81f1dd0de1670eac0bfa9e00a854733470d646",
blockHash: "0x8acd35b251c3f1c23a6276540e73b958de28686a89367ed108bef9f614771099",
blockNumber: 5,
data: "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c74a4fba809c8f0e6b410b349f2908a4dbb881230000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000011736f6d6520726571756972656d656e7473000000000000000000000000000000",
logIndex: 0,
topics: ["0xba1576d8891bfe57a45ac4b986d4a4aa912c62f44771d4eec8ab2ce06e3be5b7"],
transactionHash: "0xb3a41fa36c09010abbfa9bf80c3cd11242e4476506d6bf8b363b8feeb3cf946d",
transactionIndex: 0,
type: "mined"
}],
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000010000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
status: "0x1",
transactionHash: "0xb3a41fa36c09010abbfa9bf80c3cd11242e4476506d6bf8b363b8feeb3cf946d",
transactionIndex: 0
}

结果解读

上面是发出赏金交易的日志输出和显示交易已成功开采的交易收据。

因为这是第一个颁发的赏金,所以我们从合同代码中知道issueBounty函数将创建bountyId为0的赏金。

检查数据是否正确

现在我们知道了bountyId,我们可以调用bountiesInstance web3对象的bounties函数来仔细检查issueBounty函数是否正确存储了我们的数据

> bountiesInstance.bounties.call(0)
["0xc74a4fba809c8f0e6b410b349f2908a4dbb88123", 1691452800, "some requirements", 0, 1000000000000000000]

完事!!!!

总结

  • 编译出Bounties.sol智能合约
  • 将其部署到本地开发区块链
  • 通过发送交易来发放赏金
  • 通过致电合同签出赏金数据

题外

经过一系列的苦逼操作后,终于完成了一个智能合约的编译部署。
挺麻烦的,写智能合约就够苦逼了,编译部署还这么麻烦。
所以我们才需要框架,框架向我们隐藏了此过程的复杂性,让我们在开发dApp时专注于编写智能合约即可。
框架再推:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容