golang与以太坊交互

文章目录

  • golang与以太坊交互
    • 什么是go-ethereum
    • 与节点交互前的准备
    • 使用golang与以太坊区块链交互
    • 查询账户的余额
    • 使用golang生成以太坊账户
    • 使用golang生成以太坊钱包
    • 使用golang在账户之间转移eth
    • 安装使用solc和abigen
    • 生成bin和abi文件
    • 生成go文件
    • 使用golang在测试网上部署智能合约
    • 使用goalng与智能合约进行交互
    • 使用golang在Etherscan上验证合约

golang与以太坊交互

阅读此文章前,需要你了解go,solidity,ethereum相关基础知识。

Golang基础入门-CSDN博客

go语言–区块链学习(三)_go区块链合约-CSDN博客

MetaMask安装及使用(全网最全!!!)_matemask-CSDN博客

Solidity基础(详细易懂!!!)_solidity教程-CSDN博客

在以太坊测试网上部署合约_将智能合约部署至以太坊测试网-CSDN博客

此篇文章参考于01-Interact with Ethereum blockchain using Golang (youtube.com),博主在视频代码的基础上进行了些改进,修改了一些被弃用的包和函数,并结合自己的理解写下了这篇博客。

什么是go-ethereum

Geth (go-ethereum) 是以Go语言实现的以太坊——通往去中心化网络的门户。

自始至终,Geth 一直是以太坊的核心部分。作为最早的以太坊实现之一,Geth 经历了最多的实战检验和测试。

Geth 是一个以太坊执行客户端,负责处理交易、智能合约的部署和执行,内置了被称为以太坊虚拟机的嵌入式计算机。将 Geth 与共识客户端一起运行,可以将一台计算机转变为以太坊节点。

与节点交互前的准备

前面提到,将 Geth 与共识客户端一起运行,可以将一台计算机转变为以太坊节点,这样做,可以为我们带来什么?

运行自己的节点使您能够以真正私密、自给自足和无需信任的方式使用以太坊。您无需信任接收到的信息,因为可以通过您的 Geth 实例自行验证数据。

这样你就可以直接利用自己的节点提供的 rpc 地址直接与以太坊网络进行交互了。但是,对于一般的个人开发者来说,运营一台以太坊节点服务器,成本可能有些许高昂。

并且,由于高昂的 gas 费用,我们在开发过程中的测试,不可能是在以太坊主网上测试的。我们在实际开发过程中,可以启动本地 Geth 测试网或者用 Ganache 快速启动一条测试链,做本地开发测试,但是这并不能涵盖所有的以太坊网络上的可能性。

为了模拟更真实的以太坊网络环境,帮助我们更好地去构建我们的 dapp,我们可以选择与以太坊测试网络进行交互,做开发测试。

如何与测试网交互?同样,将自己的设备作为以太坊节点(测试网节点)还是过于繁琐,下面介绍一项第三方托管服务。

Infura 是一项托管服务,提供安全可靠的访问多种区块链网络的能力,帮助开发者摆脱管理区块链基础设施的复杂性,让他们专注于构建创新的 Web3 应用程序。

Infura 充当了连接应用程序与区块链网络的重要桥梁,为开发者提供强大的API以与区块链进行交互、部署和管理智能合约等功能。无论您是构建去中心化应用程序(Dapp)、加密钱包还是交易所,Infura都提供了必要的基础设施和工具,帮助创建高质量、可靠的 Web3 应用程序。

首先,我们来到 Infura 的官网(不要开代理):Ethereum API | IPFS API & Gateway | ETH Nodes as a Service | Infura

注册登录,选择以太坊服务,选择免费的 Infura 服务。

接下来,会进入到我们的面板,点击 My First Key,查看你的 api 密钥。

请添加图片描述

如果一开始注册过程中未选择以太坊的服务,也不要紧,这里勾选一下就好了,然后点击 Active Endpoints。

请添加图片描述

然后你就可以看到你可以使用的 rpc 地址了,这里我们只需要主网和 sepolia 测试网的就可以了。

在这里插入图片描述

使用golang与以太坊区块链交互

接下来,我们将利用 Infura 提供的 rpc 地址,去获取 sepolia 测试网上当前的区块高度。

代码:

package main

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/ethclient" // 导入以太坊客户端库
	"log"
)

var infuraURL = "https://sepolia.infura.io/v3/********************************" // Infura提供的API URL

func main() {
	// 使用Infura URL连接以太坊客户端
	client, err := ethclient.DialContext(context.Background(), infuraURL)
	if err != nil {
		log.Fatalf("Error to create a ether client:%v", err) // 如果连接失败,打印错误并终止程序
	}
	defer client.Close() // 程序结束前关闭客户端连接

	// 获取最新区块
	block, err := client.BlockByNumber(context.Background(), nil)
	if err != nil {
		log.Fatalf("Error to get a block:%v", err) // 如果获取区块失败,打印错误并终止程序
	}
	fmt.Println(block.Number()) // 打印区块号
}

然后我们编译运行一下代码。

在这里插入图片描述

可以看到,区块链浏览器上显示的最后一个区块也是6248296。TESTNET Sepolia (ETH) Blockchain Explorer (etherscan.io)

在这里插入图片描述

查询账户的余额

接下来,我们去获取我们的账户余额,打开我们的metamask,复制我们的账户地址,写入代码,编译运行。

代码:

package main

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/common" // 导入以太坊常用函数库
	"github.com/ethereum/go-ethereum/ethclient" // 导入以太坊客户端库
	"log"
	"math"
	"math/big"
)

var infuraURL = "https://sepolia.infura.io/v3/********************************" // Infura提供的API URL

func main() {
	// 使用Infura URL连接以太坊客户端
	client, err := ethclient.DialContext(context.Background(), infuraURL)
	if err != nil {
		log.Fatalf("Error to create a ether client:%v", err) // 如果连接失败,打印错误并终止程序
	}
	defer client.Close() // 程序结束前关闭客户端连接

	// 要查询余额的以太坊地址
	addr := "0x****************************************"
	address := common.HexToAddress(addr)

	// 获取地址的余额
	balance, err := client.BalanceAt(context.Background(), address, nil)
	if err != nil {
		log.Fatalf("Error to get the balance:%v", err) // 如果获取余额失败,打印错误并终止程序
	}
	fmt.Println("The balance:", balance)

	// 将余额转换为以太单位(从wei到ether)
	// 1 ether = 10^18 wei

	// 将balance转换为big.Float类型以处理大数
	fBalance := new(big.Float)
	fBalance.SetString(balance.String())

	// 打印原始的big.Float格式的余额
	fmt.Println("Balance as big.Float:", fBalance)

	// 计算以ether为单位的余额
	balanceEther := new(big.Float).Quo(fBalance, big.NewFloat(math.Pow10(18)))
	fmt.Println("Balance in ether:", balanceEther)
}

这样,我们就可以看到我们的账户余额了。

在这里插入图片描述

使用golang生成以太坊账户

当您想要创建一个账户时,大多数库会为您生成一个随机的私钥。

私钥由64个十六进制字符组成,并且可以用密码加密。

公钥是使用椭圆曲线数字签名算法从私钥生成的。您可以通过取公钥的 Keccak-256 哈希的最后20个字节并在开头添加 0x 来获得您账户的公共地址。

接下来是使用 golang 生成一个账户的代码。

代码:

package main

import (
	"fmt"
	"github.com/ethereum/go-ethereum/common/hexutil" // 导入以太坊的hex编解码包
	"github.com/ethereum/go-ethereum/crypto" // 导入以太坊的加密库
	"log"
)

func main() {
	// 生成一个新的以太坊私钥
	pvk, err := crypto.GenerateKey()
	if err != nil {
		log.Fatal(err) // 如果生成私钥时出现错误,打印错误信息并退出程序
	}

	// 将私钥转换为字节格式,并以hex编码方式打印出来
	pData := crypto.FromECDSA(pvk)
	fmt.Println(hexutil.Encode(pData))

	// 将公钥部分(从私钥派生而来)转换为字节格式,并以hex编码方式打印出来
	puData := crypto.FromECDSAPub(&pvk.PublicKey)
	fmt.Println(hexutil.Encode(puData))

	// 使用公钥生成对应的以太坊地址,并以hex编码方式打印出来
	fmt.Println(crypto.PubkeyToAddress(pvk.PublicKey).Hex())
}

获得的账户私钥是可以直接导入你的 metamask 的,不用担心会生成一个被使用过的账户。

(这里的私钥只是作为演示,我是不用的,我没打码,大家不要直接拿来用,造成的财产损失,博主概不负责,大家请妥善保管好自己的私钥)

在这里插入图片描述

在这里插入图片描述

使用golang生成以太坊钱包

除了使用 crypto.GenerateKey() 生成以太坊账户的私钥之外,还有一种更安全的方式,即使用 keystore 库。这个库将账户的私钥安全地存储在操作系统的文件系统中。私钥通常以 JSON 格式编码,并使用密码加密,以确保在存储和传输过程中的安全性。

设计 keystore 库的初衷之一是安全地管理以太坊账户的私钥,并避免将私钥直接硬编码在代码中。直接在代码中使用私钥存在许多安全风险,例如私钥泄露或意外提交到版本控制系统中,这可能导致资产损失或被恶意利用。使用 keystore 可以将私钥安全地存储在操作系统的文件系统中,并使用密码加密,只在必要时才解密和使用私钥,从而增强了私钥管理的安全性。

keystore 库使得以太坊开发者能更便捷地管理私钥和账户,提供了一种安全且标准化的方法来处理与以太坊账户相关的加密操作和文件存储需求。

代码:

package main

import (
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/keystore" // 导入以太坊账户管理和密钥存储库
	"log"
)

func main() {
	// 创建一个新的 keystore 实例,将密钥存储在当前目录下的 "wallet" 文件夹中
	key := keystore.NewKeyStore("./wallet", keystore.StandardScryptN, keystore.StandardScryptP)

	password := "password" // 设置用于加密私钥的密码

	// 使用指定的密码创建一个新的以太坊账户
	a, err := key.NewAccount(password)
	if err != nil {
		log.Fatal(err) // 如果创建账户时出现错误,打印错误信息并退出程序
	}

	// 打印新创建账户的以太坊地址
	fmt.Println(a.Address.Hex())
}

这样我们就得到了一个加密后的账户,可以看到,在我们的 wallet 文件夹下,有我们的密钥文件。

在这里插入图片描述

因为 goland 默认用 .txt 格式打开这个密钥文件,所以格式不如人意,我们可以在 Settings->File Types->JSON 里面添加文件名通配类型。

UTC--*-*-*T*-*-*.*Z--*
或
UTC--*

在这里插入图片描述

完成之后,可以看到我们的文件显示,已经变成高亮了。

在这里插入图片描述

接下来按住Ctrl+Alt+L,格式化代码,就可以看的更舒服一点了。

在这里插入图片描述

然后,接下来,我们来使用这个密钥文件,从里面拿出我们的私钥、公钥和钱包地址。

代码:

package main

import (
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"log"
	"os"
)

func main() {
	//key := keystore.NewKeyStore("./wallet", keystore.StandardScryptN, keystore.StandardScryptP)
	password := "password"
	//a, err := key.NewAccount(password)
	//if err != nil {
	//	log.Fatal(err)
	//}
	//fmt.Println(a.Address)

	// 使用已存在的密钥文件进行解密
	b, err := os.ReadFile("./wallet/UTC--****-**-**T**-**-**.**********--****************************************") // 读取密钥文件
	if err != nil {
		log.Fatal(err)
	}
	key, err := keystore.DecryptKey(b, password) // 解密密钥文件
	if err != nil {
		log.Fatal(err)
	}

	// 获取私钥的字节表示,并打印出来
	pData := crypto.FromECDSA(key.PrivateKey)
	fmt.Println("Priv", hexutil.Encode(pData))

	// 获取公钥的字节表示,并打印出来
	pData = crypto.FromECDSAPub(&key.PrivateKey.PublicKey)
	fmt.Println("Pub", hexutil.Encode(pData))

	// 获取以太坊地址,并打印出来
	fmt.Println("Add", crypto.PubkeyToAddress(key.PrivateKey.PublicKey).Hex())
}

编译运行后我们就可以拿到我们的私钥、公钥和账户地址了。

在这里插入图片描述

使用golang在账户之间转移eth

我们先使用 keystore 创建两个以太坊账户,也可以只创建一个,因为上一步已经创建了一个账户。

代码:

package main

import (
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"log"
)

func main() {
	// 用 keystore 创建两个以太坊账户的密钥文件
	ks := keystore.NewKeyStore("./wallet", keystore.StandardScryptN, keystore.StandardScryptP)
	_, err := ks.NewAccount("password")
	if err != nil {
		log.Fatal(err)
	}
	_, err = ks.NewAccount("password")
	if err != nil {
		log.Fatal(err)
	}
}

然后我们使用 metamask 往一个账户里面转点 SepoliaETH。

记得转点,就直接往账户地址里面转就行了。

代码:

package main

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
	"log"
	"math/big"
	"os"
)

var url = "https://sepolia.infura.io/v3/********************************" // Infura提供的API URL

func main() {
	// 客户端连接到以太坊节点
	client, err := ethclient.Dial(url)
	if err != nil {
		log.Fatal(err)
	}

	// a1,a2为刚刚创建的两个以太坊账户地址
	a1 := common.HexToAddress("****************************************")
	a2 := common.HexToAddress("****************************************")

	// 查询第一个地址的余额
	b1, err := client.BalanceAt(context.Background(), a1, nil)
	if err != nil {
		log.Fatal(err)
	}

	// 查询第二个地址的余额
	b2, err := client.BalanceAt(context.Background(), a2, nil)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Balance 1:", b1)
	fmt.Println("Balance 2:", b2)

	// 获取第一个地址的待处理交易数量(nonce)
	nonce, err := client.PendingNonceAt(context.Background(), a1)
	if err != nil {
		log.Fatal(err)
	}

	// 设置要发送的以太币数量(1 ether = 1000000000000000000 wei)
	amount := big.NewInt(1000000000000000)

	// 获取推荐的 gas 价格
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 创建新的交易
	tx := types.NewTx(&types.LegacyTx{
		Nonce:    nonce,
		To:       &a2,
		Value:    amount,
		Gas:      21000,
		GasPrice: gasPrice,
		Data:     nil,
	})

	// 获取当前链的 ID
	chainID, err := client.NetworkID(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 从密钥文件中解密私钥
	b, err := os.ReadFile("./wallet/UTC--****-**-**T**-**-**.**********--****************************************") // 有余额的账户的密钥文件
	if err != nil {
		log.Fatal(err)
	}
	key, err := keystore.DecryptKey(b, "password")
	if err != nil {
		log.Fatal(err)
	}

	// 使用私钥对交易进行签名
	tx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)
	if err != nil {
		log.Fatal(err)
	}

	// 发送交易到以太坊网络
	err = client.SendTransaction(context.Background(), tx)
	if err != nil {
		log.Fatal(err)
	}

    // 打印该交易的交易哈希
	fmt.Printf("tx semt: %s\n", tx.Hash().Hex())

    // 打印交易后,两个账户的剩余余额
	fmt.Println("Balance 1:", b1)
	fmt.Println("Balance 2:", b2)
}

下面是结果截图,我用的是我之前测试的账户地址。
在这里插入图片描述

我们也可以去区块链浏览器上查看这笔交易。TESTNET Sepolia (ETH) Blockchain Explorer (etherscan.io)

在这里插入图片描述

知识点补充:

nonce

在以太坊中,nonce(Number used ONCE,一次性数字)是与每个发送者账户相关联的整数,用于确保交易顺序和唯一性。每个账户的 nonce 值是账户发送的交易数量加一,从零开始。这意味着每笔交易必须使用正确的 nonce ,以确保它们按正确的顺序执行且不会被重放。

具体来说:

  • Nonce 的作用:Nonce 确保在发送交易时,每笔交易都有唯一的标识符。它防止了重放攻击,因为同样的交易数据使用不同的 nonce 会被认为是不同的交易。
  • 获取 Nonce:通过调用以太坊客户端的 PendingNonceAt 方法,可以获取指定账户当前待处理的 nonce 值。这个方法返回的 nonce 是在该账户发送的交易队列中尚未被打包进块中的数量。在创建新交易时,通常会使用此 nonce 值加一作为新交易的 nonce。

例如,对于以下代码片段:

nonce, err := client.PendingNonceAt(context.Background(), a1)

这段代码会查询账户 a1 当前的待处理交易数量(即nonce),并将其赋值给 nonce 变量。

gas费

在以太坊中,gasPrice 是指愿意支付每单位 gas 的以太币数量,用于衡量交易的成本。Gas 本质上是执行智能合约或发送交易所需的计算资源。GasPrice 决定了矿工愿意为每单位 gas 支付多少以太币来处理你的交易。

具体来说:

  • GasPrice 的作用:GasPrice 影响到你的交易被矿工选择打包进区块的速度。较高的 GasPrice 意味着交易更有可能快速被矿工处理,因为矿工有动机选择收益更高的交易。
  • 获取推荐 GasPrice:以太坊客户端提供了一个方法 SuggestGasPrice,用于推荐当前网络上合理的 GasPrice。这个推荐的 GasPrice 通常是基于当前网络上最近几个区块中包含交易的 GasPrice 的中位数或平均值。

例如,对于以下代码片段:

gasPrice, err := client.SuggestGasPrice(context.Background())

这段代码会调用以太坊客户端的 SuggestGasPrice 方法来获取当前推荐的 GasPrice,并将其赋值给 gasPrice 变量。

安装使用solc和abigen

什么是 solc,什么是 abigen?

Solc 是 Solidity 编译器的命令行接口。Solidity 是一种用于编写智能合约的高级语言,solc 则是将 Solidity 代码编译成 Ethereum 虚拟机(EVM)可以执行的字节码的工具。solc 提供了将 Solidity 代码转换为 EVM 字节码的功能,这些字节码可以部署到以太坊区块链上执行。

Abigen 是一个工具,用于从 Solidity 合约 ABI 文件生成 Go 语言绑定代码。ABI(Application Binary Interface)文件定义了合约与外部世界的接口规范,包括合约的方法、参数和返回值类型等信息。Abigen 接收 ABI 文件作为输入,并生成相应的 Go 语言代码,这些代码可以用于与 Solidity 合约进行交互,方便在 Go 语言中调用和操作以太坊智能合约。

solc下载:

Release Version 0.8.26 · ethereum/solidity (github.com)

找到所需要的系统版本下载安装就可以了,这里就以windows举例。

在这里插入图片描述

下载后,将 solc-windows.exe 改名为 solc.exe,没有为什么,只是为了输入命令方便。

然后将其放入一个已经配置在系统环境变量中的路径下,这一点很重要,这样无论在哪个路径下都可以使用 solc 命令了。

abigen下载:

如果你已经执行过下面的命令,没执行过,那就是前面的代码没有验证,只要跑过前面的代码,这个包都是已经拉过的。

go get github.com/ethereum/go-ethereum

那么请打开你的 cmd,输入 go env,找到 GOMODCACHE 路径,打开它,找到 github.com\ethereum 下的名称为 go-ethereum 的文件夹,可能会为 go-ethereum@版本号。

一般就在 %UserProfile%\go\pkg\mod\github.com\ethereum 下面

在这里插入图片描述

在这里插入图片描述

然后打开 cmd,切换进 go-ethereum目录,然后输入以下命令。

go run build/ci.go install ./cmd/abigen

这样我们就可以在 go-ethereum/build/bin 下找到 abigen.exe 了。

在这里插入图片描述

然后将其放入一个已经配置在系统环境变量中的路径下,这一点很重要,这样无论在哪个路径下都可以使用 abigen 命令了。

补充:

这里我就随便创建了一个 D:/cmd 的文件夹,然后把 solc.exe 和 abigen.exe 放进去,然后在系统环境变量中配置了一下这个路径。

在这里插入图片描述

在这里插入图片描述

生成bin和abi文件

首先,随便写一个 todo.sol 文件,放在 contract 文件夹中。

代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

contract Todo{
    address owner;
    Task[] tasks;

    struct Task{
        string content;
        bool status;
    }

    constructor(){
        owner = msg.sender;
    }

    modifier isOwner(){
        require(owner == msg.sender);
        _;
    }

    function add(string memory _content) public isOwner {
        tasks.push(Task(_content,false));
    }

    function get(uint _id) public isOwner view returns (Task memory) {
        return tasks[_id];
    }

    function list() public isOwner view returns (Task[] memory){
        return tasks;
    }

    function update(uint _id, string memory _content) public isOwner {
        tasks[_id].content = _content;
    }

    function remove(uint _id) public isOwner {
        for(uint i = _id; i<tasks.length -1; i++){
            tasks[i] = tasks[i+1];
        }
        tasks.pop();
    }
}

然后打开终端,输入:

solc --bin --abi contract/todo.sol -o build

在这里插入图片描述

这样,我们就可以在 build 文件夹下,找到我们生成的 abi 和 bin 文件。

补充:

goland 安装 solidity 插件,在 settings->Plugins,实际上没有啥用,就是图一个好看,真正编写 solidity 还是得看 remix。

在这里插入图片描述

生成go文件

我们现在有了 abi,bin 文件,也有了abigen工具,接下来我们就可以生成相应的 go 文件了。

先创建一个 gen 文件夹。

打开命令行,输入:

abigen -bin build/Todo.bin -abi build/Todo.abi -pkg todo -out gen/todo.go

在这里插入图片描述

有了这个go文件,我们就可以调用和操作以太坊智能合约了。

使用golang在测试网上部署智能合约

接下来,我们使用之前创建的账户去调用 todo.DeployTodo() 函数就可以了。(需要有足够的SepoliaETH)

代码:

package main

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	todo "go-ether-learn/gen"
	"log"
	"math/big"
	"os"
)

func main() {
	// 读取以太坊钱包文件
	b, err := os.ReadFile("./wallet/UTC--****-**-**T**-**-**.**********--****************************************")
	if err != nil {
		log.Fatal(err)
	}

	// 解密钱包文件,获取私钥
	key, err := keystore.DecryptKey(b, "password")
	if err != nil {
		log.Fatal(err)
	}

	// 连接以太坊节点
	client, err := ethclient.Dial("https://sepolia.infura.io/v3/********************************")
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	// 获取钱包地址
	add := crypto.PubkeyToAddress(key.PrivateKey.PublicKey)

	// 获取交易的nonce值
	nonce, err := client.PendingNonceAt(context.Background(), add)
	if err != nil {
		log.Fatal(err)
	}

	// 获取建议的gas价格
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 获取网络的chainID
	chainID, err := client.NetworkID(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 创建交易签名者
	auth, err := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID)
	if err != nil {
		log.Fatal(err)
	}
	auth.GasPrice = gasPrice
	auth.GasLimit = uint64(3000000)
	auth.Nonce = big.NewInt(int64(nonce))

	// 部署智能合约
	a, tx, _, err := todo.DeployTodo(auth, client)
	if err != nil {
		log.Fatal(err)
	}

	// 打印部署结果
	fmt.Println("-----------------------------------")
	fmt.Println(a.Hex())             // 合约部署的地址
	fmt.Println(tx.Hash().Hex())     // 交易哈希
	fmt.Println("-----------------------------------")
}

接下来我们编译运行一下。(白天部署的gas费有点贵,建议晚上部署试试)

在这里插入图片描述

然后,我们可以在区块链浏览器上查看这个合约。TESTNET Sepolia (ETH) Blockchain Explorer (etherscan.io)

在这里插入图片描述

使用goalng与智能合约进行交互

最后,我们就可以使用goalng与智能合约进行交互了,因为没有多少SepoliaETH币了,就不演示了,大家可以自己尝试着交互一下。

代码:

package main

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	todo "go-ether-learn/gen"
	"log"
	"os"
)

func main() {
	// 读取以太坊钱包文件
	b, err := os.ReadFile("./wallet/UTC--****-**-**T**-**-**.**********--****************************************")
	if err != nil {
		log.Fatal(err)
	}

	// 解密钱包文件,获取私钥
	key, err := keystore.DecryptKey(b, "password")
	if err != nil {
		log.Fatal(err)
	}

	// 连接以太坊节点
	client, err := ethclient.Dial("https://sepolia.infura.io/v3/********************************")
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	// 获取当前链的 ID
	chainID, err := client.NetworkID(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 获取建议的gas价格
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// 转换合约地址为公共地址(合约地址为上一节部署合约的合约部署地址)
	cAdd := common.HexToAddress("0x****************************************")
	t, err := todo.NewTodo(cAdd, client)
	if err != nil {
		log.Fatal(err)
	}

	// 创建一个交易对象,设置链 ID、gas 限制和gas 价格
	tx, err := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID)
	if err != nil {
		log.Fatal(err)
	}
	tx.GasLimit = 3000000
	tx.GasPrice = gasPrice

	// 调用 Todo 合约的 Add 方法
	tra, err := t.Add(tx, "First Task")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(tra.Hash())

	// 调用 Todo 合约的 List 方法(不消耗gas)
	//add := crypto.PubkeyToAddress(key.PrivateKey.PublicKey)
	//tasks, err := t.List(&bind.CallOpts{
	//	From: add,
	//})
	//if err != nil {
	//	log.Fatal(err)
	//}
	//fmt.Println(tasks)

	// 调用 Todo 合约的 Update 方法
	//tra, err := t.Update(tx, big.NewInt(0), "update task content")
	//if err != nil {
	//	log.Fatal(err)
	//}
	//fmt.Println("Toggle tx", tra.Hash())

	// 调用 Todo 合约的 Remove 方法
	//tra, err := t.Remove(tx, big.NewInt(0))
	//if err != nil {
	//	log.Fatal(err)
	//}
	//fmt.Println("Toggle tx", tra.Hash())
}

到这里为止,你已经掌握了如何使用go去调用智能合约,与以太坊网络进行交互,可以开始尝试构建属于你的dapp了,希望这篇文章对你有所帮助。

使用golang在Etherscan上验证合约

还没造,等几天。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/776639.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GD32MCU如何实现掉电数据保存?

大家在GD32 MCU应用时&#xff0c;是否会碰到以下应用需求&#xff1a;希望在MCU掉电时保存一定的数据或标志&#xff0c;用以记录一些关键的数据。 以GD32E103为例&#xff0c;数据的存储介质可以选择内部Flash或者备份数据寄存器。 如下图所示&#xff0c;片内Flash具有10年…

【综合能源】计及碳捕集电厂低碳特性及需求响应的综合能源系统多时间尺度调度模型

目录 1 主要内容 2 部分程序 3 实现效果 4 下载链接 1 主要内容 本程序是对《计及碳捕集电厂低碳特性的含风电电力系统源-荷多时间尺度调度方法》方法复现&#xff0c;非完全复现&#xff0c;只做了日前日内部分&#xff0c;并在上述基础上改进升级为电热综合电源微网系统&…

力扣习题--找不同

目录 前言 题目和解析 1、找不同 2、 思路和解析 总结 前言 本系列的所有习题均来自于力扣网站LeetBook - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台 题目和解析 1、找不同 给定两个字符串 s 和 t &#xff0c;它们只包含小写字母。 字符串 t…

智能光伏开发都能用到什么软件和工具?

随着全球对可再生能源的日益重视和光伏技术的快速发展&#xff0c;智能光伏开发已成为推动能源转型的重要力量。在光伏项目的全生命周期中&#xff0c;从设计、建设到运营管理&#xff0c;各种软件和工具的应用发挥着至关重要的作用。 一、光伏系统设计软件 1、PVsyst PVsyst…

Python创建MySQL数据库

一、使用Docker部署本地MySQL数据库 docker run --restartalways -p 3307:3306 --name mysql -e MYSOL_ROOT_PASSWORDlms123456 -d mysql:8.0.25 参数解析: 用户名:root 密码:lms123456 端口:3307 二、在Pycharm开发工具中配置连接MySQL数据库 三、安装zdppy_mysql pip inst…

【LabVIEW学习篇 - 2】:LabVIEW的编程特点

文章目录 LabVIEW的编程特点图形编程天然并行运行基于数据流运行 LabVIEW的编程特点 图形编程 LabVIEW使用图形化的图形化编程语言&#xff08;G语言&#xff09;&#xff0c;用户通过在程序框图中拖放和连接各种节点&#xff08;Nodes&#xff09;来编写程序。每个节点代表一…

tobias实现支付宝支付

tobias是一个为支付宝支付SDK做的Flutter插件。 如何使用 你需要在pubspec.yaml中配置url_scheme。url_scheme是一个独特的字符串&#xff0c;用来重新启动你的app&#xff0c;但是请注意字符串“_”是不合法的。 在iOS端&#xff0c;你还需要配置并传入一个universal link。…

动手学深度学习(Pytorch版)代码实践 -循环神经网络-53语言模型和数据集

53语言模型和数据集 1.自然语言统计 引入库和读取数据&#xff1a; import random import torch from d2l import torch as d2l import liliPytorch as lp import numpy as np import matplotlib.pyplot as plttokens lp.tokenize(lp.read_time_machine())一元语法&#xf…

利用Redis bitmap 实现签到案例

数据库实现 设计签到功能对应的数据库表 CREATE TABLE sign_record (id bigint NOT NULL AUTO_INCREMENT COMMENT 主键,user_id bigint NOT NULL COMMENT 用户id,year year NOT NULL COMMENT 签到年份,month tinyint NOT NULL COMMENT 签到月份,date date NOT NULL COMMENT 签…

物联网行业等保有什么要求

中国网络安全等级保护制度&#xff08;简称“等保”&#xff09;对物联网行业有特定的要求&#xff0c;以确保物联网系统的安全性。等保2.0在原有安全通用要求的基础上&#xff0c;增加了针对新技术如云计算、物联网、移动互联网等的扩展要求。以下是一些关键的物联网安全扩展要…

C语言编译和编译预处理

编译预处理 • 编译是指把高级语言编写的源程序翻译成计算机可识别的二进制程序&#xff08;目标程序&#xff09;的过程&#xff0c;它由编译程序完成。 • 编译预处理是指在编译之前所作的处理工作&#xff0c;它由编译预处理程序完成 在对一个源程序进行编译时&#xff0c;…

小红书矩阵系统源码:赋能内容创作与电商营销的创新工具

在内容驱动的电商时代&#xff0c;小红书凭借其独特的社区氛围和用户基础&#xff0c;成为品牌营销和个人创作者不可忽视的平台。小红书矩阵系统源码&#xff0c;作为支撑这一平台的核心技术&#xff0c;提供了一系列的功能和优势&#xff0c;助力用户在小红书生态中实现更高效…

简体一键转繁体,智能命名神器,轻松将文件名翻译为繁体中文并精准复制至指定文件夹!

在信息爆炸的时代&#xff0c;文件管理和命名变得愈发重要。你是否曾经因为文件名混乱、不易识别而头疼不已&#xff1f;是否想要让文件名称更符合你的阅读习惯&#xff0c;却又因为语言转换的繁琐而望而却步&#xff1f;今天&#xff0c;我们为你带来了一款文件改名神器——文…

S32DS S32 Design Studio for S32 Platform 3.5 软件安装离线激活

问题描述 重新下载安装 NXP s32系列芯片的集成开发环境&#xff08;IDE&#xff09; S32DS S32 Design Studio&#xff0c;当前版本 S32 Design Studio for S32 Platform 3.5&#xff0c;安装时遇到激活问题 在线激活&#xff0c;激活码哪里来&#xff1f; s32ds 不是免费的&a…

python: create Envircomnet in Visual Studio Code 创建虚拟环境

先配置python开发环境 1.在搜索栏输入“>" 或是用快捷组合键ctrlshiftP键 就会显示”>",再输入"python:" 选择已经安装好的python的版本,选定至当前项目中&#xff0c;都是按回车 就可以看到创建了一个虚拟环境的默认的文件夹名".venv" 2 …

Mybatis原生使用

一、MyBatis初次使用 2.1 环境搭建步骤 MyBatis 的 API &#xff1a; https://mybatis.org/mybatis-3/zh/getting-started.html 1.引入依赖包 2.准备核心配置件 db.properties drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://123.57.206.19:3306/demo?useUnicodetrue&am…

PMP–知识卡片--SWOT分析

记忆 SWOT&#xff1a;优劣鸡血&#xff1b; 记忆2&#xff1a; “两条线画成四象限”&#xff0c;即自身优势S/劣势W外部机会O/威胁T&#xff0c;如图&#xff1a; 定义 SWOT分析从优势、劣势、机会、威胁四个角度进行分析&#xff0c;常用于战略管理、项目风险识别。 项…

关于 Mac 系统 .DS_store 文件的起源

原文&#xff1a;Arno - 2006.10.01 &#xff08;前排提醒&#xff1a;可以在 .gitignore 中添加 .DS_Store&#xff0c;否则 git 仓库会存储这个和项目无关的文件。&#xff09; 如果你是 Mac 用户&#xff0c;曾经将文件从 Mac 传输到 Windows&#xff0c;那么可能对 .DS_S…

渲染回调函数将音频传给音频单元

渲染回调函数将音频传给音频单元 渲染回调函数将音频传给音频单元了解音频单元渲染回调函数 渲染回调函数将音频传给音频单元 要将音频从磁盘或内存提供到音频单元输入总线&#xff0c;需使用符合 AURenderCallback 原型的渲染回调函数进行传输。当需要另一片样本帧时&#xf…

实现模型贴图的移动缩放旋转

技术&#xff1a;threejscanvasfabric 效果图&#xff1a; 原理&#xff1a;threejs中没有局部贴图的效果&#xff0c;只能通过map 的方式贴到模型上&#xff0c;所以说换一种方式来实现&#xff0c;通过canvasfabric来实现图片的移动缩放旋转&#xff0c;然后将整个画布以map…