golang与以太坊交互

news2024/11/20 9:40:02

文章目录

  • 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上验证合约

还没造,等几天。。。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第一百四十七节 Java数据类型教程 - Java字符串字符

Java数据类型教程 - Java字符串字符 索引字符 您可以使用charAt()方法从String对象中获取特定索引处的字符。索引从零开始。 下面的代码打印索引值和字符在“W3CSCHOOL.CN"字符串中的每个索引处: public class Main {public static void main(String[] args) {String s…

SS8812T替代DRV8812的国产双通道H桥电机驱动芯片

由工采网代理的SS8812T是一款国产双通道H桥电机驱动芯片&#xff1b;该芯片为打印机和其它电机一体化应用提供一种双通道集成电机驱动方案&#xff1b;可Pin-to-Pin兼容替代DRV8812&#xff0c;可广泛应用于POS、打印机、安防相机、办公自动化设备、游戏机、机器人等。 产品描述…

免费鼠标连点器有吗?需要付费吗?鼠标连点器电脑版免费推荐6款!

在数字化时代&#xff0c;鼠标连点器成为了许多用户提高工作效率、优化游戏体验的得力助手。然而&#xff0c;面对市场上琳琅满目的鼠标连点器软件&#xff0c;很多用户都会产生疑问&#xff1a;是否有免费的鼠标连点器&#xff1f;它们真的需要付费吗&#xff1f;今天&#xf…

【IT领域新生必看】Java中的对象创建魔法:小白也能掌握的五种方法

文章目录 引言为什么需要创建对象&#xff1f;创建对象的五种常见方式1. 使用 new 关键字示例&#xff1a; 2. 使用反射示例&#xff1a; 3. 使用克隆示例&#xff1a; 4. 使用序列化和反序列化示例&#xff1a; 5. 使用工厂方法示例&#xff1a; 选择合适的对象创建方式总结 引…

解决obsidian加粗中文字体显示不突出的问题

加粗字体显示不突出的原因&#xff1a;默认字体的加粗版本本来就不突出 解决方法&#xff1a;改成显示突出的类型Microsoft YaHei UI 【效果】 修改前&#xff1a;修改后&#xff1a; 其他方法&#xff1a; 修改css&#xff08;很麻烦&#xff0c;改半天也不一定奏效&#…

《Windows API每日一练》8.3 scrollbar控件

在第三章SYSMETS2.C实例中&#xff0c;我们是通过CreateWindow函数创建窗口的参数窗口样式中添加垂直或水平滚动条。本节我们将讲述作为子窗口控件的滚动条。 本节必须掌握的知识点&#xff1a; 滚动条类 滚动条控件和着色 8.3.1 滚动条类 ■窗口滚动条与滚动条控件的异同 …

第一百四十八节 Java数据类型教程 - Java字符串搜索和Java子字符串

Java数据类型教程 - Java字符串搜索 我们可以使用indexOf()和lastIndexOf()方法获取另一个字符串中的字符或字符串的索引。例如 public class Main {public static void main(String[] args) {String str new String("Apple");int index str.indexOf("p"…

YOLOv8数据集可视化[目标检测实践篇]

先贴代码,后面再补充解析。 这个篇章主要是对标注好的标签进行可视化,虽然比较简单,但是可以从可视化代码中学习到YOLOv8是如何对标签进行解析的。 下面直接贴代码: import cv2 import numpy as np import osdef read_det_labels(label_file_path):with open(labe…

C++初学者指南-4.诊断---用gdb调试

C初学者指南-4.诊断—用gdb调试 幻灯片 gdb / 前端 gdbGNU的命令行调试器cgdb基于终端的gdb前端Linux安装:sudo apt-get install cgdbgdbgui基于浏览器的gdb前端网址&#xff1a;https://gdbgui.com/安装&#xff1a;sudo pip install gdbguiQt Creator可以连接gdbVisual St…

Vite: 近几个版本的更新

概述 在 2021 年 2 月&#xff0c;尤大正式推出了 Vite 2.0 版本&#xff0c;可以说是 Vite 的一个重要转折点&#xff0c;自此之后 Vite 的用户量发生了非常迅速的增长&#xff0c;很快达到了每周 100 万的 npm 下载量。同时&#xff0c;Vite 的社区也越来越活跃&#xff0c;…

实验3-Spark基础-Spark的安装

文章目录 1. 下载安装 Scala1.1 下载 Scala 安装包1.2 基础环境准备1.3 安装 Scala 2. 下载安装 Spark2.1 下载 Spark 安装包2.2 安装 Spark2.3 配置 Spark2.4 创建配置文件 spark-env.sh 3. pyspark 启动4. 建立/user/spark文件夹 1. 下载安装 Scala 1.1 下载 Scala 安装包 下…

Redis 八股文

标题 1. Redis主从同步原理&#xff1a;判断下线的条件:故障转移如何保证Sentinel高可用 1. Redis主从同步原理&#xff1a; 1、slave执行命令向master建立连接 2、master执行bgsave&#xff08;后台存储&#xff09;&#xff0c;生成rdb快照&#xff08;redis备份方式&#x…

基于STM32F407ZG的FreeRTOS移植

1.从FreeRTOS官网中下载源码 2、简单分析FreeRTOS源码目录结构 2.1、简单分析FreeRTOS源码根目录 &#xff08;1&#xff09;Demo&#xff1a;是官方为一些单片机移植FreeRTOS的例程 &#xff08;2&#xff09;License&#xff1a;许可信息 &#xff08;3&#xff09;Sourc…

如何使用C++调用Pytorch模型进行推理测试:使用libtorch库

如何使用C调用Pytorch模型进行推理测试&#xff1a;使用libtorch库 目录 如何使用C调用Pytorch模型进行推理测试&#xff1a;使用libtorch库一、环境准备1&#xff0c;linux&#xff1a;以ubuntu 22.04系统为例1. 准备CUDA和CUDNN2. 准备C环境3, 下载libtorch文件4, 编写测试li…

开发者评测|操作系统智能助手OS Copilot

操作系统智能助手OS Copilot 文章目录 操作系统智能助手OS CopilotOS Copilot 是什么优势功能 操作步骤创建实验重置密码创建Access Key配置安全组安装 os-copilot环境变量配置功能评测命令行模式多轮交互模式 OS Copilot 产品体验评测反馈OS Copilot 产品功能评测反馈 参考文档…

【鸿蒙学习笔记】Stage模型工程目录

官方文档&#xff1a;应用配置文件概述&#xff08;Stage模型&#xff09; 目录标题 FA模型和Stage模型工程级目录模块级目录app.json5module.json5程序执行流程程序基本结构开发调试与发布流程 FA模型和Stage模型 工程级目录 模块级目录 app.json5 官方文档&#xff1a;app.j…

【笔记】记一次在linux上通过在线安装mysql报错 CentOS 7 的官方镜像已经不再可用的解决方法+mysql配置

报错&#xff08;恨恨恨恨恨恨恨&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff09;&#xff1a; [rootlocalhost ~]# sudo yum install mysql-server 已加载插件&#xff1a;fastestmirror, langpacks Determining fastest mirrors Could not retrie…

MWC上海展 | 创新微MinewSemi携ME54系列新品亮相Nordic展台

6月28日&#xff0c; 2024MWC上海圆满落幕&#xff0c;此次盛会吸引了来自全球124个国家及地区的近40,000名与会者。本届大会以“未来先行&#xff08;Future First&#xff09;”为主题&#xff0c;聚焦“超越5G”“人工智能经济”“数智制造”三大子主题&#xff0c;探索讨论…

AI语音工具——Fish Speech:使用简单,可训练专属语音模型!

今天给大家介绍一款超好用的AI语音工具——Fish Speech&#xff0c;使用简单&#xff0c;还可以训练自己的语音模型&#xff01; 工具介绍 Fish Speech是由 Fish Audio 开发的免费开源文本转语音模型。经过十五万小时的数据训练&#xff0c;Fish Speech能够熟练掌握中文、日语…

【Docker系列】Docker 镜像构建中的跨设备移动问题及解决方案

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…