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 mainimport ("context""fmt""github.com/ethereum/go-ethereum/ethclient" // 导入以太坊客户端库"log"
)var infuraURL = "https://sepolia.infura.io/v3/********************************" // Infura提供的API URLfunc 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 mainimport ("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 URLfunc 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 mainimport ("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 mainimport ("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 mainimport ("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 mainimport ("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 mainimport ("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 URLfunc 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,})// 获取当前链的 IDchainID, 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 mainimport ("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)}// 获取网络的chainIDchainID, 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 = gasPriceauth.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 mainimport ("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()// 获取当前链的 IDchainID, 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 = 3000000tx.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.mzph.cn/news/867072.shtml

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

相关文章

《昇思25天学习打卡营第12天|onereal》

CycleGAN图像风格迁移互换 模型简介 CycleGAN(Cycle Generative Adversarial Network) 即循环对抗生成网络&#xff0c;来自论文 Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks 。该模型实现了一种在没有配对示例的情况下学习将图像从源域…

C++中的引用——引用做函数参数

作用&#xff1a;函数传参时&#xff0c;可以利用引用的技术让形参修饰实参 优点&#xff1a;可以简化指针修改实参 示例&#xff1a; 1.值传递 运行结果&#xff1a; 2.地址传递 运行结果&#xff1a; 3.引用传递 运行结果&#xff1a;

SQL注入方法

文章目录 前言如何测试与利用注入点手工注入思路工具sqlmap-r-u-m--level--risk-v-p--threads-batch-smart--os-shell--mobiletamper插件获取数据的相关参数 前言 记录一些注入思路和经常使用的工具&#xff0c;后续有用到新的工具和总结新的方法再继续补充。 如何测试与利用注…

windows下使用编译opencv在qt中使用

记录一下&#xff1a;在windows下qt使用opencv 1、涉及需要下载的软件 CMake 下载地址opecnv下载地址mingw(需要配置环境变量) 这个在下载qt的时候可以直接安装一般在qt的安装路径下的tool里比如我的安装路径 (C:\zz\ProgramFiles\QT5.12\Tools\mingw730_64) 2、在安装好CMake…

【IT领域新生必看】探索Java中的对象创建:深入理解`new`与`clone`的对比

文章目录 引言什么是new关键字&#xff1f;使用new关键字的基本语法示例&#xff1a; 什么是clone方法&#xff1f;使用clone方法的基本语法示例&#xff1a; new与clone的区别内存分配与初始化调用方式适用场景性能 new关键字的优缺点优点缺点 clone方法的优缺点优点缺点 深入…

大华设备接入GB28181视频汇聚管理平台EasyCVR安防监控系统的具体操作步骤

智慧城市/视频汇聚/安防监控平台EasyCVR兼容性强&#xff0c;支持多协议接入&#xff0c;包括国标GB/T 28181协议、GA/T 1400协议、部标JT808协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SDK等&#xff0c;并能对外分发RTMP、…

Pseudo-Label : The Simple and Efficient Semi-Supervised Learning Method--论文笔记

论文笔记 资料 1.代码地址 https://github.com/iBelieveCJM/pseudo_label-pytorch 2.论文地址 3.数据集地址 论文摘要的翻译 本文提出了一种简单有效的深度神经网络半监督学习方法。基本上&#xff0c;所提出的网络是以有监督的方式同时使用标记数据和未标记数据来训练的…

加法器的基本操作

基本单元 与门(AND) 全1为1&#xff0c;有0为0 或门(OR) 全0为0&#xff0c;有1为1 非门(NOT) 为1则0&#xff0c;为0则1 异或门(XOR) 两个输入端&#xff0c;相同为0&#xff0c;不同为1 与非门(NADD) 全1为0&#xff0c;有0为1 或非门(NOR) 全0为1&#xff0c;有1为0。刚…

redis 如何使用 scan, go语言

建议用方案乙 文章目录 场景方案方案甲方案乙 拓展 场景 redis 中存在大量 key。 其中有一部分是用户登陆的 session_id&#xff0c; 结构是 &#xff1a; session_id:1session_id:2session_id:3需求&#xff1a; 有多少用户在线 方案 方案甲 keys session_id:*这种方式简…

项目部署_持续集成_Jenkins

1 今日内容介绍 1.1 什么是持续集成 持续集成&#xff08; Continuous integration &#xff0c; 简称 CI &#xff09;指的是&#xff0c;频繁地&#xff08;一天多次&#xff09;将代码集成到主干 持续集成的组成要素 一个自动构建过程&#xff0c; 从检出代码、 编译构建…

数据结构——单向循环链表

文章目录 1. 概念 2. 区别 2.1 结构区别 2.2 访问方式区别 2.3 优缺点对比 3. 流程 4. 基本操作 5. 代码示例 1. 概念 单向循环链表是一种特殊的单链表&#xff0c;其中最后一个节点的后继指针指向头节点&#xff0c;形成一个环。单向循环链表适合用于需要循环访问数据…

Spring Boot集成jacoco实现单元测试覆盖统计

1.什么是jacoco&#xff1f; JaCoCo&#xff0c;即 Java Code Coverage&#xff0c;是一款开源的 Java 代码覆盖率统计工具。支持 Ant 、Maven、Gradle 等构建工具&#xff0c;支持 Jenkins、Sonar 等持续集成工具&#xff0c;支持 Java Agent 技术远程监控 Java 程序运行情况…

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

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

STM32学习历程(day3)

通过GPIO点灯 首先先创建工程 这步比较繁琐 可以去参考江协科技[3-2]章节 想要驱动LED灯 要先使能时钟、然后再初始化、GPIO模式、引脚、以及输出速率 可以查看RCC的头文件 能看到三个使能函数 使能AHB、APB2、APB1 &#xff0c;GPIO用APB2这个函数、 通过看RCC库函数的源码…

给我的 IM 系统加上监控两件套:【Prometheus + Grafana】

监控是一个系统必不可少的组成部分&#xff0c;实时&#xff0c;准确的监控&#xff0c;将会大大有助于我们排查问题。而当今微服务系统的话有一个监控组合很火那就是 Prometheus Grafana&#xff0c;嘿你别说 这俩兄弟配合的相当完美&#xff0c;Prometheus负责数据采集&…

【MySQL系列】VARCHAR 类型详解及其使用策略

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

MySQL---事务管理

1.关于事务 理解和学习事务&#xff0c;不能只站在程序猿的角度来理解事务&#xff0c;而是要站在使用者&#xff08;用户&#xff09;的角度来理解事务。 比如支付宝转账&#xff0c;A转了B100块前&#xff0c;在程序猿的角度来看&#xff0c;是两条update操作&#xff0c;A …

浅谈反射机制

1. 何为反射&#xff1f; 反射&#xff08;Reflection&#xff09;机制指的是程序在运行的时候能够获取自身的信息。具体来说&#xff0c;反射允许程序在运行时获取关于自己代码的各种信息。如果知道一个类的名称或者它的一个实例对象&#xff0c; 就能把这个类的所有方法和变…

【贪心 堆 优先队列】502. IPO

本文涉及知识点 贪心 堆 优先队列 LeetCode502. IPO 假设 力扣&#xff08;LeetCode&#xff09;即将开始 IPO 。为了以更高的价格将股票卖给风险投资公司&#xff0c;力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限&#xff0c;它只能在 IPO 之前完成最多 k…

ORB-SLAM3源码分析(案例分析)

一、ORB-SLAM3简介 ORB-SLAM3 (Oriented FAST and Rotated BRIEF SLAM 3) 是一种视觉SLAM&#xff08;Simultaneous Localization and Mapping&#xff0c;同时定位与地图构建&#xff09;系统&#xff0c;用于机器人和计算机视觉领域。它是ORB-SLAM系列的第三个版本&#xff…