go-connect-eth-contract
golang如何连接以太坊合约。近一段时间在学习以太坊智能合约,在学习过程中走了不少弯路,本文是对此处相关知识的总结希望可以帮助后来者少走弯路。
Solidity
合约编写
通过继承zeppelin-solidity提供的功能,编写一个ERC-20
代币合约,核心代码甚至只需要定义一下代币数量和名称。
在实际部署合约时候,建议将所有继承到的合约都直接Copy到了源码之中,这样做原因是Solidity目前对于import的支持还很弱,可以避免不必要到错误。在示例代码中为了便于理解,我也做了如上操作。
下面到这个合约SuperCoin
,主要除了定义了名称、数量之外,借助继承的合约还具备:白名单管理、铸币到白名单、铸币总量限制等功能,具体怎样实现上述功能可以自行查看源码,此处就不介绍Solidity到基础知识了。
contract SuperCoin is CappedToken, Whitelist {
string public name = "SuperCoin";
string public symbol = "SC";
uint8 public decimals = 18;
// 初始币量1亿5千万
uint256 public INITIAL_SUPPLY = 105000000 * (10 ** 18);
// 总币量2亿1千万
uint256 public CAP_SUPPLY = 210000000 * (10 ** 18);
// 每次最多铸币1024个
uint256 public ONCE_MAX_MINT = 1024 * (10 ** 18);
function SuperCoin() public CappedToken(CAP_SUPPLY) {
totalSupply_ = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
emit Transfer(0x0, msg.sender, INITIAL_SUPPLY);
}
function mint(address to, uint256 amount) onlyOwner canMint onlyWhitelisted(to) public returns (bool) {
if (amount > ONCE_MAX_MINT) {
amount = ONCE_MAX_MINT;
}
return super.mint(to, amount);
}
}
使用Ganache
和Truffle
和编写和测试合约
Ganache是一个个人的以太坊客户端,可以启动一个私有链用于开发测试的区块链环境。Truffle framework是一个使用非常广泛的智能合约开发框架,通过Truffle可以快速开发和测试合约。
Ganache
和Truffle
安装
Ganache官方提供的下载地址,下载安装允许即可不需要修改默认设置。
Truffle的目录结构跟Web项目相似度非常高,node_modules和Web一样是用来存放依赖库的目录,同样的安装依赖库也需要使用npm命令,安装方式请参考:npmjs
Trffule官方提供的安装方式便是借助npm的:
npm install -g truffle
zeppelin-solidity
安装
zeppelin-solidity
是开发基于ERC-20代币必须要用到的库,功能比较完善,通过继承这个库的合约,可以非常方便的实现ERC-20协议、铸币、白名单等常见的功能。
npm install -g zeppelin-solidity
安装按完成后即可通过import方式引入相关依赖合约:
import "zeppelin-solidity/contracts/token/ERC20/CappedToken.sol";
使用Truffle
编写和测试合约
安装完成Truffle后,cd到目标文件夹,执行 truffle init
命令,程序便会生成如下图目录,需要注意的示目标文件夹必须是空文件夹:
contracts 目录存放合约文件,migrateions 目录,test 目录存放测试文件。
初始化truffle目录后即可编写合约,详细用法可参考官方文档:
- 在contracts文件夹下创建
SuperCoin.sol
文件,写入合约内容,solidity对于import引入方式比较糟糕,并且不同版本solidity语法还略有不同,库所使用的语法可能已经在最新版失效,建议使用过程中直接在node_modules/zeppelin-solidity
找到对应需要继承的合约,复制到源码中进行最新版本适配和使用; - migrateions文件夹下创建
2_deploy_contracts.js
文件,写入合约部署配置,此步骤是固定写法,不需要修改; - 在部署成功后,test文件夹下创建和编写测试脚本,truffle提供了两种脚本文件类型,js文件和sol文件类型,合约运行过程中大部分都是异步操作,个人觉得js类型文件对于异步支持更好,具体测试脚本可以参考
/truffle/test
目录下提供的范例。
truffle compile // 构建合约,如果构建成功可以看到新增了build文件夹
truffle migrate // 部署合约
truffle test // 执行目录下所有测试文件
truffle test xxx_test.js // 测试某个test文件
使用truffle migrate
不是合约的时候可能会出现Error: No network specified. Cannot determine current network.
的错误,可以使用将下面配置测试网络的代码放到truffle.js
文件内即可。
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*" // Match any network id
}
}
使用Geth
和Remix
编写和测试合约
什么是Geth
?官方解释是:Geth是用Go实现的命令行界面运行的完整功能以太坊节点。借助Geth实现:在主网络挖矿、地址间转账、创建合约和发送交易、浏览区块历史等功能。我们主要需要用Geth创建合约和发送交易等功能。
Geth
安装
拉取go-ethereum
源码,建议配置命令行科学上网后再尝试:go get -u github.com/ethereum/go-ethereum
,go-ethereum是以太坊源码,我们用Golang连接以太坊合约需要便是要借助它来实现。
Geth安装可运行命令行工具,官方分别给出来两个系统下安装包和源码两种方式:Windows、Mac
Mac下我推荐使用源码方式安装:
cd $GOPATH/src/github.com/ethereum/go-ethereum
make geth
执行完毕上面两个步骤,如果没有报错, build/bin/geth 便是生成好的 geth 可执行文件。
需要注意等是源码方式安装完毕后,需要将可执行文件手动添加到环境变量。
启动Geth
客户端
正确执行上一步安装Geth,在命令行输入geth -h
可测试geth是否正确安装,也可以通过这个命令查看geth提供的工具。
使用全默认配置启动geth客户端,在命令行输入geth
回车执行即可,geth会默认启动一个主网络节点,并尝试连接到其他节点,开始同步全量的区块数据。
启动一个geth开发环境dev节点,这个是我们在本地使用最多的启动方式,命令如下:
geth --networkid=1234 --nodiscover --rpc --rpcport=8545 --ws --wsport=8546 --rpccorsdomain="*" --dev --dev.period 1 --datadir=/Users/james/eth/dev console 2>>eth_dev_log
命令 | 解释 |
---|---|
--networkid=1234 | 指定网络ID,只有网络ID一致等节点才可以相互链接,以太主网路网络ID是1,不设置情况下默认ID也是1 |
--nodiscover | 设置为不被其他节点发现 |
--rpc --rpcport=8545 | 开启RPC连接方式,并设置端口为8545 |
--rpccorsdomain="*" | RPC允许所有跨域连接,这个设置主要是为了Remix在线连接本地开发网络 |
--ws --wsport=8546 | 开启WebSocket连接方式,并设置端口为8546 |
--dev --dev.period 1 | 开启开发网络无交易时自动挖矿设置,如不添加此设置在没有新交易时,默认不自动挖矿 |
--datadir=/eth/dev | 设置节点区块数据本地磁盘路径,不设置时将使用默认路径 |
console | Geth启动后仍可接收命令行命令,如不开启又需要使用命令行也可以通过geth attach ipc:\\.\pipe\geth.ipc 方式连接到当前节点 |
console 2>>eth_dev_log | 将命令行操作记录输出到指定文件 |
启动的运行效果如下图,geth客户端运行起来后,类似于eth.blockNumber
的方法可以在:管理API查阅:
更多参数可以使用geth -h
方式查看。
Remix
介绍
Remix
是以太坊官方提供的在线合约构建和debug的IDE和工具集,项目地址: https://github.com/ethereum/remix-ide 、 在线工具: https://remix.ethereum.org
下面简单介绍一下怎样用remix部署合约到前一步geth启动起来的dev环境:
- 创建
coin.sol
文件; - 将编写好的合约代码置于代码区域;
- Environment选择
Web3 Provider
,此步骤将连接本地启动的dev环境; - 选择我们要发布的合约
SuperCoin
; - 点击create按钮部署到dev环境;
- 下图2中区域6即为合约所提供到功能,输入相关内容点击按钮即可测试合约;
- 下图2中区域7为每一次访问dev网络的记录,点击detail查看详细,点击debug调试功能。
具体操作如下图所示:
remix-1.jpg remix-2.jpg
Golang
连接合约
使用abigen
生成合约交互工具super_coin.go
ABI是程序的二进制接口。一般来说,ABI是两个程序模块之间的接口,而且通常其中一个程序处于机器级别。也就是说事实上ABI接口就是用于将数据编码/解码到机器代码的方法。
在以太坊上,就是通过ABI把Solidity合约写入到EVM,后续也是借助ABI来从事务中读取到数据的。
具体使用的来说,需要先获取到合约abi文件,再用abigen
工具生成super_coin.go
,最后程序调用super_coin.go
实现合约的部署、方法调用(白名单管理、铸币、转账、余额查询)等交互操作。
生成合约abi文件
可以借助前面提到的Remix工具生成abi文件。
- 创建
coin.sol
文件; - 将编写好的合约代码置于代码区域;
- 选择我们要发布的合约
SuperCoin
; - 点击detail按钮;
- 找到图2所示abi内容,复制并存储于项目中对应的
super_coin.abi
文件。
具体操作如下图
使用abigen
生成super_coin.go
abigen是go-ethereum一个内置工具,可以使用下面方法安装
cd $GOPATH/src/github.com/ethereum/go-ethereum
godep go install ./cmd/abigen
abigen --abi super_coin.abi --pkg coin --type SuperCoin --out super_coin.go
命令 | 解释 |
---|---|
--abi super_coin.abi | 指定abi文件来源 |
--pkg coin | 指定输出文件的包名 |
--type SuperCoin | 指定合约结构体名称 |
--out super_coin.go | 指定合约交互文件名称 |
更多使用方法可使用abigen -h
命令来查看。
使用super_coin.go
实现与合约交互
如下面代码,ethclient.Dial()
创建出来和以太坊的链接,再将这个链接传入 super_coin.go
的 NewSuperCoin()
方法即可创建出来合约对象,super_coin.go
提供了几乎所有程序需要和合约交互的方法,详细使用可以查看示例代码 connecter.go 。或查阅 官方文档。
var (
coinAddr = common.HexToAddress("0x5A4E05aCd772BAe3109e6C424907BE9F4e35b6Db")
coinHash = coinAddr.Hash()
)
// Connecter SuperCoin连接者
type Connecter struct {
ctx context.Context
conn *ethclient.Client
coin *SuperCoin
}
// NewConnecter 生成一个SuperCoin连接者
func NewConnecter() *Connecter {
// Dial这里支持传入 ws、http、ipc的多种链接
// 如果是经常需要调用最好还是使用 ws 方式保持通讯状态
conn, err := ethclient.Dial("ws://127.0.0.1:8546")
if err != nil {
panic(err)
}
coin, err := NewSuperCoin(coinAddr, conn)
if err != nil {
panic(err)
}
return &Connecter{
ctx: context.Background(),
conn: conn,
coin: coin,
}
}
借助Infura
连接主网络或测试网络
项目开发过程中,测试阶段使用dev网络是没问题的,开发完毕后我们需要在测试运行,以及正式部署运行,这时候往往会发现 geth 运行起来的节点如果在国内的服务器上,经常会出现链接不到节点,或者链接不稳定的情况。这个时候你可能会考虑将 geth 运行在国外的服务器,实际上这个时候我们可以选择使用 Infura
, Infura
可以给我们提供稳定的测试网络 Rinkeby
、Ropsten
和主网络 Mainnet
的链接,使用也毫无门槛,只需要如下将 ethclient.Dial()
url替换即可。
官网地址: http://infura.io/
conn, err := ethclient.Dial("https://mainnet.infura.io/LQ........bg")
if err != nil {
panic(err)
}
源码
文中所有源码均已上传至Github:https://github.com/finejian/go-connect-eth-contract
网友评论