如何使用 Golang 正确发送 RPC 调用以获取智能合约所有者?

Posted

技术标签:

【中文标题】如何使用 Golang 正确发送 RPC 调用以获取智能合约所有者?【英文标题】:How to correctly send RPC call using Golang to get smart-contract owner? 【发布时间】:2018-11-10 09:47:39 【问题描述】:

更新

由于我无法使用此问题中的方法来实现这一点,因此我创建了自己的库来做同样的事情 (link)。它不依赖 go-ethereum 包,而是使用普通的net/http 包来做 JSON RPC 请求。

我仍然很想知道我在下面的方法中做错了什么。


定义

所有者 = publicaddress 类型的合同变量 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 方法的情况下解决这个特定问题。

【问题讨论】:

【参考方案1】:

您可以使用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())

【讨论】:

谢谢。这是最接近的解决方案。感谢您的帮助!【参考方案2】:

如果您查看客户端库代码,您会看到 JSON RPC 响应对象已经被反汇编,并且失败时返回错误,或者解析出的实际结果:https://github.com/ethereum/go-ethereum/blob/master/rpc/client.go#L277

然而,解析器已经解开了包含“结果”字段。你的类型仍然想做一个额外的解包:

type response struct 
    Result string

删除外部结构,只需将字符串指针传递给client.Call 的第一个参数。

【讨论】:

对不起@Péter Szilágyi,我不是很清楚。你能在代码中显示它吗?谢谢。【参考方案3】:

您的响应结构没有显示响应的 json 具有的数据

试试这个

type response struct 
    Jsonrpc string `json:"jsonrpc"`
    ID      int    `json:"id"`
    Result  string `json:"result"`

【讨论】:

感谢您的帮助。不幸的是,我仍然收到json: cannot unmarshal string into Go value of type main.response 错误。 尝试调整响应。我没有查看您正在使用的库,它可能会剥离 jsonrpc 或 id 我试过了。我评论了Jsonrpc。它失败了。接下来我取消了Jsonrpc 的注释并评论了ID。还是失败了。 在 go-ethereum client.go 的第 277 行添加到 printf("%v",resp.Result),就在它触发错误之前。看看它返回了什么【参考方案4】:

json: cannot unmarshal string into Go value of type main.response 错误。我在解组响应时遇到了类似的类型错误。这是因为响应实际上是 json 字符串,我的意思是它有引号 " 作为第一个字符。所以为了确保你也遇到了同样的问题,请printf("%v",resp.Result)在这里解组之前https://github.com/ethereum/go-ethereum/blob/1ff152f3a43e4adf030ac61eb5d8da345554fc5a/rpc/client.go#L278。

【讨论】:

以上是关于如何使用 Golang 正确发送 RPC 调用以获取智能合约所有者?的主要内容,如果未能解决你的问题,请参考以下文章

Rabbit MQ 阻止调用以发送消息并确保它为超出消息限制或超出消息大小限制提供正确的回复代码

使用 node-json-rpc 库中的客户端时使用正确的 SSL 协议

Golang goroutines 共享 RPC 连接

RPC in Golang

Golang RPC 编码自定义函数

golang rpc package分析