前言
本文主要基于 go-ethereum (以太坊官方 Golang 实现版本),演示 Golang 调用合约流程,以及区块链相关概念。
智能合约
所谓智能合约(Smart Contract),既不智能也没有任何法律约束力。其本质是运行在以太坊虚拟机(EVM)中的一段代码逻辑。
下面我们看一段简单的智能合约,使用 Solidity
编写。First Application
逻辑很简单,声明了一个 public 变量 count, 三个方法 分别是读取,加一,减一。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract Counter {
uint public count;
// Function to get the current count
function get() public view returns (uint) {
return count;
}
// Function to increment count by 1
function inc() public {
count += 1;
}
// Function to decrement count by 1
function dec() public {
count -= 1;
}
}
我们使用 Remix 部署该合约。
Golang 合约交互
与智能合约交互,我们要先生成相应智能合约的应用二进制接口 ABI (application binary interface),并把 ABI 编译成我们可以在Go应用中调用的格式。
1. 将合约转为 ABI
Counter 合约使用 Solidity 编写,我们使用 Solidity 官方提供的客户端 solc 导出 ABI。下载地址:solc
安装完成,运行:
solc --abi Counter.sol
将导出的json复制到新建文件 Counter.abi。
2. ABI 生成 Go 文件
使用 abigen 将 ABI 文件转为 Go 文件。 (abigen 工具在 go-ethereum 中,需先安装 go-ethereum)
运行:
abigen --abi=Counter.abi --pkg=counter --out=Counter.go
3. 调用合约
以下为完整代码,俺使用了英文注释。
- 使用币安测试链
- privateKey 需要设置你自己的私钥,保证上面有测试 BNB
- 测试合约地址,已部署。
- 发送交易,count+1
- 读取count值
package main
import (
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"goeth-demo/contracts/counter"
"log"
"math/big"
)
func main() {
// 1. use bsc testnet
client, err := ethclient.Dial("https://data-seed-prebsc-1-s1.binance.org:8545")
if err != nil {
log.Fatal(err)
}
// 2. put in your test private key, make sure it has bsc testnet BNB
privateKey, err := crypto.HexToECDSA("private key")
if err != nil {
log.Fatal(err)
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
// 3. contract address
address := common.HexToAddress("0x392698b12759AB3CB5dBADBFC1601a24d3d4b7aD")
instance, err := counter.NewCounter(address, client)
if err != nil {
log.Fatal(err)
}
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(97))
if err != nil {
log.Fatal(err)
}
transactOpts := &bind.TransactOpts{
From: fromAddress,
Nonce: auth.Nonce,
Signer: auth.Signer,
Value: big.NewInt(0),
GasPrice: auth.GasPrice,
GasLimit: auth.GasLimit,
Context: auth.Context,
NoSend: false,
}
// 4. send tx
tx, err := instance.Inc(transactOpts)
if err != nil {
log.Fatal(err)
}
log.Printf("tx sent: %s", tx.Hash().Hex())
// 5. get count
count, err := instance.Get(nil)
if err != nil {
log.Fatal(err)
}
log.Printf("count: %d", count)
}
完整代码参见:https://github.com/mangoim/goeth-demo
总结
go-ethereum 包含整个区块链功能,这里演示只是冰山一角。有兴趣的童鞋推荐去看用Go来做以太坊开发