Как правильно отправить RPC-вызов с помощью Golang, чтобы получить владельца смарт-контракта?

Обновить

Поскольку я не могу добиться этого, используя подход, описанный в этом вопросе, я создал свою собственную библиотеку, чтобы сделать то же самое (ссылка). Он не полагается на пакет go-ethereum, но использует обычный пакет net/http для выполнения запроса JSON RPC.

Мне все еще нравится знать, что я сделал не так в моем подходе, приведенном ниже.


Определения:

  • владелец = public переменная в контракте с типом address
  • контракт = смарт-контракт, у которого есть владелец

Это запрос curl для получения владельца контракта. Мне удалось заполучить хозяина. (документы JSON RPC)

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 type main.response error. (код go-ethereum, который я использую )

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.


person Zulhilmi Zainudin    schedule 10.11.2018    source источник


Ответы (4)


Лучше всего решить проблему с помощью 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())
}
person user10595796    schedule 12.11.2018
comment
Спасибо. Это наиболее близкое решение. Ценю вашу помощь! - person Zulhilmi Zainudin; 12.11.2018

Если вы посмотрите на код клиентской библиотеки, вы увидите, что объект ответа JSON RPC уже дизассемблирован, и либо при ошибке возвращается ошибка, либо анализируется фактический результат: https://github.com/ethereum/go-ethereum/blob/master/rpc/client.go#L277

Однако синтаксический анализатор уже развернул содержащееся поле «результат». Ваш тип по-прежнему хочет выполнить дополнительное развертывание:

type response struct {
    Result string
}

Отбросьте внешнюю структуру, просто передайте строковый указатель на первый параметр client.Call.

person Péter Szilágyi    schedule 12.11.2018
comment
Извините, @ Péter Szilágyi, я не очень понимаю. Вы можете показать это в коде? Спасибо. - person Zulhilmi Zainudin; 12.11.2018

В вашей структуре ответа не отображаются данные, которые содержит json ответа.

попробуй это

type response struct {
    Jsonrpc string `json:"jsonrpc"`
    ID      int    `json:"id"`
    Result  string `json:"result"`
}
person Vorsprung    schedule 10.11.2018
comment
Спасибо за помощь. К сожалению, я все еще получаю json: cannot unmarshal string into Go value of type main.response ошибку. - person Zulhilmi Zainudin; 10.11.2018
comment
попробуйте настроить ответ. Я не смотрел на библиотеку, которую вы используете, она может отключить jsonrpc или идентификатор - person Vorsprung; 10.11.2018
comment
Я пытался. Я прокомментировал Jsonrpc. Это не удалось. Затем я раскомментировал Jsonrpc и прокомментировал ID. Это все еще не удалось. - person Zulhilmi Zainudin; 10.11.2018
comment
добавьте строку 277 go-ethereum client.go в printf("%v",resp.Result) непосредственно перед тем, как он выдает ошибку. Посмотрите, что он возвращает - person Vorsprung; 10.11.2018

json: невозможно демаршалировать строку в значение Go типа main.response error. У меня возникла ошибка аналогичного типа, когда я демаршалировал ответ. Это произошло потому, что ответ был на самом деле строкой json, я имею в виду, что первым символом была цитата ". Чтобы убедиться, что вы столкнулись с той же проблемой, printf("%v",resp.Result) перед демаршалингом здесь https://github.com/ethereum/go-ethereum/blob/1ff152f3a43e4adf030ac61eb5d8da345554fc5a/rpc/client.go#L278.

person nightfury1204    schedule 10.11.2018