From 959bd21e757287ffebc86a758711af697e4f8ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 26 Aug 2015 20:42:15 +0300 Subject: [PATCH] rpc: first version of an RPC over IPC API generator and API --- cmd/geth/monitorcmd.go | 6 +- rpc/genapi.go | 407 +++++++++++++++++++++++++++++++++++++ rpc/generator/generator.go | 216 ++++++++++++++++++++ rpc/xeth.go | 4 +- 4 files changed, 630 insertions(+), 3 deletions(-) create mode 100644 rpc/genapi.go create mode 100644 rpc/generator/generator.go diff --git a/cmd/geth/monitorcmd.go b/cmd/geth/monitorcmd.go index a45d29b8f2..2f08f16758 100644 --- a/cmd/geth/monitorcmd.go +++ b/cmd/geth/monitorcmd.go @@ -165,7 +165,11 @@ func monitor(ctx *cli.Context) { // retrieveMetrics contacts the attached geth node and retrieves the entire set // of collected system metrics. func retrieveMetrics(xeth *rpc.Xeth) (map[string]interface{}, error) { - return xeth.Call("debug_metrics", []interface{}{true}) + reply, err := xeth.Call("debug_metrics", []interface{}{true}) + if err != nil { + return nil, err + } + return reply.(map[string]interface{}), nil } // resolveMetrics takes a list of input metric patterns, and resolves each to one diff --git a/rpc/genapi.go b/rpc/genapi.go new file mode 100644 index 0000000000..e31ba4b0be --- /dev/null +++ b/rpc/genapi.go @@ -0,0 +1,407 @@ +package rpc + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/compiler" +) + +type GenApi struct { + Db *Db + Miner *Miner + Web3 *Web3 + Net *Net + Personal *Personal + Shh *Shh + Admin *Admin + Debug *Debug + Txpool *Txpool + Eth *Eth +} + +func NewGenApi(xeth *Xeth) *GenApi { + return &GenApi{ + Net: &Net{xeth}, + Personal: &Personal{xeth}, + Shh: &Shh{xeth}, + Db: &Db{xeth}, + Miner: &Miner{xeth}, + Web3: &Web3{xeth}, + Debug: &Debug{xeth}, + Txpool: &Txpool{xeth}, + Eth: &Eth{xeth}, + Admin: &Admin{xeth}, + } +} + +type Net struct { + xeth *Xeth +} + +func (self *Net) PeerCount() (interface{}, error) { + return self.xeth.Call("net_peerCount", nil) +} +func (self *Net) Listening() (interface{}, error) { + return self.xeth.Call("net_listening", nil) +} +func (self *Net) Version() (interface{}, error) { + return self.xeth.Call("net_version", nil) +} + +type Personal struct { + xeth *Xeth +} + +func (self *Personal) ListAccounts() (interface{}, error) { + return self.xeth.Call("personal_listAccounts", nil) +} +func (self *Personal) NewAccount(passphrase string) (interface{}, error) { + return self.xeth.Call("personal_newAccount", []interface{}{passphrase}) +} +func (self *Personal) DeleteAccount(address string, passphrase string) (interface{}, error) { + return self.xeth.Call("personal_deleteAccount", []interface{}{address, passphrase}) +} +func (self *Personal) UnlockAccount(address string, passphrase string, duration int) (interface{}, error) { + return self.xeth.Call("personal_unlockAccount", []interface{}{address, passphrase, duration}) +} + +type Shh struct { + xeth *Xeth +} + +func (self *Shh) Version() (interface{}, error) { + return self.xeth.Call("shh_version", nil) +} +func (self *Shh) Post() (interface{}, error) { + return self.xeth.Call("shh_post", nil) +} +func (self *Shh) HasIdentity() (interface{}, error) { + return self.xeth.Call("shh_hasIdentity", nil) +} +func (self *Shh) NewIdentity() (interface{}, error) { + return self.xeth.Call("shh_newIdentity", nil) +} +func (self *Shh) NewFilter() (interface{}, error) { + return self.xeth.Call("shh_newFilter", nil) +} +func (self *Shh) UninstallFilter() (interface{}, error) { + return self.xeth.Call("shh_uninstallFilter", nil) +} +func (self *Shh) GetFilterChanges() (interface{}, error) { + return self.xeth.Call("shh_getFilterChanges", nil) +} + +type Db struct { + xeth *Xeth +} + +func (self *Db) GetString() (interface{}, error) { + return self.xeth.Call("db_getString", nil) +} +func (self *Db) PutString() (interface{}, error) { + return self.xeth.Call("db_putString", nil) +} +func (self *Db) GetHex() (interface{}, error) { + return self.xeth.Call("db_getHex", nil) +} +func (self *Db) PutHex() (interface{}, error) { + return self.xeth.Call("db_putHex", nil) +} + +type Miner struct { + xeth *Xeth +} + +func (self *Miner) Hashrate() (interface{}, error) { + return self.xeth.Call("miner_hashrate", nil) +} +func (self *Miner) MakeDAG(blockNumber int64) (interface{}, error) { + return self.xeth.Call("miner_makeDAG", []interface{}{blockNumber}) +} +func (self *Miner) SetExtra(data string) (interface{}, error) { + return self.xeth.Call("miner_setExtra", []interface{}{data}) +} +func (self *Miner) SetGasPrice() (interface{}, error) { + return self.xeth.Call("miner_setGasPrice", nil) +} +func (self *Miner) SetEtherbase(etherbase common.Address) (interface{}, error) { + return self.xeth.Call("miner_setEtherbase", []interface{}{etherbase}) +} +func (self *Miner) StartAutoDAG() (interface{}, error) { + return self.xeth.Call("miner_startAutoDAG", nil) +} +func (self *Miner) Start(threads int) (interface{}, error) { + return self.xeth.Call("miner_start", []interface{}{threads}) +} +func (self *Miner) StopAutoDAG() (interface{}, error) { + return self.xeth.Call("miner_stopAutoDAG", nil) +} +func (self *Miner) Stop() (interface{}, error) { + return self.xeth.Call("miner_stop", nil) +} + +type Web3 struct { + xeth *Xeth +} + +func (self *Web3) Sha3(data string) (interface{}, error) { + return self.xeth.Call("web3_sha3", []interface{}{data}) +} +func (self *Web3) ClientVersion() (interface{}, error) { + return self.xeth.Call("web3_clientVersion", nil) +} + +type Debug struct { + xeth *Xeth +} + +func (self *Debug) DumpBlock() (interface{}, error) { + return self.xeth.Call("debug_dumpBlock", nil) +} +func (self *Debug) GetBlockRlp() (interface{}, error) { + return self.xeth.Call("debug_getBlockRlp", nil) +} +func (self *Debug) PrintBlock() (interface{}, error) { + return self.xeth.Call("debug_printBlock", nil) +} +func (self *Debug) ProcessBlock() (interface{}, error) { + return self.xeth.Call("debug_processBlock", nil) +} +func (self *Debug) SeedHash() (interface{}, error) { + return self.xeth.Call("debug_seedHash", nil) +} +func (self *Debug) SetHead() (interface{}, error) { + return self.xeth.Call("debug_setHead", nil) +} +func (self *Debug) Metrics(raw bool) (interface{}, error) { + return self.xeth.Call("debug_metrics", []interface{}{raw}) +} + +type Txpool struct { + xeth *Xeth +} + +func (self *Txpool) Status() (interface{}, error) { + return self.xeth.Call("txpool_status", nil) +} + +type Eth struct { + xeth *Xeth +} + +func (self *Eth) Accounts() (interface{}, error) { + return self.xeth.Call("eth_accounts", nil) +} +func (self *Eth) BlockNumber() (interface{}, error) { + return self.xeth.Call("eth_blockNumber", nil) +} +func (self *Eth) GetBalance(address string, blockNumber int64) (interface{}, error) { + return self.xeth.Call("eth_getBalance", []interface{}{address, blockNumber}) +} +func (self *Eth) ProtocolVersion() (interface{}, error) { + return self.xeth.Call("eth_protocolVersion", nil) +} +func (self *Eth) Coinbase() (interface{}, error) { + return self.xeth.Call("eth_coinbase", nil) +} +func (self *Eth) Mining() (interface{}, error) { + return self.xeth.Call("eth_mining", nil) +} +func (self *Eth) GasPrice(price string) (interface{}, error) { + return self.xeth.Call("eth_gasPrice", []interface{}{price}) +} +func (self *Eth) GetStorage(address string, blockNumber int64) (interface{}, error) { + return self.xeth.Call("eth_getStorage", []interface{}{address, blockNumber}) +} +func (self *Eth) StorageAt(address string, blockNumber int64) (interface{}, error) { + return self.xeth.Call("eth_storageAt", []interface{}{address, blockNumber}) +} +func (self *Eth) GetStorageAt(address string, blockNumber int64, key string) (interface{}, error) { + return self.xeth.Call("eth_getStorageAt", []interface{}{address, blockNumber, key}) +} +func (self *Eth) GetTransactionCount() (interface{}, error) { + return self.xeth.Call("eth_getTransactionCount", nil) +} +func (self *Eth) GetBlockTransactionCountByHash() (interface{}, error) { + return self.xeth.Call("eth_getBlockTransactionCountByHash", nil) +} +func (self *Eth) GetBlockTransactionCountByNumber() (interface{}, error) { + return self.xeth.Call("eth_getBlockTransactionCountByNumber", nil) +} +func (self *Eth) GetUncleCountByBlockHash() (interface{}, error) { + return self.xeth.Call("eth_getUncleCountByBlockHash", nil) +} +func (self *Eth) GetUncleCountByBlockNumber() (interface{}, error) { + return self.xeth.Call("eth_getUncleCountByBlockNumber", nil) +} +func (self *Eth) GetData(address string, blockNumber int64) (interface{}, error) { + return self.xeth.Call("eth_getData", []interface{}{address, blockNumber}) +} +func (self *Eth) GetCode(address string, blockNumber int64) (interface{}, error) { + return self.xeth.Call("eth_getCode", []interface{}{address, blockNumber}) +} +func (self *Eth) Sign() (interface{}, error) { + return self.xeth.Call("eth_sign", nil) +} +func (self *Eth) SendRawTransaction() (interface{}, error) { + return self.xeth.Call("eth_sendRawTransaction", nil) +} +func (self *Eth) SendTransaction() (interface{}, error) { + return self.xeth.Call("eth_sendTransaction", nil) +} +func (self *Eth) Transact() (interface{}, error) { + return self.xeth.Call("eth_transact", nil) +} +func (self *Eth) EstimateGas() (interface{}, error) { + return self.xeth.Call("eth_estimateGas", nil) +} +func (self *Eth) Call(from string, to string, value *big.Int, gas *big.Int, gasPrice *big.Int, data string, blockNumber int64) (interface{}, error) { + return self.xeth.Call("eth_call", []interface{}{from, to, value, gas, gasPrice, data, blockNumber}) +} +func (self *Eth) Flush() (interface{}, error) { + return self.xeth.Call("eth_flush", nil) +} +func (self *Eth) GetBlockByHash(blockHash string, includeTxs bool) (interface{}, error) { + return self.xeth.Call("eth_getBlockByHash", []interface{}{blockHash, includeTxs}) +} +func (self *Eth) GetBlockByNumber(blockNumber int64, includeTxs bool) (interface{}, error) { + return self.xeth.Call("eth_getBlockByNumber", []interface{}{blockNumber, includeTxs}) +} +func (self *Eth) GetTransactionByHash() (interface{}, error) { + return self.xeth.Call("eth_getTransactionByHash", nil) +} +func (self *Eth) GetTransactionByBlockNumberAndIndex() (interface{}, error) { + return self.xeth.Call("eth_getTransactionByBlockNumberAndIndex", nil) +} +func (self *Eth) GetTransactionByBlockHashAndIndex() (interface{}, error) { + return self.xeth.Call("eth_getTransactionByBlockHashAndIndex", nil) +} +func (self *Eth) GetUncleByBlockHashAndIndex() (interface{}, error) { + return self.xeth.Call("eth_getUncleByBlockHashAndIndex", nil) +} +func (self *Eth) GetUncleByBlockNumberAndIndex() (interface{}, error) { + return self.xeth.Call("eth_getUncleByBlockNumberAndIndex", nil) +} +func (self *Eth) GetCompilers() (interface{}, error) { + return self.xeth.Call("eth_getCompilers", nil) +} +func (self *Eth) CompileSolidity() (interface{}, error) { + return self.xeth.Call("eth_compileSolidity", nil) +} +func (self *Eth) NewFilter() (interface{}, error) { + return self.xeth.Call("eth_newFilter", nil) +} +func (self *Eth) NewBlockFilter() (interface{}, error) { + return self.xeth.Call("eth_newBlockFilter", nil) +} +func (self *Eth) NewPendingTransactionFilter() (interface{}, error) { + return self.xeth.Call("eth_newPendingTransactionFilter", nil) +} +func (self *Eth) UninstallFilter() (interface{}, error) { + return self.xeth.Call("eth_uninstallFilter", nil) +} +func (self *Eth) GetFilterChanges() (interface{}, error) { + return self.xeth.Call("eth_getFilterChanges", nil) +} +func (self *Eth) GetFilterLogs() (interface{}, error) { + return self.xeth.Call("eth_getFilterLogs", nil) +} +func (self *Eth) GetLogs() (interface{}, error) { + return self.xeth.Call("eth_getLogs", nil) +} +func (self *Eth) Hashrate() (interface{}, error) { + return self.xeth.Call("eth_hashrate", nil) +} +func (self *Eth) GetWork() (interface{}, error) { + return self.xeth.Call("eth_getWork", nil) +} +func (self *Eth) SubmitWork(nonce uint64, header string, digest string) (interface{}, error) { + return self.xeth.Call("eth_submitWork", []interface{}{nonce, header, digest}) +} +func (self *Eth) SubmitHashrate() (interface{}, error) { + return self.xeth.Call("eth_submitHashrate", nil) +} +func (self *Eth) PendingTransactions() (interface{}, error) { + return self.xeth.Call("eth_pendingTransactions", nil) +} +func (self *Eth) GetTransactionReceipt() (interface{}, error) { + return self.xeth.Call("eth_getTransactionReceipt", nil) +} + +type Admin struct { + xeth *Xeth +} + +func (self *Admin) AddPeer(url string) (interface{}, error) { + return self.xeth.Call("admin_addPeer", []interface{}{url}) +} +func (self *Admin) Peers() (interface{}, error) { + return self.xeth.Call("admin_peers", nil) +} +func (self *Admin) NodeInfo() (interface{}, error) { + return self.xeth.Call("admin_nodeInfo", nil) +} +func (self *Admin) ExportChain() (interface{}, error) { + return self.xeth.Call("admin_exportChain", nil) +} +func (self *Admin) ImportChain() (interface{}, error) { + return self.xeth.Call("admin_importChain", nil) +} +func (self *Admin) Verbosity(level int) (interface{}, error) { + return self.xeth.Call("admin_verbosity", []interface{}{level}) +} +func (self *Admin) ChainSyncStatus() (interface{}, error) { + return self.xeth.Call("admin_chainSyncStatus", nil) +} +func (self *Admin) SetSolc(path string) (interface{}, error) { + return self.xeth.Call("admin_setSolc", []interface{}{path}) +} +func (self *Admin) Datadir() (interface{}, error) { + return self.xeth.Call("admin_datadir", nil) +} +func (self *Admin) StartRPC(listenAddress string, listenPort uint, corsDomain string, apis string) (interface{}, error) { + return self.xeth.Call("admin_startRPC", []interface{}{listenAddress, listenPort, corsDomain, apis}) +} +func (self *Admin) StopRPC() (interface{}, error) { + return self.xeth.Call("admin_stopRPC", nil) +} +func (self *Admin) SetGlobalRegistrar(nameReg string, contractAddress string) (interface{}, error) { + return self.xeth.Call("admin_setGlobalRegistrar", []interface{}{nameReg, contractAddress}) +} +func (self *Admin) SetHashReg(hashReg string, sender string) (interface{}, error) { + return self.xeth.Call("admin_setHashReg", []interface{}{hashReg, sender}) +} +func (self *Admin) SetUrlHint(urlHint string, sender string) (interface{}, error) { + return self.xeth.Call("admin_setUrlHint", []interface{}{urlHint, sender}) +} +func (self *Admin) SaveInfo(contractInfo compiler.ContractInfo, filename string) (interface{}, error) { + return self.xeth.Call("admin_saveInfo", []interface{}{contractInfo, filename}) +} +func (self *Admin) Register(sender string, address string, contentHashHex string) (interface{}, error) { + return self.xeth.Call("admin_register", []interface{}{sender, address, contentHashHex}) +} +func (self *Admin) RegisterUrl(sender string, contentHash string, url string) (interface{}, error) { + return self.xeth.Call("admin_registerUrl", []interface{}{sender, contentHash, url}) +} +func (self *Admin) StartNatSpec() (interface{}, error) { + return self.xeth.Call("admin_startNatSpec", nil) +} +func (self *Admin) StopNatSpec() (interface{}, error) { + return self.xeth.Call("admin_stopNatSpec", nil) +} +func (self *Admin) GetContractInfo(contract string) (interface{}, error) { + return self.xeth.Call("admin_getContractInfo", []interface{}{contract}) +} +func (self *Admin) HttpGet(uri string, path string) (interface{}, error) { + return self.xeth.Call("admin_httpGet", []interface{}{uri, path}) +} +func (self *Admin) SleepBlocks(n int64, timeout int64) (interface{}, error) { + return self.xeth.Call("admin_sleepBlocks", []interface{}{n, timeout}) +} +func (self *Admin) Sleep(s int) (interface{}, error) { + return self.xeth.Call("admin_sleep", []interface{}{s}) +} +func (self *Admin) EnableUserAgent() (interface{}, error) { + return self.xeth.Call("admin_enableUserAgent", nil) +} diff --git a/rpc/generator/generator.go b/rpc/generator/generator.go new file mode 100644 index 0000000000..a535b812c7 --- /dev/null +++ b/rpc/generator/generator.go @@ -0,0 +1,216 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// This is the Go API auto-generator for the RPC APIs. +package main //build !none + +//go:generate go run generator.go + +import ( + "encoding/json" + "fmt" + "go/ast" + "go/parser" + "go/token" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + "unicode" + + "golang.org/x/tools/imports" +) + +// Package description from the go list command +type Package struct { + Name string + Dir string + GoFiles []string +} + +type Endpoint struct { + Method string + Function string + Argument string + Params []string +} + +func main() { + // Iterate over all the API files and collect the top level declarations + api, err := details("github.com/ethereum/go-ethereum/rpc/api") + if err != nil { + log.Fatalf("Failed to retrieve API package details: %v", err) + } + types, values, err := declarations(api) + if err != nil { + log.Fatalf("Failed to collect API declarations: %v", err) + } + // Create the collectors for the sobmodules + modules := make(map[string][]*Endpoint) + + // Iterate over all the API mappings, and locate the RPC function associations + for variable, val := range values { + if strings.HasSuffix(variable, "Mapping") { + for _, mapping := range val.(*ast.CompositeLit).Elts { + // Fetch the name of the RPC function, and the associated argument definition + call := strings.Trim(mapping.(*ast.KeyValueExpr).Key.(*ast.BasicLit).Value, "\"") + args := mapping.(*ast.KeyValueExpr).Value.(*ast.SelectorExpr).Sel.Name + "Args" + + // Generate the submodule and function names + module := strings.Split(call, "_")[0] + module = string(unicode.ToUpper(rune(module[0]))) + module[1:] + function := strings.Split(call, "_")[1] + function = string(unicode.ToUpper(rune(function[0]))) + function[1:] + + // Generate the parameter list + params, paramList := []string{}, []string{} + if arg := types[args]; arg != nil { + for _, field := range arg.Type.(*ast.StructType).Fields.List { + variable := field.Names[0].String() + variable = string(unicode.ToLower(rune(variable[0]))) + variable[1:] + + kind := "" + switch t := field.Type.(type) { + case *ast.Ident: + kind = t.String() + case *ast.SelectorExpr: + kind = t.X.(*ast.Ident).String() + "." + t.Sel.String() + case *ast.StarExpr: + switch sub := t.X.(type) { + case *ast.Ident: + kind = "*" + sub.String() + case *ast.SelectorExpr: + kind = "*" + sub.X.(*ast.Ident).String() + "." + sub.Sel.String() + default: + log.Fatalf("Unknown pointer subtype: %v", sub) + } + default: + log.Fatalf("Unknown type: %v", t) + } + params = append(params, fmt.Sprintf("%s %s", variable, kind)) + paramList = append(paramList, variable) + } + } + // Append the function to the sobmodule collection + modules[module] = append(modules[module], &Endpoint{ + Method: call, + Function: fmt.Sprintf("%s(%s)", function, strings.Join(params, ",")), + Argument: args, + Params: paramList, + }) + } + } + } + // Start generating the client API + client := "package rpc\n" + + // Generate the client struct with all its submodules + client += fmt.Sprintf("type GenApi struct {\n") + for module, _ := range modules { + client += fmt.Sprintf("%s *%s\n", module, module) + } + client += fmt.Sprintf("}\n") + + // Generate the API constructor to create the individual submodules + client += fmt.Sprint("func NewGenApi(xeth *Xeth) *GenApi {\n") + client += fmt.Sprint("return &GenApi{\n") + for module, _ := range modules { + client += fmt.Sprintf("%s: &%s{xeth},\n", module, module) + } + client += fmt.Sprintf("}}\n") + + // Generate each of the client API calls + for module, endpoints := range modules { + client += fmt.Sprintf("\ntype %s struct {\n xeth *Xeth\n}\n", module) + for _, endpoint := range endpoints { + client += fmt.Sprintf("func (self *%s) %s (interface{}, error) {\n", module, endpoint.Function) + if len(endpoint.Params) == 0 { + client += fmt.Sprintf("return self.xeth.Call(\"%s\", nil)\n", endpoint.Method) + } else { + client += fmt.Sprintf("return self.xeth.Call(\"%s\", []interface{}{%s})\n", endpoint.Method, strings.Join(endpoint.Params, ",")) + } + client += fmt.Sprintf("}\n") + } + } + // Format the final code and output + if blob, err := imports.Process("", []byte(client), nil); err != nil { + log.Fatalf("Failed to format output code: %v", err) + } else { + fmt.Println(string(blob)) + } +} + +// Loads the details of the Go package. +func details(name string) (*Package, error) { + // Create the command to retrieve the package infos + cmd := exec.Command("go", "list", "-e", "-json", name) + + // Retrieve the output, redirect the errors + out, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + cmd.Stderr = os.Stderr + + // Start executing and parse the results + if err := cmd.Start(); err != nil { + return nil, err + } + defer cmd.Process.Kill() + + info := new(Package) + if err := json.NewDecoder(out).Decode(&info); err != nil { + return nil, err + } + // Clean up and return + if err := cmd.Wait(); err != nil { + return nil, err + } + return info, nil +} + +// Iterates over a package contents and collects interesting declarations. +func declarations(pack *Package) (map[string]*ast.TypeSpec, map[string]ast.Expr, error) { + types := make(map[string]*ast.TypeSpec) + values := make(map[string]ast.Expr) + + for _, path := range pack.GoFiles { + // Parse the specified source file + fileSet := token.NewFileSet() + tree, err := parser.ParseFile(fileSet, filepath.Join(pack.Dir, path), nil, parser.ParseComments) + if err != nil { + return nil, nil, err + } + // Collect all top level declarations + for _, decl := range tree.Decls { + switch decl := decl.(type) { + case *ast.GenDecl: + for _, spec := range decl.Specs { + switch spec := spec.(type) { + case *ast.ValueSpec: + for i, name := range spec.Names { + values[name.String()] = spec.Values[i] + } + case *ast.TypeSpec: + types[spec.Name.String()] = spec + } + } + } + } + } + return types, values, nil +} diff --git a/rpc/xeth.go b/rpc/xeth.go index 9527a96c00..25a4d98fd8 100644 --- a/rpc/xeth.go +++ b/rpc/xeth.go @@ -41,7 +41,7 @@ func NewXeth(client comms.EthereumClient) *Xeth { } // Call invokes a method with the given parameters are the remote node. -func (self *Xeth) Call(method string, params []interface{}) (map[string]interface{}, error) { +func (self *Xeth) Call(method string, params []interface{}) (interface{}, error) { // Assemble the json RPC request data, err := json.Marshal(params) if err != nil { @@ -69,7 +69,7 @@ func (self *Xeth) Call(method string, params []interface{}) (map[string]interfac return nil, fmt.Errorf("Method invocation failed: %v", failure.Error) case isSuccessResponse: - return success.Result.(map[string]interface{}), nil + return success.Result, nil default: return nil, fmt.Errorf("Invalid response type: %v", reflect.TypeOf(res))