doufuxi7093
doufuxi7093
2018-11-10 09:47

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

已采纳

Update

Since I'm not able to achieve this using the approach in this question, I created my own library to do the same thing (link). It doesn't rely on go-ethereum package but use the normal net/http package to do JSON RPC request.

I still love to know what I did wrong in my approach below.


Definitions:

  • owner = public variable in contract with address type
  • contract = smart-contract that has owner

This is the curl request to get the owner of a contract. I managed to get the owner. (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"}

But when I try to replicate it in Golang (code below), I got json: cannot unmarshal string into Go value of type main.response error. (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
", resp)
}

What did I miss here?

Expected result:

Address in string format. E.g. 0x3ab17372b25154400738C04B04f755321bB5a94b

P/S — I'm aware of abigen and I know it's better and easier to do this using abigen. But I'm trying to solve this specific issue without using abigen method.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

4条回答

  • dtz8044 dtz8044 3年前

    You can solve the problem best using the 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())
    }
    
    点赞 评论 复制链接分享
  • dongling0519 dongling0519 3年前

    If you look at the client library code, you'll see that the JSON RPC response object is already disassembled and either an error is returned on failure, or the actual result parsed: https://github.com/ethereum/go-ethereum/blob/master/rpc/client.go#L277

    The parser however already unwrapped the containing "result" field. Your type still wants to do an additional unwrap:

    type response struct {
        Result string
    }
    

    Drop the outer struct, simply pass a string pointer to the client.Call's first parameter.

    点赞 评论 复制链接分享
  • dongzhi1950 dongzhi1950 3年前

    json: cannot unmarshal string into Go value of type main.response error. I got similar type error when i was unmarshaling a response. It was because the response was actually json string, i mean it had Quotation " as first character. So to be sure you also encountered the same problem, please printf("%v",resp.Result) before unmarshaling in here https://github.com/ethereum/go-ethereum/blob/1ff152f3a43e4adf030ac61eb5d8da345554fc5a/rpc/client.go#L278.

    点赞 评论 复制链接分享
  • douhu5837 douhu5837 3年前

    Your response struct doesn't show the data that the json of the response has

    try this

    type response struct {
        Jsonrpc string `json:"jsonrpc"`
        ID      int    `json:"id"`
        Result  string `json:"result"`
    }
    
    点赞 评论 复制链接分享

相关推荐