mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 05:06:43 +00:00
Split RPC API into multiple seperate smaller API's which can be offered over different RPC mechanisms
This commit is contained in:
parent
5b14fdb94b
commit
0eca879627
20 changed files with 2453 additions and 8 deletions
6
cmd/console/contracts.go
Normal file
6
cmd/console/contracts.go
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
var (
|
||||||
|
globalRegistrar = `var GlobalRegistrar = web3.eth.contract([{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},{"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}]);`
|
||||||
|
globalRegistrarAddr = "0xc6d9d2cd449a754c494264e1809c50e34d64562b"
|
||||||
|
)
|
||||||
275
cmd/console/js.go
Normal file
275
cmd/console/js.go
Normal file
|
|
@ -0,0 +1,275 @@
|
||||||
|
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This 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
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
// MA 02110-1301 USA
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/common/docserver"
|
||||||
|
re "github.com/ethereum/go-ethereum/jsre"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/peterh/liner"
|
||||||
|
"github.com/robertkrimen/otto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type prompter interface {
|
||||||
|
AppendHistory(string)
|
||||||
|
Prompt(p string) (string, error)
|
||||||
|
PasswordPrompt(p string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dumbterm struct{ r *bufio.Reader }
|
||||||
|
|
||||||
|
func (r dumbterm) Prompt(p string) (string, error) {
|
||||||
|
fmt.Print(p)
|
||||||
|
line, err := r.r.ReadString('\n')
|
||||||
|
return strings.TrimSuffix(line, "\n"), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r dumbterm) PasswordPrompt(p string) (string, error) {
|
||||||
|
fmt.Println("!! Unsupported terminal, password will echo.")
|
||||||
|
fmt.Print(p)
|
||||||
|
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||||
|
fmt.Println()
|
||||||
|
return input, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r dumbterm) AppendHistory(string) {}
|
||||||
|
|
||||||
|
type jsre struct {
|
||||||
|
re *re.JSRE
|
||||||
|
wait chan *big.Int
|
||||||
|
ps1 string
|
||||||
|
atexit func()
|
||||||
|
datadir string
|
||||||
|
prompter
|
||||||
|
}
|
||||||
|
|
||||||
|
func newJSRE(datadir, libPath string) *jsre {
|
||||||
|
js := &jsre{ps1: "> "}
|
||||||
|
js.wait = make(chan *big.Int)
|
||||||
|
|
||||||
|
// update state in separare forever blocks
|
||||||
|
js.re = re.New(libPath)
|
||||||
|
js.apiBindings()
|
||||||
|
// js.adminBindings()
|
||||||
|
|
||||||
|
if !liner.TerminalSupported() {
|
||||||
|
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
|
||||||
|
} else {
|
||||||
|
lr := liner.NewLiner()
|
||||||
|
js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) })
|
||||||
|
lr.SetCtrlCAborts(true)
|
||||||
|
js.prompter = lr
|
||||||
|
js.atexit = func() {
|
||||||
|
js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
|
||||||
|
lr.Close()
|
||||||
|
close(js.wait)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return js
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *jsre) apiBindings() {
|
||||||
|
ethApi := rpc.NewEthereumApi(nil)
|
||||||
|
jeth := rpc.NewJeth(ethApi, js.re)
|
||||||
|
|
||||||
|
js.re.Set("jeth", struct{}{})
|
||||||
|
t, _ := js.re.Get("jeth")
|
||||||
|
jethObj := t.Object()
|
||||||
|
jethObj.Set("send", jeth.Send)
|
||||||
|
jethObj.Set("sendAsync", jeth.Send)
|
||||||
|
|
||||||
|
err := js.re.Compile("bignumber.js", re.BigNumber_JS)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Error loading bignumber.js: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = js.re.Compile("ethereum.js", re.Ethereum_JS)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Error loading ethereum.js: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = js.re.Eval("var web3 = require('web3');")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Error requiring web3: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = js.re.Eval("web3.setProvider(jeth)")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Error setting web3 provider: %v", err)
|
||||||
|
}
|
||||||
|
_, err = js.re.Eval(`
|
||||||
|
var eth = web3.eth;
|
||||||
|
var shh = web3.shh;
|
||||||
|
var db = web3.db;
|
||||||
|
var net = web3.net;
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Error setting namespaces: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ds, _ = docserver.New("/")
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (self *jsre) ConfirmTransaction(tx string) bool {
|
||||||
|
if self.ethereum.NatSpec {
|
||||||
|
notice := natspec.GetNotice(self.xeth, tx, ds)
|
||||||
|
fmt.Println(notice)
|
||||||
|
answer, _ := self.Prompt("Confirm Transaction [y/n]")
|
||||||
|
return strings.HasPrefix(strings.Trim(answer, " "), "y")
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) UnlockAccount(addr []byte) bool {
|
||||||
|
fmt.Printf("Please unlock account %x.\n", addr)
|
||||||
|
pass, err := self.PasswordPrompt("Passphrase: ")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// TODO: allow retry
|
||||||
|
if err := self.ethereum.AccountManager().Unlock(common.BytesToAddress(addr), pass); err != nil {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
fmt.Println("Account is now unlocked for this session.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (self *jsre) exec(filename string) error {
|
||||||
|
if err := self.re.Exec(filename); err != nil {
|
||||||
|
self.re.Stop(false)
|
||||||
|
return fmt.Errorf("Javascript Error: %v", err)
|
||||||
|
}
|
||||||
|
self.re.Stop(true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) interactive() {
|
||||||
|
// Read input lines.
|
||||||
|
prompt := make(chan string)
|
||||||
|
inputln := make(chan string)
|
||||||
|
go func() {
|
||||||
|
defer close(inputln)
|
||||||
|
for {
|
||||||
|
line, err := self.Prompt(<-prompt)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
inputln <- line
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// Wait for Ctrl-C, too.
|
||||||
|
sig := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sig, os.Interrupt)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if self.atexit != nil {
|
||||||
|
self.atexit()
|
||||||
|
}
|
||||||
|
self.re.Stop(false)
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
prompt <- self.ps1
|
||||||
|
select {
|
||||||
|
case <-sig:
|
||||||
|
fmt.Println("caught interrupt, exiting")
|
||||||
|
return
|
||||||
|
case input, ok := <-inputln:
|
||||||
|
if !ok || indentCount <= 0 && input == "exit" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if input == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
str += input + "\n"
|
||||||
|
self.setIndent()
|
||||||
|
if indentCount <= 0 {
|
||||||
|
hist := str[:len(str)-1]
|
||||||
|
self.AppendHistory(hist)
|
||||||
|
self.parseInput(str)
|
||||||
|
str = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) withHistory(op func(*os.File)) {
|
||||||
|
hist, err := os.OpenFile(filepath.Join(self.datadir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("unable to open history file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
op(hist)
|
||||||
|
hist.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) parseInput(code string) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println("[native] error", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
value, err := self.re.Run(code)
|
||||||
|
if err != nil {
|
||||||
|
if ottoErr, ok := err.(*otto.Error); ok {
|
||||||
|
fmt.Println(ottoErr.String())
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.printValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var indentCount = 0
|
||||||
|
var str = ""
|
||||||
|
|
||||||
|
func (self *jsre) setIndent() {
|
||||||
|
open := strings.Count(str, "{")
|
||||||
|
open += strings.Count(str, "(")
|
||||||
|
closed := strings.Count(str, "}")
|
||||||
|
closed += strings.Count(str, ")")
|
||||||
|
indentCount = open - closed
|
||||||
|
if indentCount <= 0 {
|
||||||
|
self.ps1 = "> "
|
||||||
|
} else {
|
||||||
|
self.ps1 = strings.Join(make([]string, indentCount*2), "..")
|
||||||
|
self.ps1 += " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *jsre) printValue(v interface{}) {
|
||||||
|
val, err := self.re.PrettyPrint(v)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("%v", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
48
cmd/console/main.go
Normal file
48
cmd/console/main.go
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
This file is part of go-ethereum
|
||||||
|
|
||||||
|
go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
go-ethereum 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @authors
|
||||||
|
* Jeffrey Wilcke <i@jev.io>
|
||||||
|
*/
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/mattn/go-colorable"
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClientIdentifier = "Geth console"
|
||||||
|
Version = "0.9.26"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Wrap the standard output with a colorified stream (windows)
|
||||||
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
|
if pr, pw, err := os.Pipe(); err == nil {
|
||||||
|
go io.Copy(colorable.NewColorableStdout(), pr)
|
||||||
|
os.Stdout = pw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO, datadir + jspath
|
||||||
|
repl := newJSRE("/home/bas/.ethereum", ".")
|
||||||
|
repl.interactive()
|
||||||
|
}
|
||||||
|
|
@ -238,6 +238,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
||||||
utils.RPCEnabledFlag,
|
utils.RPCEnabledFlag,
|
||||||
utils.RPCListenAddrFlag,
|
utils.RPCListenAddrFlag,
|
||||||
utils.RPCPortFlag,
|
utils.RPCPortFlag,
|
||||||
|
utils.IPCEnabledFlag,
|
||||||
utils.WhisperEnabledFlag,
|
utils.WhisperEnabledFlag,
|
||||||
utils.VMDebugFlag,
|
utils.VMDebugFlag,
|
||||||
utils.ProtocolVersionFlag,
|
utils.ProtocolVersionFlag,
|
||||||
|
|
@ -386,6 +387,11 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
||||||
utils.Fatalf("Error starting RPC: %v", err)
|
utils.Fatalf("Error starting RPC: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ctx.GlobalBool(utils.IPCEnabledFlag.Name) {
|
||||||
|
if err := utils.StartIPC(eth, ctx); err != nil {
|
||||||
|
utils.Fatalf("Error starting IPC: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
||||||
if err := eth.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil {
|
if err := eth.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil {
|
||||||
utils.Fatalf("%v", err)
|
utils.Fatalf("%v", err)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/api"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -201,6 +204,10 @@ var (
|
||||||
Usage: "Domain on which to send Access-Control-Allow-Origin header",
|
Usage: "Domain on which to send Access-Control-Allow-Origin header",
|
||||||
Value: "",
|
Value: "",
|
||||||
}
|
}
|
||||||
|
IPCEnabledFlag = cli.BoolFlag{
|
||||||
|
Name: "ipc",
|
||||||
|
Usage: "Enable the IPC-RPC server",
|
||||||
|
}
|
||||||
// Network Settings
|
// Network Settings
|
||||||
MaxPeersFlag = cli.IntFlag{
|
MaxPeersFlag = cli.IntFlag{
|
||||||
Name: "maxpeers",
|
Name: "maxpeers",
|
||||||
|
|
@ -369,6 +376,21 @@ func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error {
|
||||||
return rpc.Start(xeth, config)
|
return rpc.Start(xeth, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StartIPC(eth *eth.Ethereum, ctx *cli.Context) error {
|
||||||
|
config := comms.IpcConfig{
|
||||||
|
Endpoint: ctx.GlobalString(DataDirFlag.Name) + "/geth.sock",
|
||||||
|
}
|
||||||
|
|
||||||
|
xeth := xeth.New(eth, nil)
|
||||||
|
// offered API over IPC
|
||||||
|
codec := codec.JSON
|
||||||
|
web3Api := api.NewWeb3(xeth, codec)
|
||||||
|
ethApi := api.NewEth(xeth, codec)
|
||||||
|
netApi := api.NewNet(xeth, codec)
|
||||||
|
|
||||||
|
return comms.StartIpc(config, codec, web3Api, ethApi, netApi)
|
||||||
|
}
|
||||||
|
|
||||||
func StartPProf(ctx *cli.Context) {
|
func StartPProf(ctx *cli.Context) {
|
||||||
address := fmt.Sprintf("localhost:%d", ctx.GlobalInt(PProfPortFlag.Name))
|
address := fmt.Sprintf("localhost:%d", ctx.GlobalInt(PProfPortFlag.Name))
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
||||||
44
rpc/api/api.go
Normal file
44
rpc/api/api.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Descriptor for all API implementations
|
||||||
|
type Ethereum interface {
|
||||||
|
// Execute single API request
|
||||||
|
Execute(*shared.Request) (interface{}, error)
|
||||||
|
// List with supported methods
|
||||||
|
Methods() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type mergedEthereumApi struct {
|
||||||
|
apis map[string]Ethereum
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMergedEthereumApi(apis ...Ethereum) *mergedEthereumApi {
|
||||||
|
mergedApi := new(mergedEthereumApi)
|
||||||
|
mergedApi.apis = make(map[string]Ethereum)
|
||||||
|
|
||||||
|
for _, api := range apis {
|
||||||
|
for _, method := range api.Methods() {
|
||||||
|
mergedApi.apis[method] = api
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mergedApi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mergedEthereumApi) Methods() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mergedEthereumApi) Execute(req *shared.Request) (interface{}, error) {
|
||||||
|
if api, found := self.apis[req.Method]; found {
|
||||||
|
return api.Execute(req)
|
||||||
|
}
|
||||||
|
return nil, shared.NewNotImplementedError(req.Method)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Merge(apis ...Ethereum) Ethereum {
|
||||||
|
return newMergedEthereumApi(apis...)
|
||||||
|
}
|
||||||
11
rpc/api/errors.go
Normal file
11
rpc/api/errors.go
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type NotImplementedError struct {
|
||||||
|
Method string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NotImplementedError) Error() string {
|
||||||
|
return fmt.Sprintf("%s method not implemented", e.Method)
|
||||||
|
}
|
||||||
1000
rpc/api/eth.go
Normal file
1000
rpc/api/eth.go
Normal file
File diff suppressed because it is too large
Load diff
69
rpc/api/net.go
Normal file
69
rpc/api/net.go
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// mapping between methods and handlers
|
||||||
|
netMapping = map[string]nethandler{
|
||||||
|
"net_version": (*net).Version,
|
||||||
|
"net_peerCount": (*net).PeerCount,
|
||||||
|
"net_listening": (*net).IsListening,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// net callback handler
|
||||||
|
type nethandler func(*net, *shared.Request) (interface{}, error)
|
||||||
|
|
||||||
|
// net api provider
|
||||||
|
type net struct {
|
||||||
|
xeth *xeth.XEth
|
||||||
|
methods map[string]nethandler
|
||||||
|
codec codec.ApiCoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new net api instance
|
||||||
|
func NewNet(xeth *xeth.XEth, coder codec.Codec) *net {
|
||||||
|
return &net{
|
||||||
|
xeth: xeth,
|
||||||
|
methods: netMapping,
|
||||||
|
codec: coder.New(nil),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collection with supported methods
|
||||||
|
func (self *net) Methods() []string {
|
||||||
|
methods := make([]string, len(self.methods))
|
||||||
|
i := 0
|
||||||
|
for k := range self.methods {
|
||||||
|
methods[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return methods
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute given request
|
||||||
|
func (self *net) Execute(req *shared.Request) (interface{}, error) {
|
||||||
|
if callback, ok := self.methods[req.Method]; ok {
|
||||||
|
return callback(self, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, shared.NewNotImplementedError(req.Method)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network version
|
||||||
|
func (self *net) Version(req *shared.Request) (interface{}, error) {
|
||||||
|
return self.xeth.NetworkVersion(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of connected peers
|
||||||
|
func (self *net) PeerCount(req *shared.Request) (interface{}, error) {
|
||||||
|
return newHexNum(self.xeth.PeerCount()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *net) IsListening(req *shared.Request) (interface{}, error) {
|
||||||
|
return self.xeth.IsListening(), nil
|
||||||
|
}
|
||||||
460
rpc/api/utils.go
Normal file
460
rpc/api/utils.go
Normal file
|
|
@ -0,0 +1,460 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
type hexdata struct {
|
||||||
|
data []byte
|
||||||
|
isNil bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *hexdata) String() string {
|
||||||
|
return "0x" + common.Bytes2Hex(d.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *hexdata) MarshalJSON() ([]byte, error) {
|
||||||
|
if d.isNil {
|
||||||
|
return json.Marshal(nil)
|
||||||
|
}
|
||||||
|
return json.Marshal(d.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHexData(input interface{}) *hexdata {
|
||||||
|
d := new(hexdata)
|
||||||
|
|
||||||
|
if input == nil {
|
||||||
|
d.isNil = true
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
switch input := input.(type) {
|
||||||
|
case []byte:
|
||||||
|
d.data = input
|
||||||
|
case common.Hash:
|
||||||
|
d.data = input.Bytes()
|
||||||
|
case *common.Hash:
|
||||||
|
if input == nil {
|
||||||
|
d.isNil = true
|
||||||
|
} else {
|
||||||
|
d.data = input.Bytes()
|
||||||
|
}
|
||||||
|
case common.Address:
|
||||||
|
d.data = input.Bytes()
|
||||||
|
case *common.Address:
|
||||||
|
if input == nil {
|
||||||
|
d.isNil = true
|
||||||
|
} else {
|
||||||
|
d.data = input.Bytes()
|
||||||
|
}
|
||||||
|
case types.Bloom:
|
||||||
|
d.data = input.Bytes()
|
||||||
|
case *types.Bloom:
|
||||||
|
if input == nil {
|
||||||
|
d.isNil = true
|
||||||
|
} else {
|
||||||
|
d.data = input.Bytes()
|
||||||
|
}
|
||||||
|
case *big.Int:
|
||||||
|
if input == nil {
|
||||||
|
d.isNil = true
|
||||||
|
} else {
|
||||||
|
d.data = input.Bytes()
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
d.data = big.NewInt(input).Bytes()
|
||||||
|
case uint64:
|
||||||
|
buff := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(buff, input)
|
||||||
|
d.data = buff
|
||||||
|
case int:
|
||||||
|
d.data = big.NewInt(int64(input)).Bytes()
|
||||||
|
case uint:
|
||||||
|
d.data = big.NewInt(int64(input)).Bytes()
|
||||||
|
case int8:
|
||||||
|
d.data = big.NewInt(int64(input)).Bytes()
|
||||||
|
case uint8:
|
||||||
|
d.data = big.NewInt(int64(input)).Bytes()
|
||||||
|
case int16:
|
||||||
|
d.data = big.NewInt(int64(input)).Bytes()
|
||||||
|
case uint16:
|
||||||
|
buff := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(buff, input)
|
||||||
|
d.data = buff
|
||||||
|
case int32:
|
||||||
|
d.data = big.NewInt(int64(input)).Bytes()
|
||||||
|
case uint32:
|
||||||
|
buff := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(buff, input)
|
||||||
|
d.data = buff
|
||||||
|
case string: // hexstring
|
||||||
|
// aaargh ffs TODO: avoid back-and-forth hex encodings where unneeded
|
||||||
|
bytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
|
||||||
|
if err != nil {
|
||||||
|
d.isNil = true
|
||||||
|
} else {
|
||||||
|
d.data = bytes
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
d.isNil = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
type hexnum struct {
|
||||||
|
data []byte
|
||||||
|
isNil bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *hexnum) String() string {
|
||||||
|
// Get hex string from bytes
|
||||||
|
out := common.Bytes2Hex(d.data)
|
||||||
|
// Trim leading 0s
|
||||||
|
out = strings.TrimLeft(out, "0")
|
||||||
|
// Output "0x0" when value is 0
|
||||||
|
if len(out) == 0 {
|
||||||
|
out = "0"
|
||||||
|
}
|
||||||
|
return "0x" + out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *hexnum) MarshalJSON() ([]byte, error) {
|
||||||
|
if d.isNil {
|
||||||
|
return json.Marshal(nil)
|
||||||
|
}
|
||||||
|
return json.Marshal(d.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHexNum(input interface{}) *hexnum {
|
||||||
|
d := new(hexnum)
|
||||||
|
|
||||||
|
d.data = newHexData(input).data
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockRes struct {
|
||||||
|
fullTx bool
|
||||||
|
|
||||||
|
BlockNumber *hexnum `json:"number"`
|
||||||
|
BlockHash *hexdata `json:"hash"`
|
||||||
|
ParentHash *hexdata `json:"parentHash"`
|
||||||
|
Nonce *hexdata `json:"nonce"`
|
||||||
|
Sha3Uncles *hexdata `json:"sha3Uncles"`
|
||||||
|
LogsBloom *hexdata `json:"logsBloom"`
|
||||||
|
TransactionRoot *hexdata `json:"transactionsRoot"`
|
||||||
|
StateRoot *hexdata `json:"stateRoot"`
|
||||||
|
Miner *hexdata `json:"miner"`
|
||||||
|
Difficulty *hexnum `json:"difficulty"`
|
||||||
|
TotalDifficulty *hexnum `json:"totalDifficulty"`
|
||||||
|
Size *hexnum `json:"size"`
|
||||||
|
ExtraData *hexdata `json:"extraData"`
|
||||||
|
GasLimit *hexnum `json:"gasLimit"`
|
||||||
|
GasUsed *hexnum `json:"gasUsed"`
|
||||||
|
UnixTimestamp *hexnum `json:"timestamp"`
|
||||||
|
Transactions []*TransactionRes `json:"transactions"`
|
||||||
|
Uncles []*UncleRes `json:"uncles"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BlockRes) MarshalJSON() ([]byte, error) {
|
||||||
|
if b.fullTx {
|
||||||
|
var ext struct {
|
||||||
|
BlockNumber *hexnum `json:"number"`
|
||||||
|
BlockHash *hexdata `json:"hash"`
|
||||||
|
ParentHash *hexdata `json:"parentHash"`
|
||||||
|
Nonce *hexdata `json:"nonce"`
|
||||||
|
Sha3Uncles *hexdata `json:"sha3Uncles"`
|
||||||
|
LogsBloom *hexdata `json:"logsBloom"`
|
||||||
|
TransactionRoot *hexdata `json:"transactionsRoot"`
|
||||||
|
StateRoot *hexdata `json:"stateRoot"`
|
||||||
|
Miner *hexdata `json:"miner"`
|
||||||
|
Difficulty *hexnum `json:"difficulty"`
|
||||||
|
TotalDifficulty *hexnum `json:"totalDifficulty"`
|
||||||
|
Size *hexnum `json:"size"`
|
||||||
|
ExtraData *hexdata `json:"extraData"`
|
||||||
|
GasLimit *hexnum `json:"gasLimit"`
|
||||||
|
GasUsed *hexnum `json:"gasUsed"`
|
||||||
|
UnixTimestamp *hexnum `json:"timestamp"`
|
||||||
|
Transactions []*TransactionRes `json:"transactions"`
|
||||||
|
Uncles []*hexdata `json:"uncles"`
|
||||||
|
}
|
||||||
|
|
||||||
|
ext.BlockNumber = b.BlockNumber
|
||||||
|
ext.BlockHash = b.BlockHash
|
||||||
|
ext.ParentHash = b.ParentHash
|
||||||
|
ext.Nonce = b.Nonce
|
||||||
|
ext.Sha3Uncles = b.Sha3Uncles
|
||||||
|
ext.LogsBloom = b.LogsBloom
|
||||||
|
ext.TransactionRoot = b.TransactionRoot
|
||||||
|
ext.StateRoot = b.StateRoot
|
||||||
|
ext.Miner = b.Miner
|
||||||
|
ext.Difficulty = b.Difficulty
|
||||||
|
ext.TotalDifficulty = b.TotalDifficulty
|
||||||
|
ext.Size = b.Size
|
||||||
|
ext.ExtraData = b.ExtraData
|
||||||
|
ext.GasLimit = b.GasLimit
|
||||||
|
ext.GasUsed = b.GasUsed
|
||||||
|
ext.UnixTimestamp = b.UnixTimestamp
|
||||||
|
ext.Transactions = b.Transactions
|
||||||
|
ext.Uncles = make([]*hexdata, len(b.Uncles))
|
||||||
|
for i, u := range b.Uncles {
|
||||||
|
ext.Uncles[i] = u.BlockHash
|
||||||
|
}
|
||||||
|
return json.Marshal(ext)
|
||||||
|
} else {
|
||||||
|
var ext struct {
|
||||||
|
BlockNumber *hexnum `json:"number"`
|
||||||
|
BlockHash *hexdata `json:"hash"`
|
||||||
|
ParentHash *hexdata `json:"parentHash"`
|
||||||
|
Nonce *hexdata `json:"nonce"`
|
||||||
|
Sha3Uncles *hexdata `json:"sha3Uncles"`
|
||||||
|
LogsBloom *hexdata `json:"logsBloom"`
|
||||||
|
TransactionRoot *hexdata `json:"transactionsRoot"`
|
||||||
|
StateRoot *hexdata `json:"stateRoot"`
|
||||||
|
Miner *hexdata `json:"miner"`
|
||||||
|
Difficulty *hexnum `json:"difficulty"`
|
||||||
|
TotalDifficulty *hexnum `json:"totalDifficulty"`
|
||||||
|
Size *hexnum `json:"size"`
|
||||||
|
ExtraData *hexdata `json:"extraData"`
|
||||||
|
GasLimit *hexnum `json:"gasLimit"`
|
||||||
|
GasUsed *hexnum `json:"gasUsed"`
|
||||||
|
UnixTimestamp *hexnum `json:"timestamp"`
|
||||||
|
Transactions []*hexdata `json:"transactions"`
|
||||||
|
Uncles []*hexdata `json:"uncles"`
|
||||||
|
}
|
||||||
|
|
||||||
|
ext.BlockNumber = b.BlockNumber
|
||||||
|
ext.BlockHash = b.BlockHash
|
||||||
|
ext.ParentHash = b.ParentHash
|
||||||
|
ext.Nonce = b.Nonce
|
||||||
|
ext.Sha3Uncles = b.Sha3Uncles
|
||||||
|
ext.LogsBloom = b.LogsBloom
|
||||||
|
ext.TransactionRoot = b.TransactionRoot
|
||||||
|
ext.StateRoot = b.StateRoot
|
||||||
|
ext.Miner = b.Miner
|
||||||
|
ext.Difficulty = b.Difficulty
|
||||||
|
ext.TotalDifficulty = b.TotalDifficulty
|
||||||
|
ext.Size = b.Size
|
||||||
|
ext.ExtraData = b.ExtraData
|
||||||
|
ext.GasLimit = b.GasLimit
|
||||||
|
ext.GasUsed = b.GasUsed
|
||||||
|
ext.UnixTimestamp = b.UnixTimestamp
|
||||||
|
ext.Transactions = make([]*hexdata, len(b.Transactions))
|
||||||
|
for i, tx := range b.Transactions {
|
||||||
|
ext.Transactions[i] = tx.Hash
|
||||||
|
}
|
||||||
|
ext.Uncles = make([]*hexdata, len(b.Uncles))
|
||||||
|
for i, u := range b.Uncles {
|
||||||
|
ext.Uncles[i] = u.BlockHash
|
||||||
|
}
|
||||||
|
return json.Marshal(ext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBlockRes(block *types.Block, fullTx bool) *BlockRes {
|
||||||
|
if block == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res := new(BlockRes)
|
||||||
|
res.fullTx = fullTx
|
||||||
|
res.BlockNumber = newHexNum(block.Number())
|
||||||
|
res.BlockHash = newHexData(block.Hash())
|
||||||
|
res.ParentHash = newHexData(block.ParentHash())
|
||||||
|
res.Nonce = newHexData(block.Nonce())
|
||||||
|
res.Sha3Uncles = newHexData(block.Header().UncleHash)
|
||||||
|
res.LogsBloom = newHexData(block.Bloom())
|
||||||
|
res.TransactionRoot = newHexData(block.Header().TxHash)
|
||||||
|
res.StateRoot = newHexData(block.Root())
|
||||||
|
res.Miner = newHexData(block.Header().Coinbase)
|
||||||
|
res.Difficulty = newHexNum(block.Difficulty())
|
||||||
|
res.TotalDifficulty = newHexNum(block.Td)
|
||||||
|
res.Size = newHexNum(block.Size().Int64())
|
||||||
|
res.ExtraData = newHexData(block.Header().Extra)
|
||||||
|
res.GasLimit = newHexNum(block.GasLimit())
|
||||||
|
res.GasUsed = newHexNum(block.GasUsed())
|
||||||
|
res.UnixTimestamp = newHexNum(block.Time())
|
||||||
|
|
||||||
|
res.Transactions = make([]*TransactionRes, len(block.Transactions()))
|
||||||
|
for i, tx := range block.Transactions() {
|
||||||
|
res.Transactions[i] = NewTransactionRes(tx)
|
||||||
|
res.Transactions[i].BlockHash = res.BlockHash
|
||||||
|
res.Transactions[i].BlockNumber = res.BlockNumber
|
||||||
|
res.Transactions[i].TxIndex = newHexNum(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Uncles = make([]*UncleRes, len(block.Uncles()))
|
||||||
|
for i, uncle := range block.Uncles() {
|
||||||
|
res.Uncles[i] = NewUncleRes(uncle)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionRes struct {
|
||||||
|
Hash *hexdata `json:"hash"`
|
||||||
|
Nonce *hexnum `json:"nonce"`
|
||||||
|
BlockHash *hexdata `json:"blockHash"`
|
||||||
|
BlockNumber *hexnum `json:"blockNumber"`
|
||||||
|
TxIndex *hexnum `json:"transactionIndex"`
|
||||||
|
From *hexdata `json:"from"`
|
||||||
|
To *hexdata `json:"to"`
|
||||||
|
Value *hexnum `json:"value"`
|
||||||
|
Gas *hexnum `json:"gas"`
|
||||||
|
GasPrice *hexnum `json:"gasPrice"`
|
||||||
|
Input *hexdata `json:"input"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransactionRes(tx *types.Transaction) *TransactionRes {
|
||||||
|
if tx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var v = new(TransactionRes)
|
||||||
|
v.Hash = newHexData(tx.Hash())
|
||||||
|
v.Nonce = newHexNum(tx.Nonce())
|
||||||
|
// v.BlockHash =
|
||||||
|
// v.BlockNumber =
|
||||||
|
// v.TxIndex =
|
||||||
|
from, _ := tx.From()
|
||||||
|
v.From = newHexData(from)
|
||||||
|
v.To = newHexData(tx.To())
|
||||||
|
v.Value = newHexNum(tx.Value())
|
||||||
|
v.Gas = newHexNum(tx.Gas())
|
||||||
|
v.GasPrice = newHexNum(tx.GasPrice())
|
||||||
|
v.Input = newHexData(tx.Data())
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type UncleRes struct {
|
||||||
|
BlockNumber *hexnum `json:"number"`
|
||||||
|
BlockHash *hexdata `json:"hash"`
|
||||||
|
ParentHash *hexdata `json:"parentHash"`
|
||||||
|
Nonce *hexdata `json:"nonce"`
|
||||||
|
Sha3Uncles *hexdata `json:"sha3Uncles"`
|
||||||
|
ReceiptHash *hexdata `json:"receiptHash"`
|
||||||
|
LogsBloom *hexdata `json:"logsBloom"`
|
||||||
|
TransactionRoot *hexdata `json:"transactionsRoot"`
|
||||||
|
StateRoot *hexdata `json:"stateRoot"`
|
||||||
|
Miner *hexdata `json:"miner"`
|
||||||
|
Difficulty *hexnum `json:"difficulty"`
|
||||||
|
ExtraData *hexdata `json:"extraData"`
|
||||||
|
GasLimit *hexnum `json:"gasLimit"`
|
||||||
|
GasUsed *hexnum `json:"gasUsed"`
|
||||||
|
UnixTimestamp *hexnum `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUncleRes(h *types.Header) *UncleRes {
|
||||||
|
if h == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var v = new(UncleRes)
|
||||||
|
v.BlockNumber = newHexNum(h.Number)
|
||||||
|
v.BlockHash = newHexData(h.Hash())
|
||||||
|
v.ParentHash = newHexData(h.ParentHash)
|
||||||
|
v.Sha3Uncles = newHexData(h.UncleHash)
|
||||||
|
v.Nonce = newHexData(h.Nonce[:])
|
||||||
|
v.LogsBloom = newHexData(h.Bloom)
|
||||||
|
v.TransactionRoot = newHexData(h.TxHash)
|
||||||
|
v.StateRoot = newHexData(h.Root)
|
||||||
|
v.Miner = newHexData(h.Coinbase)
|
||||||
|
v.Difficulty = newHexNum(h.Difficulty)
|
||||||
|
v.ExtraData = newHexData(h.Extra)
|
||||||
|
v.GasLimit = newHexNum(h.GasLimit)
|
||||||
|
v.GasUsed = newHexNum(h.GasUsed)
|
||||||
|
v.UnixTimestamp = newHexNum(h.Time)
|
||||||
|
v.ReceiptHash = newHexData(h.ReceiptHash)
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// type FilterLogRes struct {
|
||||||
|
// Hash string `json:"hash"`
|
||||||
|
// Address string `json:"address"`
|
||||||
|
// Data string `json:"data"`
|
||||||
|
// BlockNumber string `json:"blockNumber"`
|
||||||
|
// TransactionHash string `json:"transactionHash"`
|
||||||
|
// BlockHash string `json:"blockHash"`
|
||||||
|
// TransactionIndex string `json:"transactionIndex"`
|
||||||
|
// LogIndex string `json:"logIndex"`
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type FilterWhisperRes struct {
|
||||||
|
// Hash string `json:"hash"`
|
||||||
|
// From string `json:"from"`
|
||||||
|
// To string `json:"to"`
|
||||||
|
// Expiry string `json:"expiry"`
|
||||||
|
// Sent string `json:"sent"`
|
||||||
|
// Ttl string `json:"ttl"`
|
||||||
|
// Topics string `json:"topics"`
|
||||||
|
// Payload string `json:"payload"`
|
||||||
|
// WorkProved string `json:"workProved"`
|
||||||
|
// }
|
||||||
|
|
||||||
|
func numString(raw interface{}) (*big.Int, error) {
|
||||||
|
var number *big.Int
|
||||||
|
// Parse as integer
|
||||||
|
num, ok := raw.(float64)
|
||||||
|
if ok {
|
||||||
|
number = big.NewInt(int64(num))
|
||||||
|
return number, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse as string/hexstring
|
||||||
|
str, ok := raw.(string)
|
||||||
|
if ok {
|
||||||
|
number = common.String2Big(str)
|
||||||
|
return number, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, shared.NewInvalidTypeError("", "not a number or string")
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockHeight(raw interface{}, number *int64) error {
|
||||||
|
// Parse as integer
|
||||||
|
num, ok := raw.(float64)
|
||||||
|
if ok {
|
||||||
|
*number = int64(num)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse as string/hexstring
|
||||||
|
str, ok := raw.(string)
|
||||||
|
if !ok {
|
||||||
|
return shared.NewInvalidTypeError("", "not a number or string")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch str {
|
||||||
|
case "earliest":
|
||||||
|
*number = 0
|
||||||
|
case "latest":
|
||||||
|
*number = -1
|
||||||
|
case "pending":
|
||||||
|
*number = -2
|
||||||
|
default:
|
||||||
|
if common.HasHexPrefix(str) {
|
||||||
|
*number = common.String2Big(str).Int64()
|
||||||
|
} else {
|
||||||
|
return shared.NewInvalidTypeError("blockNumber", "is not a valid string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockHeightFromJson(msg json.RawMessage, number *int64) error {
|
||||||
|
var raw interface{}
|
||||||
|
if err := json.Unmarshal(msg, &raw); err != nil {
|
||||||
|
return shared.NewDecodeParamError(err.Error())
|
||||||
|
}
|
||||||
|
return blockHeight(raw, number)
|
||||||
|
}
|
||||||
80
rpc/api/web3.go
Normal file
80
rpc/api/web3.go
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Web3Version = "1.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// mapping between methods and handlers
|
||||||
|
Web3Mapping = map[string]web3handler{
|
||||||
|
"web3_sha3": (*web3).Sha3,
|
||||||
|
"web3_clientVersion": (*web3).ClientVersion,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// web3 callback handler
|
||||||
|
type web3handler func(*web3, *shared.Request) (interface{}, error)
|
||||||
|
|
||||||
|
// web3 api provider
|
||||||
|
type web3 struct {
|
||||||
|
xeth *xeth.XEth
|
||||||
|
methods map[string]web3handler
|
||||||
|
codec codec.ApiCoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new web3 api instance
|
||||||
|
func NewWeb3(xeth *xeth.XEth, coder codec.Codec) *web3 {
|
||||||
|
return &web3{
|
||||||
|
xeth: xeth,
|
||||||
|
methods: Web3Mapping,
|
||||||
|
codec: coder.New(nil),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collection with supported methods
|
||||||
|
func (self *web3) Methods() []string {
|
||||||
|
methods := make([]string, len(self.methods))
|
||||||
|
i := 0
|
||||||
|
for k := range self.methods {
|
||||||
|
methods[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return methods
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute given request
|
||||||
|
func (self *web3) Execute(req *shared.Request) (interface{}, error) {
|
||||||
|
if callback, ok := self.methods[req.Method]; ok {
|
||||||
|
return callback(self, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &NotImplementedError{req.Method}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version of the API this instance provides
|
||||||
|
func (self *web3) Version() string {
|
||||||
|
return Web3Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the sha3 over req.Params.Data
|
||||||
|
func (self *web3) Sha3(req *shared.Request) (interface{}, error) {
|
||||||
|
args := new(shared.Sha3Args)
|
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return common.ToHex(crypto.Sha3(common.FromHex(args.Data))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the xeth client vrsion
|
||||||
|
func (self *web3) ClientVersion(req *shared.Request) (interface{}, error) {
|
||||||
|
return self.xeth.ClientVersion(), nil
|
||||||
|
}
|
||||||
47
rpc/codec/codec.go
Normal file
47
rpc/codec/codec.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package codec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Codec int
|
||||||
|
|
||||||
|
// (de)serialization support for rpc interface
|
||||||
|
type ApiCoder interface {
|
||||||
|
// Parse message to request from underlying stream
|
||||||
|
ReadRequest() (*shared.Request, error)
|
||||||
|
// Parse response message from underlying stream
|
||||||
|
ReadResponse() (interface{}, error)
|
||||||
|
// Encode response to encoded form in underlying stream
|
||||||
|
WriteResponse(interface{}) error
|
||||||
|
// Decode single message from data
|
||||||
|
Decode([]byte, interface{}) error
|
||||||
|
// Encode msg to encoded form
|
||||||
|
Encode(msg interface{}) ([]byte, error)
|
||||||
|
// close the underlying stream
|
||||||
|
Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// supported codecs
|
||||||
|
const (
|
||||||
|
JSON Codec = iota
|
||||||
|
nCodecs
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// collection with supported coders
|
||||||
|
coders = make([]func(net.Conn) ApiCoder, nCodecs)
|
||||||
|
)
|
||||||
|
|
||||||
|
// create a new coder instance
|
||||||
|
func (c Codec) New(conn net.Conn) ApiCoder {
|
||||||
|
switch c {
|
||||||
|
case JSON:
|
||||||
|
return NewJsonCoder(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("codec: request for codec #" + strconv.Itoa(int(c)) + " is unavailable")
|
||||||
|
}
|
||||||
68
rpc/codec/json.go
Normal file
68
rpc/codec/json.go
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
package codec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Json serialization support
|
||||||
|
type JsonCodec struct {
|
||||||
|
c net.Conn
|
||||||
|
d *json.Decoder
|
||||||
|
e *json.Encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new JSON coder instance
|
||||||
|
func NewJsonCoder(conn net.Conn) ApiCoder {
|
||||||
|
return &JsonCodec{
|
||||||
|
c: conn,
|
||||||
|
d: json.NewDecoder(conn),
|
||||||
|
e: json.NewEncoder(conn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize obj to JSON and write it to conn
|
||||||
|
func (self *JsonCodec) ReadRequest() (*shared.Request, error) {
|
||||||
|
req := shared.Request{}
|
||||||
|
err := self.d.Decode(&req)
|
||||||
|
if err == nil {
|
||||||
|
return &req, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *JsonCodec) ReadResponse() (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
var success shared.SuccessResponse
|
||||||
|
if err = self.d.Decode(&success); err == nil {
|
||||||
|
return success, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var failure shared.ErrorResponse
|
||||||
|
if err = self.d.Decode(&failure); err == nil {
|
||||||
|
return failure, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode response to encoded form in underlying stream
|
||||||
|
func (self *JsonCodec) Decode(data []byte, msg interface{}) error {
|
||||||
|
return json.Unmarshal(data, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *JsonCodec) Encode(msg interface{}) ([]byte, error) {
|
||||||
|
return json.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse JSON data from conn to obj
|
||||||
|
func (self *JsonCodec) WriteResponse(res interface{}) error {
|
||||||
|
return self.e.Encode(&res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close decoder and encoder
|
||||||
|
func (self *JsonCodec) Close() {
|
||||||
|
self.c.Close()
|
||||||
|
}
|
||||||
7
rpc/comms/comms.go
Normal file
7
rpc/comms/comms.go
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
package comms
|
||||||
|
|
||||||
|
type EthereumClient interface {
|
||||||
|
Close()
|
||||||
|
Send(interface{}) error
|
||||||
|
Recv() (interface{}, error)
|
||||||
|
}
|
||||||
37
rpc/comms/ipc.go
Normal file
37
rpc/comms/ipc.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package comms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/api"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IpcConfig struct {
|
||||||
|
Endpoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ipcClient struct {
|
||||||
|
c codec.ApiCoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ipcClient) Close() {
|
||||||
|
self.c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ipcClient) Send(req interface{}) error {
|
||||||
|
return self.c.WriteResponse(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ipcClient) Recv() (interface{}, error) {
|
||||||
|
return self.c.ReadResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new IPC client, UNIX domain socket on posix, named pipe on Windows
|
||||||
|
func NewIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
|
||||||
|
return newIpcClient(cfg, codec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start IPC server
|
||||||
|
func StartIpc(cfg IpcConfig, codec codec.Codec, apis ...api.Ethereum) error {
|
||||||
|
offered := api.Merge(apis...)
|
||||||
|
return startIpc(cfg, codec, offered)
|
||||||
|
}
|
||||||
76
rpc/comms/ipc_unix.go
Normal file
76
rpc/comms/ipc_unix.go
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
|
||||||
|
|
||||||
|
package comms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/api"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
|
||||||
|
c, err := net.DialUnix("unix", nil, &net.UnixAddr{cfg.Endpoint, "unix"})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ipcClient{codec.New(c)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func startIpc(cfg IpcConfig, codec codec.Codec, api api.Ethereum) error {
|
||||||
|
os.Remove(cfg.Endpoint) // in case it still exists from a previous run
|
||||||
|
|
||||||
|
l, err := net.ListenUnix("unix", &net.UnixAddr{Name: cfg.Endpoint, Net: "unix"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
os.Chmod(cfg.Endpoint, 0600)
|
||||||
|
glog.V(logger.Info).Infof("IPC service started (%s)\n", cfg.Endpoint)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := l.AcceptUnix()
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Error accepting ipc connection - %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(conn net.Conn) {
|
||||||
|
codec := codec.New(conn)
|
||||||
|
|
||||||
|
for {
|
||||||
|
req, err := codec.ReadRequest()
|
||||||
|
if err == io.EOF {
|
||||||
|
codec.Close()
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("IPC recv err - %v\n", err)
|
||||||
|
codec.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var rpcResponse interface{}
|
||||||
|
res, err := api.Execute(req)
|
||||||
|
|
||||||
|
rpcResponse = shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err)
|
||||||
|
err = codec.WriteResponse(rpcResponse)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("IPC send err - %v\n", err)
|
||||||
|
codec.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(cfg.Endpoint)
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
43
rpc/jeth.go
43
rpc/jeth.go
|
|
@ -3,8 +3,12 @@ package rpc
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/jsre"
|
"github.com/ethereum/go-ethereum/jsre"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/comms"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,11 +33,21 @@ func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
|
func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
|
||||||
|
|
||||||
reqif, err := call.Argument(0).Export()
|
reqif, err := call.Argument(0).Export()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return self.err(call, -32700, err.Error(), nil)
|
return self.err(call, -32700, err.Error(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
client, err := comms.NewIpcClient(comms.IpcConfig{"/home/bas/.ethereum/geth.sock"}, codec.JSON)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error response:", err)
|
||||||
|
return self.err(call, -32603, err.Error(), -1)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
jsonreq, err := json.Marshal(reqif)
|
jsonreq, err := json.Marshal(reqif)
|
||||||
var reqs []RpcRequest
|
var reqs []RpcRequest
|
||||||
batch := true
|
batch := true
|
||||||
|
|
@ -48,19 +62,34 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
|
||||||
call.Otto.Run("var ret_response = new Array(response_len);")
|
call.Otto.Run("var ret_response = new Array(response_len);")
|
||||||
|
|
||||||
for i, req := range reqs {
|
for i, req := range reqs {
|
||||||
var respif interface{}
|
err := client.Send(&req)
|
||||||
err = self.ethApi.GetRequestReply(&req, &respif)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error response:", err)
|
fmt.Println("Error send request:", err)
|
||||||
return self.err(call, -32603, err.Error(), req.Id)
|
return self.err(call, -32603, err.Error(), req.Id)
|
||||||
}
|
}
|
||||||
call.Otto.Set("ret_jsonrpc", jsonrpcver)
|
|
||||||
call.Otto.Set("ret_id", req.Id)
|
|
||||||
|
|
||||||
res, _ := json.Marshal(respif)
|
respif, err := client.Recv()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error recv response:", err)
|
||||||
|
return self.err(call, -32603, err.Error(), req.Id)
|
||||||
|
}
|
||||||
|
|
||||||
call.Otto.Set("ret_result", string(res))
|
if res, ok := respif.(shared.SuccessResponse); ok {
|
||||||
|
call.Otto.Set("ret_id", res.Id)
|
||||||
|
call.Otto.Set("ret_jsonrpc", res.Jsonrpc)
|
||||||
|
resObj, _ := json.Marshal(res.Result)
|
||||||
|
call.Otto.Set("ret_result", string(resObj))
|
||||||
call.Otto.Set("response_idx", i)
|
call.Otto.Set("response_idx", i)
|
||||||
|
} else if res, ok := respif.(shared.ErrorResponse); ok {
|
||||||
|
call.Otto.Set("ret_id", res.Id)
|
||||||
|
call.Otto.Set("ret_jsonrpc", res.Jsonrpc)
|
||||||
|
errorObj, _ := json.Marshal(res.Error)
|
||||||
|
call.Otto.Set("ret_result", string(errorObj))
|
||||||
|
call.Otto.Set("response_idx", i)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("different type\n", reflect.TypeOf(respif))
|
||||||
|
}
|
||||||
|
|
||||||
response, err = call.Otto.Run(`
|
response, err = call.Otto.Run(`
|
||||||
ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) };
|
ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) };
|
||||||
`)
|
`)
|
||||||
|
|
|
||||||
59
rpc/shared/api.go
Normal file
59
rpc/shared/api.go
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package shared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
Id interface{} `json:"id"`
|
||||||
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Params json.RawMessage `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Id interface{} `json:"id"`
|
||||||
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SuccessResponse struct {
|
||||||
|
Id interface{} `json:"id"`
|
||||||
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
|
Result interface{} `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Id interface{} `json:"id"`
|
||||||
|
Jsonrpc string `json:"jsonrpc"`
|
||||||
|
Error *ErrorObject `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorObject struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
// Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRpcResponse(id interface{}, jsonrpcver string, reply interface{}, err error) *interface{} {
|
||||||
|
var response interface{}
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
response = &SuccessResponse{Jsonrpc: jsonrpcver, Id: id, Result: reply}
|
||||||
|
case *NotImplementedError:
|
||||||
|
jsonerr := &ErrorObject{-32601, err.Error()}
|
||||||
|
response = &ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
|
||||||
|
case *DecodeParamError, *InsufficientParamsError, *ValidationError, *InvalidTypeError:
|
||||||
|
jsonerr := &ErrorObject{-32602, err.Error()}
|
||||||
|
response = &ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
|
||||||
|
default:
|
||||||
|
jsonerr := &ErrorObject{-32603, err.Error()}
|
||||||
|
response = &ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr}
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(logger.Detail).Infof("Generated response: %T %s", response, response)
|
||||||
|
return &response
|
||||||
|
}
|
||||||
5
rpc/shared/apiargs.go
Normal file
5
rpc/shared/apiargs.go
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package shared
|
||||||
|
|
||||||
|
type Sha3Args struct {
|
||||||
|
Data string
|
||||||
|
}
|
||||||
96
rpc/shared/errors.go
Normal file
96
rpc/shared/errors.go
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
package shared
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type InvalidTypeError struct {
|
||||||
|
method string
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidTypeError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid type on field %s: %s", e.method, e.msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInvalidTypeError(method, msg string) *InvalidTypeError {
|
||||||
|
return &InvalidTypeError{
|
||||||
|
method: method,
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type InsufficientParamsError struct {
|
||||||
|
have int
|
||||||
|
want int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InsufficientParamsError) Error() string {
|
||||||
|
return fmt.Sprintf("insufficient params, want %d have %d", e.want, e.have)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInsufficientParamsError(have int, want int) *InsufficientParamsError {
|
||||||
|
return &InsufficientParamsError{
|
||||||
|
have: have,
|
||||||
|
want: want,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotImplementedError struct {
|
||||||
|
Method string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NotImplementedError) Error() string {
|
||||||
|
return fmt.Sprintf("%s method not implemented", e.Method)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNotImplementedError(method string) *NotImplementedError {
|
||||||
|
return &NotImplementedError{
|
||||||
|
Method: method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DecodeParamError struct {
|
||||||
|
err string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DecodeParamError) Error() string {
|
||||||
|
return fmt.Sprintf("could not decode, %s", e.err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDecodeParamError(errstr string) error {
|
||||||
|
return &DecodeParamError{
|
||||||
|
err: errstr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidationError struct {
|
||||||
|
ParamName string
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ValidationError) Error() string {
|
||||||
|
return fmt.Sprintf("%s not valid, %s", e.ParamName, e.msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewValidationError(param string, msg string) error {
|
||||||
|
return &ValidationError{
|
||||||
|
ParamName: param,
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotAvailableError struct {
|
||||||
|
Method string
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NotAvailableError) Error() string {
|
||||||
|
return fmt.Sprintf("%s method not available: %s", e.Method, e.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNotAvailableError(method string, reason string) *NotAvailableError {
|
||||||
|
return &NotAvailableError{
|
||||||
|
Method: method,
|
||||||
|
Reason: reason,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue