当前位置: 首页 > news >正文

订阅区块,部署合约,加载合约

订阅区块

订阅区块需要 websocket RPC URL。

client, err := ethclient.Dial("wss://eth-sepolia.g.alchemy.com/v2/<API_KEY>")
if err != nil {log.Fatal(err)
}

接下来,我们将创建一个新的通道,用于接收最新的区块头。

headers := make(chan *types.Header)

现在我们调用客户端的 SubscribeNewHead 方法,它接收我们刚创建的区块头通道,该方法将返回一个订阅对象。

sub, err := client.SubscribeNewHead(context.Background(), headers)
if err != nil {log.Fatal(err)
}

订阅将推送新的区块头事件到我们的通道,因此我们可以使用一个 select 语句来监听新消息。订阅对象还包括一个 error 通道,该通道将在订阅失败时发送消息。

for {select {case err := <-sub.Err():log.Fatal(err)case header := <-headers:fmt.Println(header.Hash().Hex()) // 0xbc10defa8dda384c96a17640d84de5578804945d347072e091b4e5f390ddea7f}
}

要获得该区块的完整内容,我们可以将区块头的摘要传递给客户端的 BlockByHash 函数。

block, err := client.BlockByHash(context.Background(), header.Hash())
if err != nil {log.Fatal(err)
}fmt.Println(block.Hash().Hex())        // 0xbc10defa8dda384c96a17640d84de5578804945d347072e091b4e5f390ddea7f
fmt.Println(block.Number().Uint64())   // 3477413
fmt.Println(block.Time().Uint64())     // 1529525947
fmt.Println(block.Nonce())             // 130524141876765836fmt.Println(len(block.Transactions())) // 7

正如您所见,您可以读取整个区块的元数据字段,交易列表等等。

完整代码

package mainimport ("context""fmt""log""github.com/ethereum/go-ethereum/core/types""github.com/ethereum/go-ethereum/ethclient"
)func main() {client, err := ethclient.Dial("wss://ropsten.infura.io/ws")if err != nil {log.Fatal(err)}headers := make(chan *types.Header)sub, err := client.SubscribeNewHead(context.Background(), headers)if err != nil {log.Fatal(err)}for {select {case err := <-sub.Err():log.Fatal(err)case header := <-headers:fmt.Println(header.Hash().Hex()) // 0xbc10defa8dda384c96a17640d84de5578804945d347072e091b4e5f390ddea7fblock, err := client.BlockByHash(context.Background(), header.Hash())if err != nil {log.Fatal(err)}fmt.Println(block.Hash().Hex())        // 0xbc10defa8dda384c96a17640d84de5578804945d347072e091b4e5f390ddea7ffmt.Println(block.Number().Uint64())   // 3477413fmt.Println(block.Time().Uint64())     // 1529525947fmt.Println(block.Nonce())             // 130524141876765836fmt.Println(len(block.Transactions())) // 7}}
}

合约示例代码

Store.sol

pragma solidity ^0.8.26;contract Store {event ItemSet(bytes32 key, bytes32 value);string public version;mapping (bytes32 => bytes32) public items;constructor(string memory _version) {version = _version;}function setItem(bytes32 key, bytes32 value) external {items[key] = value;emit ItemSet(key, value);}
}

使用 nodejs,安装 solc 工具:

npm install -g solc

使用命令,编译合约代码,会在当目录下生成一个编译好的二进制字节码文件 store_sol_Store.bin:

solcjs --bin Store.sol

使用命令,生成合约 abi 文件,会在当目录下生成 store_sol_Store.abi 文件:

solcjs --abi Store.sol

abigin 工具可以使用下面的命令安装:

go install github.com/ethereum/go-ethereum/cmd/abigen@latest

使用 abigen 工具根据这两个生成 bin 文件和 abi 文件,生成 go 代码:

abigen --bin=Store_sol_Store.bin --abi=Store_sol_Store.abi --pkg=store --out=store.go

当go.mod报错时,使用

go get github.com/ethereum/go-ethereum

go mod tidy -e

使用 abigen 工具

示例代码

func main() {client, err := ethclient.Dial("https://eth-sepolia.g.alchemy.com/v2/<apikey>")if err != nil {log.Fatal(err)}// privateKey, err := crypto.GenerateKey()// privateKeyBytes := crypto.FromECDSA(privateKey)// privateKeyHex := hex.EncodeToString(privateKeyBytes)// fmt.Println("Private Key:", privateKeyHex)privateKey, err := crypto.HexToECDSA("<your 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)nonce, err := client.PendingNonceAt(context.Background(), fromAddress)if err != nil {log.Fatal(err)}gasPrice, err := client.SuggestGasPrice(context.Background())if err != nil {log.Fatal(err)}chainId, err := client.NetworkID(context.Background())if err != nil {log.Fatal(err)}auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainId)if err != nil {log.Fatal(err)}auth.Nonce = big.NewInt(int64(nonce))auth.Value = big.NewInt(0)     // in weiauth.GasLimit = uint64(300000) // in unitsauth.GasPrice = gasPriceinput := "1.0"address, tx, instance, err := store.DeployStore(auth, client, input)if err != nil {log.Fatal(err)}fmt.Println(address.Hex())fmt.Println(tx.Hash().Hex())_ = instance
}

solc version used for these examples

$ solcjs --version
0.8.26+commit.8a97fa7a.Emscripten.clang

仅使用 ethclient 工具

以太坊中,部署合约其实也是发起了一笔交易,并不是一定需要 abigen 工具生成 go 代码。

不是只能使用生成的 go 的合约代码才能部署合约。

可以仅使用 ethclient,使用更底层的方法,直接通过发送交易的方式来部署合约。

生成的 store_sol_Store.bin 文件中的字符串作为交易数据,部署 store 合约。

import ("context""crypto/ecdsa""encoding/hex""fmt""log""math/big""time""github.com/ethereum/go-ethereum""github.com/ethereum/go-ethereum/common""github.com/ethereum/go-ethereum/core/types""github.com/ethereum/go-ethereum/crypto""github.com/ethereum/go-ethereum/ethclient"
)const (// store合约的字节码contractBytecode = "608060405234801561000f575f80fd5b5060405161087538038061087583398181016040528101906100319190610193565b805f908161003f91906103e7565b50506104b6565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6100a58261005f565b810181811067ffffffffffffffff821117156100c4576100c361006f565b5b80604052505050565b5f6100d6610046565b90506100e2828261009c565b919050565b5f67ffffffffffffffff8211156101015761010061006f565b5b61010a8261005f565b9050602081019050919050565b8281835e5f83830152505050565b5f610137610132846100e7565b6100cd565b9050828152602081018484840111156101535761015261005b565b5b61015e848285610117565b509392505050565b5f82601f83011261017a57610179610057565b5b815161018a848260208601610125565b91505092915050565b5f602082840312156101a8576101a761004f565b5b5f82015167ffffffffffffffff8111156101c5576101c4610053565b5b6101d184828501610166565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061022857607f821691505b60208210810361023b5761023a6101e4565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f6008830261029d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610262565b6102a78683610262565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6102eb6102e66102e1846102bf565b6102c8565b6102bf565b9050919050565b5f819050919050565b610304836102d1565b610318610310826102f2565b84845461026e565b825550505050565b5f90565b61032c610320565b6103378184846102fb565b505050565b5b8181101561035a5761034f5f82610324565b60018101905061033d565b5050565b601f82111561039f5761037081610241565b61037984610253565b81016020851015610388578190505b61039c61039485610253565b83018261033c565b50505b505050565b5f82821c905092915050565b5f6103bf5f19846008026103a4565b1980831691505092915050565b5f6103d783836103b0565b9150826002028217905092915050565b6103f0826101da565b67ffffffffffffffff8111156104095761040861006f565b5b6104138254610211565b61041e82828561035e565b5f60209050601f83116001811461044f575f841561043d578287015190505b61044785826103cc565b8655506104ae565b601f19841661045d86610241565b5f5b828110156104845784890151825560018201915060208501945060208101905061045f565b868310156104a1578489015161049d601f8916826103b0565b8355505b6001600288020188555050505b505050505050565b6103b2806104c35f395ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c806348f343f31461004357806354fd4d5014610073578063f56256c714610091575b5f80fd5b61005d600480360381019061005891906101d7565b6100ad565b60405161006a9190610211565b60405180910390f35b61007b6100c2565b604051610088919061029a565b60405180910390f35b6100ab60048036038101906100a691906102ba565b61014d565b005b6001602052805f5260405f205f915090505481565b5f80546100ce90610325565b80601f01602080910402602001604051908101604052809291908181526020018280546100fa90610325565b80156101455780601f1061011c57610100808354040283529160200191610145565b820191905f5260205f20905b81548152906001019060200180831161012857829003601f168201915b505050505081565b8060015f8481526020019081526020015f20819055507fe79e73da417710ae99aa2088575580a60415d359acfad9cdd3382d59c80281d48282604051610194929190610355565b60405180910390a15050565b5f80fd5b5f819050919050565b6101b6816101a4565b81146101c0575f80fd5b50565b5f813590506101d1816101ad565b92915050565b5f602082840312156101ec576101eb6101a0565b5b5f6101f9848285016101c3565b91505092915050565b61020b816101a4565b82525050565b5f6020820190506102245f830184610202565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61026c8261022a565b6102768185610234565b9350610286818560208601610244565b61028f81610252565b840191505092915050565b5f6020820190508181035f8301526102b28184610262565b905092915050565b5f80604083850312156102d0576102cf6101a0565b5b5f6102dd858286016101c3565b92505060206102ee858286016101c3565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061033c57607f821691505b60208210810361034f5761034e6102f8565b5b50919050565b5f6040820190506103685f830185610202565b6103756020830184610202565b939250505056fea26469706673582212205aae308f77654b000c9d222eff2d9f2bd2ac18d990b10774842e4309d4e3e15664736f6c634300081a0033"
)func main() {// 连接到以太坊网络(这里使用 Goerli 测试网络作为示例)client, err := ethclient.Dial("https://goerli.infura.io/v3/YOUR-PROJECT-ID")if err != nil {log.Fatal(err)}// 创建私钥(在实际应用中,您应该使用更安全的方式来管理私钥)privateKey, err := crypto.HexToECDSA("YOUR-PRIVATE-KEY-HERE")if err != nil {log.Fatal(err)}publicKey := privateKey.Public()publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)if !ok {log.Fatal("error casting public key to ECDSA")}fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)// 获取noncenonce, err := client.PendingNonceAt(context.Background(), fromAddress)if err != nil {log.Fatal(err)}// 获取建议的gas价格gasPrice, err := client.SuggestGasPrice(context.Background())if err != nil {log.Fatal(err)}// 解码合约字节码data, err := hex.DecodeString(contractBytecode)if err != nil {log.Fatal(err)}// 创建交易tx := types.NewContractCreation(nonce, big.NewInt(0), 3000000, gasPrice, data)// 签名交易chainID, err := client.NetworkID(context.Background())if err != nil {log.Fatal(err)}signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)if err != nil {log.Fatal(err)}// 发送交易err = client.SendTransaction(context.Background(), signedTx)if err != nil {log.Fatal(err)}fmt.Printf("Transaction sent: %s\n", signedTx.Hash().Hex())// 等待交易被挖矿receipt, err := waitForReceipt(client, signedTx.Hash())if err != nil {log.Fatal(err)}fmt.Printf("Contract deployed at: %s\n", receipt.ContractAddress.Hex())
}func waitForReceipt(client *ethclient.Client, txHash common.Hash) (*types.Receipt, error) {for {receipt, err := client.TransactionReceipt(context.Background(), txHash)if err == nil {return receipt, nil}if err != ethereum.NotFound {return nil, err}// 等待一段时间后再次查询time.Sleep(1 * time.Second)}
}

 

使用 remix 工具

也可以使用 Solidity 网页 IDE 工具 Remix。

以下是使用 Remix 工具部署合约到测试网的操作步骤:

  1. 首先打开 Remix IDE ,打开浏览器访问 Remix IDE 的官方网站:Remix - Ethereum IDE

  2. 导入智能合约到 Remix 的文件浏览器中,创建一个 store.sol 文件。把 2.10.0 步骤中的示例合约代码复制到这个 store.sol 文件中并保存。

  3. 在左侧菜单中选择"Solidity Compiler",然后点击"Compile"按钮编译合约。确保编译器版本与你的合约兼容。

  4. 在左侧菜单中选择"Deploy & Run Transactions"。在"Environment"下拉菜单中,选择"Injected Web3"。允许使用 MetaMask 或其他 Web3 钱包连接到测试网。

  5. 确保 MetaMask 插件已经连接到所需的测试网(如 Goerli、Sepolia 等)。如果需要,添加测试网络到 MetaMask 并获取一些测试以太币。

  6. 部署合约 在 Remix 的"Deploy & Run Transactions"面板中:

    • 选择你要部署的合约
    • 如果合约构造函数需要参数,在"Deploy"按钮下方的输入框中填入参数
    • 点击"Deploy"按钮
  7. MetaMask 会弹出一个窗口,要求你确认交易。检查 gas 费用和其他详情,然后确认交易。

  8. 等待部署完成 交易被确认后,合约将被部署到测试网。你可以在 Remix 的控制台中看到部署的详细信息,包括合约地址。

  9. 可以使用测试网的区块浏览器(https://sepolia.etherscan.io/)来验证合约是否成功部署,只需搜索合约地址即可。

  10. 部署完成后,就可以在 Remix 的"Deployed Contracts"部分与合约进行交互,调用函数或发送交易。

加载合约

加载合约是在成功部署合约后,使用合约的 abi 文件生成 go 合约代码,并且在代码中初始化这个合约的实例。

初始化合约实例时需要提供两个参数,分别是 ethclient 的实例和合约地址。

使用 2.10 中的示例合约代码生成 abi 文件:

solcjs --abi store.sol

然后使用 abigen,仅根据 abi 文件生成合约代码:

abigen --abi=Store_sol_Store.abi --pkg=store --out=store.go

注:仅使用 abi 文件生成的合约代码时,生成的代码中不会包含部署合约的代码。

2.11.1 使用生成的代码加载合约

部署的合约的地址,加载合约示例:

package mainimport ("log""github.com/ethereum/go-ethereum/common""github.com/ethereum/go-ethereum/ethclient""github.com/learn/init_order/store"
)const (contractAddr = "0x8D4141ec2b522dE5Cf42705C3010541B4B3EC24e"
)func main() {client, err := ethclient.Dial("http://127.0.0.1:7545")if err != nil {log.Fatal(err)}storeContract, err := store.NewStore(common.HexToAddress(contractAddr), client)if err != nil {log.Fatal(err)}_ = storeContract
}

 

使用 Remix 在线 IDE 工具加载合约

使用 Remix 在线 IDE 工具加载合约的前提是必须有合约代码,需要先在 Remix 中把合约编译一遍之后,才可以使用合约地址加载合约。

使用 Remix 在线 IDE 工具加载合约步骤:

  1. 导入智能合约到 Remix 的文件浏览器中,创建一个 store.sol 文件。把 2.10.0 步骤中的示例合约代码复制到这个 store.sol 文件中并保存。
  2. 在左侧菜单中选择"Solidity Compiler",然后点击"Compile"按钮编译合约。确保编译器版本与你的合约兼容。
  3. 在左侧菜单中选择"Deploy & Run Transactions"。在"Environment"下拉菜单中,选择"Injected Web3"。允许使用 MetaMask 或其他 Web3 钱包连接到测试网。
  4. 在"Contract"下来菜单中选中 store 合约,然后在"At Address"按钮边的输入框中,输入合约地址,点击"At Address"按钮。
  5. 可以看到"Deployed/Unpinned Contracts"栏新增一条记录,点击下拉按钮,即可与合约进行交互,调用函数或发送交易。
http://www.lryc.cn/news/605241.html

相关文章:

  • 颐顿机电携手观远BI数据:以数据驱动决策,领跑先进制造智能化升级
  • 流程制造的数字孪生:从黑箱生产到全息掌控
  • Linux c网络专栏第四章io_uring
  • Linux零基础Shell教学全集(可用于日常查询语句,目录清晰,内容详细)(自学尚硅谷B站shell课程后的万字学习笔记,附课程链接)
  • Baumer工业相机堡盟工业相机如何通过YoloV8的深度学习模型实现汽车牌照的位置识别(C#代码,UI界面版)
  • 大厂主力双塔模型实践与线上服务
  • SSRF漏洞基础
  • 爬虫验证码处理:ddddocr 的详细使用(通用验证码识别OCR pypi版)
  • Redis 中 key 的过期策略 和 定时器的两种实现方式
  • cocos打包web端需要注意的地方
  • Apache HTTP Server 2.4.50 路径穿越漏洞(CVE-2021-42013)
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现裂缝的检测识别(C#代码UI界面版)
  • 生成式推荐网络架构汇总
  • Java注解与反射:从自定义注解到框架设计原理
  • CHI - Transaction介绍(4) - 原子操作
  • 工厂方法模式:从基础到C++实现
  • Spring Boot 数据源配置中为什么可以不用写 driver-class-name
  • 1. ESP开发之实体按键(KEYPADBUTTON)控制LVGL控件
  • 一文掌握最新版本Monocle3单细胞轨迹(拟时序)分析
  • 【Unity】在构建好的项目里创建自定义文件夹
  • Thales靶机
  • Redis知识点(1)
  • 【力扣热题100】哈希——字母异位词分组
  • 【c++】leetcode763 划分字母区间
  • LeetCode热题100--148. 排序链表--中等
  • 限流算法详解:固定窗口、滑动窗口、令牌桶与漏桶算法全面对比
  • 力扣-543.二叉树的直径
  • 【LeetCode】链表反转实现与测试
  • (补题)小塔的饭
  • sqLite 数据库 (3):以编程方式使用 sqLite,4 个函数,以及 sqLite 移植,合并编译