go-eth

前言

本文主要基于 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. 调用合约

以下为完整代码,俺使用了英文注释。

  1. 使用币安测试链
  2. privateKey 需要设置你自己的私钥,保证上面有测试 BNB
  3. 测试合约地址,已部署。
  4. 发送交易,count+1
  5. 读取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来做以太坊开发