在本地以太坊私链上,使用go调用智能合约,获取事件日志

编程入门 行业动态 更新时间:2024-10-12 01:24:08

在本地<a href=https://www.elefans.com/category/jswz/34/1768575.html style=以太坊私链上,使用go调用智能合约,获取事件日志"/>

在本地以太坊私链上,使用go调用智能合约,获取事件日志

1、关于开发环境搭建配置等可参考之前的文章
2、部署合约代码erc20.js

const hre = require("hardhat");
async function main() {const CONTRACT = await hre.ethers.getContractFactory("ERC20");const contract = await CONTRACT.deploy();await contract.init("ERC20Name","ERC20Symbol");console.log("name:",contract.name(),"symbol:",contract.symbol());await contract.deployed();console.log(`contract deployed to ${contract.address}`);
}main().catch((error) => {console.error(error);process.exitCode = 1;
});

3、启动并上链

#切换到智能合约项目位置
npx hardhat node
#新开一个窗口,确保localhost已经在hardhat.config.js中配置了,可查看第一步链接对照
npx hardhat run scripts/erc.js --network localhost


4、新建一个文件夹,存放go项目,完成mod初始化等

完整go项目文件目录


5、拷贝智能合约compile产生的ABI,在新文件夹中新建一个erc20.json文件

 

 

6、安装abigen

go get github/ethereum/go-ethereum#切换路径 cd $GOPATH/pkg/mod/github/ethereum/go-ethereum@v1.10.25
sudo make && make devtools#测试安装
abigen --help

7、将ABI生成GO文件

abigen --abi erc20.json -pkg json -type erc20 --out erc20.go

8、编写调用文件 main.go

package mainimport ("context""crypto/ecdsa""fmt""github/ethereum/go-ethereum/accounts/abi/bind""github/ethereum/go-ethereum/common""github/ethereum/go-ethereum/crypto""github/ethereum/go-ethereum/ethclient""math/big""mysolidity/json"
)func main() {//合约地址contractAddress := "0x5FbDB2315678afecb367f032d93F642f64180aa3"//连接本地的以太坊私链(一定要保证本地以太坊私链已经启动)conn, err := ethclient.Dial("http://127.0.0.1:8545")fmt.Println("connect to local node...", conn)if err != nil {fmt.Errorf("could not connect to local node: %v", err)return}//创建合约erc20, err := json.NewErc20(common.HexToAddress(contractAddress), conn)if err != nil {fmt.Errorf("failed to instantiate a Token contract: %v", err)return}fmt.Println("contract token:", erc20)//调用合约查询方法name, err := erc20.Name(&bind.CallOpts{Pending:     false,From:        common.Address{},BlockNumber: nil,Context:     nil,})if err != nil {fmt.Errorf("name:%v", err)return}symbol, err := erc20.Symbol(&bind.CallOpts{Pending:     false,From:        common.Address{},BlockNumber: nil,Context:     nil,})if err != nil {fmt.Errorf("name:%v", err)return}fmt.Println("name:", name, "symbol:", symbol)//查询第一个账户余额b, err := erc20.BalanceOf(&bind.CallOpts{Pending:     false,From:        common.Address{},BlockNumber: nil,Context:     nil,}, common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))//启动node默认生成的第1个账户地址if err != nil {fmt.Errorf("BalanceOf:%v", err)return}fmt.Println("first balance:", b)第一个账户给第二个账户转账//私钥,需要生成签名privateKey, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")//私钥注意去掉ox,这是启动node默认生成的第1个账户的私钥if err != nil {fmt.Errorf("err:%v\n", err)return}publicKey := privateKey.Public()publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)if !ok {fmt.Errorf("cannot assert type: publicKey is not of type *ecdsa.PublicKey")return}fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)nonce, err := conn.PendingNonceAt(context.Background(), fromAddress)if err != nil {fmt.Errorf("%v", err)return}gasPrice, err := conn.SuggestGasPrice(context.Background())if err != nil {fmt.Errorf("%v", err)return}//chainIDid, err := conn.ChainID(context.Background())if err != nil {return}fmt.Println("chainID:", id)auth, _ := bind.NewKeyedTransactorWithChainID(privateKey, id)auth.Nonce = big.NewInt(int64(nonce))auth.Value = big.NewInt(10)    auth.GasLimit = uint64(300000) auth.GasPrice = gasPricetx, err := erc20.Transfer(&bind.TransactOpts{Signer:   auth.Signer,From:     fromAddress,GasLimit: auth.GasLimit,GasPrice: auth.GasPrice,Context:  nil,}, common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"), big.NewInt(8))if err != nil {fmt.Errorf("transfer:%v", err)return}fmt.Println("tx.GasPrice():", tx.GasPrice())//查询两个账户余额b, err = erc20.BalanceOf(&bind.CallOpts{From: fromAddress}, common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"))//启动node默认生成的第2个账户地址if err != nil {fmt.Errorf("BalanceOf:%v", err)return}fmt.Println("second balance:", b)b, err = erc20.BalanceOf(&bind.CallOpts{From: fromAddress}, fromAddress)if err != nil {fmt.Errorf("BalanceOf:%v", err)return}fmt.Println("first balance:", b)
}

9、查询事件日志(完整开发的一般流程,在链端开发智能合约后,由前端使用web3.js等进行交互,后端通过查询事件日志修改数据库信息展示)

package mainimport ("context""fmt""github/ethereum/go-ethereum""github/ethereum/go-ethereum/common""github/ethereum/go-ethereum/crypto""github/ethereum/go-ethereum/ethclient""math/big""mysolidity/json"
)func main() {//合约地址contractAddress := common.HexToAddress("0x5FbDB2315678afecb367f032d93F642f64180aa3")//websocket监听client, err := ethclient.Dial("ws://127.0.0.1:8545/ws")if err != nil {fmt.Errorf("could not connect to local node: %v", err)return}query := ethereum.FilterQuery{FromBlock: big.NewInt(1), //生产环境中,从0开始,查询后修改区块记录,下一次就从后一个有记录的区块数开始ToBlock:   big.NewInt(100),Addresses: []common.Address{contractAddress,},}erc20, _ := json.NewErc20(contractAddress, client)logs, err := client.FilterLogs(context.Background(), query)if err != nil {fmt.Errorf("err:%v\n", err)return}for _, vLog := range logs {if len(vLog.Topics) == 0 {continue}event := vLog.Topics[0].Hex()if event == TransferEvent() { //对对应的事件进行对应的处理fmt.Println(vLog.Data)data, err := erc20.ParseTransfer(vLog)if err != nil {fmt.Errorf("err:%v\n", err)continue}fmt.Println(data.From.Hex(), data.To.Hex(), data.Value.Int64(), data.Raw.Data)}}
}
func TransferEvent() string {event := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")).Hex()return event
}

10、测试结果(main.go为最后一次运行结果)

 

更多推荐

在本地以太坊私链上,使用go调用智能合约,获取事件日志

本文发布于:2024-02-27 09:05:11,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1705960.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:以太   合约   事件   智能   日志

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!