美文网首页以太坊
Golang连接以太坊合约

Golang连接以太坊合约

作者: james_fan | 来源:发表于2018-04-23 16:40 被阅读1065次

    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);
        }
    }
    

    使用GanacheTruffle和编写和测试合约

    Ganache是一个个人的以太坊客户端,可以启动一个私有链用于开发测试的区块链环境。Truffle framework是一个使用非常广泛的智能合约开发框架,通过Truffle可以快速开发和测试合约。

    GanacheTruffle安装

    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 命令,程序便会生成如下图目录,需要注意的示目标文件夹必须是空文件夹:

    truffle-1.jpg

    contracts 目录存放合约文件,migrateions 目录,test 目录存放测试文件。
    初始化truffle目录后即可编写合约,详细用法可参考官方文档

    1. 在contracts文件夹下创建SuperCoin.sol文件,写入合约内容,solidity对于import引入方式比较糟糕,并且不同版本solidity语法还略有不同,库所使用的语法可能已经在最新版失效,建议使用过程中直接在node_modules/zeppelin-solidity找到对应需要继承的合约,复制到源码中进行最新版本适配和使用;
    2. migrateions文件夹下创建2_deploy_contracts.js文件,写入合约部署配置,此步骤是固定写法,不需要修改;
    3. 在部署成功后,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
        }
    }
    

    使用GethRemix编写和测试合约

    什么是Geth?官方解释是:Geth是用Go实现的命令行界面运行的完整功能以太坊节点。借助Geth实现:在主网络挖矿、地址间转账、创建合约和发送交易、浏览区块历史等功能。我们主要需要用Geth创建合约和发送交易等功能。

    Geth安装

    拉取go-ethereum源码,建议配置命令行科学上网后再尝试:go get -u github.com/ethereum/go-ethereum,go-ethereum是以太坊源码,我们用Golang连接以太坊合约需要便是要借助它来实现。

    Geth安装可运行命令行工具,官方分别给出来两个系统下安装包和源码两种方式:WindowsMac
    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-1.jpg

    更多参数可以使用geth -h方式查看。

    Remix介绍

    Remix是以太坊官方提供的在线合约构建和debug的IDE和工具集,项目地址: https://github.com/ethereum/remix-ide 、 在线工具: https://remix.ethereum.org
    下面简单介绍一下怎样用remix部署合约到前一步geth启动起来的dev环境:

    1. 创建coin.sol文件;
    2. 将编写好的合约代码置于代码区域;
    3. Environment选择Web3 Provider,此步骤将连接本地启动的dev环境;
    4. 选择我们要发布的合约SuperCoin
    5. 点击create按钮部署到dev环境;
    6. 下图2中区域6即为合约所提供到功能,输入相关内容点击按钮即可测试合约;
    7. 下图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文件。

    1. 创建coin.sol文件;
    2. 将编写好的合约代码置于代码区域;
    3. 选择我们要发布的合约SuperCoin
    4. 点击detail按钮;
    5. 找到图2所示abi内容,复制并存储于项目中对应的super_coin.abi文件。
      具体操作如下图
    gen-abi-1.jpg gen-abi-2.jpg

    使用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.goNewSuperCoin() 方法即可创建出来合约对象,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 运行在国外的服务器,实际上这个时候我们可以选择使用 InfuraInfura 可以给我们提供稳定的测试网络 RinkebyRopsten 和主网络 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

    相关文章

      网友评论

      本文标题:Golang连接以太坊合约

      本文链接:https://www.haomeiwen.com/subject/dtsllftx.html