如何使用 Golang 正确发送 RPC 调用以获取智能合约所有者?
How to correctly send RPC call using Golang to get smart-contract owner?
更新
由于我无法使用此问题中的方法实现此目的,因此我创建了自己的库来做同样的事情 (link)。它不依赖于 go-ethereum 包,而是使用普通的 net/http
包来执行 JSON RPC 请求。
我仍然很想知道我在下面的方法中做错了什么。
定义:
- 所有者 =
public
合同中的变量 address
类型
- contract = 拥有 owner
的智能合约
这是获取合同所有者的 curl 请求。我设法得到了主人。 (JSON RPC docs)
curl localhost:8545 -X POST \
--header 'Content-type: application/json' \
--data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"to": "0x_MY_CONTRACT_ADDRESS", "data": "0x8da5cb5b"}, "latest"], "id":1}'
{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000_OWNER"}
但是当我尝试在 Golang 中复制它时(下面的代码),我得到了 json: cannot unmarshal string into Go value of type main.response错误。 (go-ethereum code that I use)
package main
import (
"fmt"
"log"
"os"
"github.com/ethereum/go-ethereum/rpc"
)
func main() {
client, err := rpc.DialHTTP(os.Getenv("RPC_SERVER"))
if err != nil {
log.Fatal(err)
}
defer client.Close()
type request struct {
To string `json:"to"`
Data string `json:"data"`
}
type response struct {
Result string
}
req := request{"0x_MY_CONTRACT_ADDRESS", "0x8da5cb5b"}
var resp response
if err := client.Call(&resp, "eth_call", req, "latest"); err != nil {
log.Fatal(err)
}
fmt.Printf("%v\n", resp)
}
我错过了什么?
预期结果:
字符串格式的地址。例如。 0x3ab17372b25154400738C04B04f755321bB5a94b
P/S — 我知道 abigen 并且我知道使用 abigen 更好更容易地做到这一点。但我试图在不使用 abigen 方法的情况下解决这个具体问题。
您的响应结构未显示响应的 json 具有的数据
试试这个
type response struct {
Jsonrpc string `json:"jsonrpc"`
ID int `json:"id"`
Result string `json:"result"`
}
json:无法将字符串解组为 main.response 类型的 Go 值错误。 我在解组响应时遇到了类似的类型错误。这是因为响应实际上是 json 字符串,我的意思是它的第一个字符是 Quotation "
。因此,为确保您也遇到了同样的问题,请在此处 https://github.com/ethereum/go-ethereum/blob/1ff152f3a43e4adf030ac61eb5d8da345554fc5a/rpc/client.go#L278.
解组之前 printf("%v",resp.Result)
如果您查看客户端库代码,您会看到 JSON RPC 响应对象已经被反汇编,失败时返回错误,或者解析的实际结果:https://github.com/ethereum/go-ethereum/blob/master/rpc/client.go#L277
然而,解析器已经解包了包含 "result" 的字段。您的类型仍想进行额外的展开:
type response struct {
Result string
}
删除外部结构,只需将字符串指针传递给 client.Call
的第一个参数。
您最好使用 go-ethereum/ethclient:
来解决问题
package main
import (
"context"
"log"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, _ := ethclient.Dial("https://mainnet.infura.io")
defer client.Close()
contractAddr := common.HexToAddress("0xCc13Fc627EFfd6E35D2D2706Ea3C4D7396c610ea")
callMsg := ethereum.CallMsg{
To: &contractAddr,
Data: common.FromHex("0x8da5cb5b"),
}
res, err := client.CallContract(context.Background(), callMsg, nil)
if err != nil {
log.Fatalf("Error calling contract: %v", err)
}
log.Printf("Owner: %s", common.BytesToAddress(res).Hex())
}
更新
由于我无法使用此问题中的方法实现此目的,因此我创建了自己的库来做同样的事情 (link)。它不依赖于 go-ethereum 包,而是使用普通的 net/http
包来执行 JSON RPC 请求。
我仍然很想知道我在下面的方法中做错了什么。
定义:
- 所有者 =
public
合同中的变量address
类型 - contract = 拥有 owner 的智能合约
这是获取合同所有者的 curl 请求。我设法得到了主人。 (JSON RPC docs)
curl localhost:8545 -X POST \
--header 'Content-type: application/json' \
--data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"to": "0x_MY_CONTRACT_ADDRESS", "data": "0x8da5cb5b"}, "latest"], "id":1}'
{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000_OWNER"}
但是当我尝试在 Golang 中复制它时(下面的代码),我得到了 json: cannot unmarshal string into Go value of type main.response错误。 (go-ethereum code that I use)
package main
import (
"fmt"
"log"
"os"
"github.com/ethereum/go-ethereum/rpc"
)
func main() {
client, err := rpc.DialHTTP(os.Getenv("RPC_SERVER"))
if err != nil {
log.Fatal(err)
}
defer client.Close()
type request struct {
To string `json:"to"`
Data string `json:"data"`
}
type response struct {
Result string
}
req := request{"0x_MY_CONTRACT_ADDRESS", "0x8da5cb5b"}
var resp response
if err := client.Call(&resp, "eth_call", req, "latest"); err != nil {
log.Fatal(err)
}
fmt.Printf("%v\n", resp)
}
我错过了什么?
预期结果:
字符串格式的地址。例如。 0x3ab17372b25154400738C04B04f755321bB5a94b
P/S — 我知道 abigen 并且我知道使用 abigen 更好更容易地做到这一点。但我试图在不使用 abigen 方法的情况下解决这个具体问题。
您的响应结构未显示响应的 json 具有的数据
试试这个
type response struct {
Jsonrpc string `json:"jsonrpc"`
ID int `json:"id"`
Result string `json:"result"`
}
json:无法将字符串解组为 main.response 类型的 Go 值错误。 我在解组响应时遇到了类似的类型错误。这是因为响应实际上是 json 字符串,我的意思是它的第一个字符是 Quotation "
。因此,为确保您也遇到了同样的问题,请在此处 https://github.com/ethereum/go-ethereum/blob/1ff152f3a43e4adf030ac61eb5d8da345554fc5a/rpc/client.go#L278.
printf("%v",resp.Result)
如果您查看客户端库代码,您会看到 JSON RPC 响应对象已经被反汇编,失败时返回错误,或者解析的实际结果:https://github.com/ethereum/go-ethereum/blob/master/rpc/client.go#L277
然而,解析器已经解包了包含 "result" 的字段。您的类型仍想进行额外的展开:
type response struct {
Result string
}
删除外部结构,只需将字符串指针传递给 client.Call
的第一个参数。
您最好使用 go-ethereum/ethclient:
来解决问题package main
import (
"context"
"log"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, _ := ethclient.Dial("https://mainnet.infura.io")
defer client.Close()
contractAddr := common.HexToAddress("0xCc13Fc627EFfd6E35D2D2706Ea3C4D7396c610ea")
callMsg := ethereum.CallMsg{
To: &contractAddr,
Data: common.FromHex("0x8da5cb5b"),
}
res, err := client.CallContract(context.Background(), callMsg, nil)
if err != nil {
log.Fatalf("Error calling contract: %v", err)
}
log.Printf("Owner: %s", common.BytesToAddress(res).Hex())
}