doufuxi7093
2018-11-10 09:47
浏览 254
已采纳

如何使用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 2018-11-12 11:06
    已采纳

    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())
    }
    
    点赞 打赏 评论
  • douhu5837 2018-11-10 10:02

    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"`
    }
    
    点赞 打赏 评论
  • dongzhi1950 2018-11-10 17:39

    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.

    点赞 打赏 评论
  • dongling0519 2018-11-12 08:58

    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.

    点赞 打赏 评论

相关推荐 更多相似问题