diff options
Diffstat (limited to 'rpc')
-rw-r--r-- | rpc/api/admin.go | 465 | ||||
-rw-r--r-- | rpc/api/admin_args.go | 468 | ||||
-rw-r--r-- | rpc/api/admin_js.go | 143 | ||||
-rw-r--r-- | rpc/api/api.go | 26 | ||||
-rw-r--r-- | rpc/api/api_test.go | 170 | ||||
-rw-r--r-- | rpc/api/args.go | 74 | ||||
-rw-r--r-- | rpc/api/args_test.go | 2649 | ||||
-rw-r--r-- | rpc/api/db.go | 144 | ||||
-rw-r--r-- | rpc/api/db_args.go | 126 | ||||
-rw-r--r-- | rpc/api/db_js.go | 29 | ||||
-rw-r--r-- | rpc/api/debug.go | 303 | ||||
-rw-r--r-- | rpc/api/debug_args.go | 87 | ||||
-rw-r--r-- | rpc/api/debug_js.go | 83 | ||||
-rw-r--r-- | rpc/api/eth.go | 721 | ||||
-rw-r--r-- | rpc/api/eth_args.go | 1104 | ||||
-rw-r--r-- | rpc/api/eth_js.go | 66 | ||||
-rw-r--r-- | rpc/api/mergedapi.go | 88 | ||||
-rw-r--r-- | rpc/api/miner.go | 177 | ||||
-rw-r--r-- | rpc/api/miner_args.go | 142 | ||||
-rw-r--r-- | rpc/api/miner_js.go | 83 | ||||
-rw-r--r-- | rpc/api/net.go | 99 | ||||
-rw-r--r-- | rpc/api/net_js.go | 39 | ||||
-rw-r--r-- | rpc/api/parsing.go | 522 | ||||
-rw-r--r-- | rpc/api/personal.go | 139 | ||||
-rw-r--r-- | rpc/api/personal_args.go | 85 | ||||
-rw-r--r-- | rpc/api/personal_js.go | 51 | ||||
-rw-r--r-- | rpc/api/shh.go | 196 | ||||
-rw-r--r-- | rpc/api/shh_args.go | 174 | ||||
-rw-r--r-- | rpc/api/shh_js.go | 34 | ||||
-rw-r--r-- | rpc/api/txpool.go | 92 | ||||
-rw-r--r-- | rpc/api/txpool_js.go | 33 | ||||
-rw-r--r-- | rpc/api/utils.go | 226 | ||||
-rw-r--r-- | rpc/api/web3.go | 99 | ||||
-rw-r--r-- | rpc/codec/codec.go | 65 | ||||
-rw-r--r-- | rpc/codec/json.go | 149 | ||||
-rw-r--r-- | rpc/codec/json_test.go | 157 | ||||
-rw-r--r-- | rpc/comms/comms.go | 150 | ||||
-rw-r--r-- | rpc/comms/http.go | 345 | ||||
-rw-r--r-- | rpc/comms/inproc.go | 82 | ||||
-rw-r--r-- | rpc/comms/ipc.go | 158 | ||||
-rw-r--r-- | rpc/comms/ipc_unix.go | 82 | ||||
-rw-r--r-- | rpc/doc.go (renamed from rpc/v2/doc.go) | 128 | ||||
-rw-r--r-- | rpc/errors.go (renamed from rpc/v2/errors.go) | 14 | ||||
-rw-r--r-- | rpc/http.go | 368 | ||||
-rw-r--r-- | rpc/ipc.go | 84 | ||||
-rw-r--r-- | rpc/ipc_unix.go (renamed from rpc/api/web3_args.go) | 42 | ||||
-rw-r--r-- | rpc/ipc_windows.go (renamed from rpc/comms/ipc_windows.go) | 56 | ||||
-rw-r--r-- | rpc/javascript.go | 414 | ||||
-rw-r--r-- | rpc/jeth.go | 324 | ||||
-rw-r--r-- | rpc/json.go (renamed from rpc/v2/json.go) | 28 | ||||
-rw-r--r-- | rpc/json_test.go (renamed from rpc/v2/json_test.go) | 2 | ||||
-rw-r--r-- | rpc/server.go (renamed from rpc/v2/server.go) | 61 | ||||
-rw-r--r-- | rpc/server_test.go (renamed from rpc/v2/server_test.go) | 32 | ||||
-rw-r--r-- | rpc/shared/errors.go | 126 | ||||
-rw-r--r-- | rpc/shared/types.go | 108 | ||||
-rw-r--r-- | rpc/shared/utils.go | 43 | ||||
-rw-r--r-- | rpc/types.go (renamed from rpc/v2/types.go) | 18 | ||||
-rw-r--r-- | rpc/types_test.go (renamed from rpc/v2/types_test.go) | 18 | ||||
-rw-r--r-- | rpc/useragent/agent.go | 24 | ||||
-rw-r--r-- | rpc/useragent/remote_frontend.go | 166 | ||||
-rw-r--r-- | rpc/utils.go (renamed from rpc/v2/utils.go) | 34 | ||||
-rw-r--r-- | rpc/websocket.go | 235 | ||||
-rw-r--r-- | rpc/xeth.go | 77 |
63 files changed, 1432 insertions, 11095 deletions
diff --git a/rpc/api/admin.go b/rpc/api/admin.go deleted file mode 100644 index daf2f31b4..000000000 --- a/rpc/api/admin.go +++ /dev/null @@ -1,465 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "fmt" - "io" - "math/big" - "os" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/compiler" - "github.com/ethereum/go-ethereum/common/natspec" - "github.com/ethereum/go-ethereum/common/registrar" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/comms" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/rpc/useragent" - "github.com/ethereum/go-ethereum/xeth" -) - -const ( - AdminApiversion = "1.0" - importBatchSize = 2500 -) - -var ( - // mapping between methods and handlers - AdminMapping = map[string]adminhandler{ - "admin_addPeer": (*adminApi).AddPeer, - "admin_peers": (*adminApi).Peers, - "admin_nodeInfo": (*adminApi).NodeInfo, - "admin_exportChain": (*adminApi).ExportChain, - "admin_importChain": (*adminApi).ImportChain, - "admin_setSolc": (*adminApi).SetSolc, - "admin_datadir": (*adminApi).DataDir, - "admin_startRPC": (*adminApi).StartRPC, - "admin_stopRPC": (*adminApi).StopRPC, - "admin_setGlobalRegistrar": (*adminApi).SetGlobalRegistrar, - "admin_setHashReg": (*adminApi).SetHashReg, - "admin_setUrlHint": (*adminApi).SetUrlHint, - "admin_saveInfo": (*adminApi).SaveInfo, - "admin_register": (*adminApi).Register, - "admin_registerUrl": (*adminApi).RegisterUrl, - "admin_startNatSpec": (*adminApi).StartNatSpec, - "admin_stopNatSpec": (*adminApi).StopNatSpec, - "admin_getContractInfo": (*adminApi).GetContractInfo, - "admin_httpGet": (*adminApi).HttpGet, - "admin_sleepBlocks": (*adminApi).SleepBlocks, - "admin_sleep": (*adminApi).Sleep, - "admin_enableUserAgent": (*adminApi).EnableUserAgent, - } -) - -// admin callback handler -type adminhandler func(*adminApi, *shared.Request) (interface{}, error) - -// admin api provider -type adminApi struct { - xeth *xeth.XEth - stack *node.Node - ethereum *eth.Ethereum - codec codec.Codec - coder codec.ApiCoder -} - -// create a new admin api instance -func NewAdminApi(xeth *xeth.XEth, stack *node.Node, codec codec.Codec) *adminApi { - api := &adminApi{ - xeth: xeth, - stack: stack, - codec: codec, - coder: codec.New(nil), - } - if stack != nil { - stack.Service(&api.ethereum) - } - return api -} - -// collection with supported methods -func (self *adminApi) Methods() []string { - methods := make([]string, len(AdminMapping)) - i := 0 - for k := range AdminMapping { - methods[i] = k - i++ - } - return methods -} - -// Execute given request -func (self *adminApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := AdminMapping[req.Method]; ok { - return callback(self, req) - } - - return nil, &shared.NotImplementedError{req.Method} -} - -func (self *adminApi) Name() string { - return shared.AdminApiName -} - -func (self *adminApi) ApiVersion() string { - return AdminApiversion -} - -func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { - args := new(AddPeerArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - node, err := discover.ParseNode(args.Url) - if err != nil { - return nil, fmt.Errorf("invalid node URL: %v", err) - } - self.stack.Server().AddPeer(node) - return true, nil -} - -func (self *adminApi) Peers(req *shared.Request) (interface{}, error) { - return self.stack.Server().PeersInfo(), nil -} - -func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) { - return self.stack.Server().NodeInfo(), nil -} - -func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) { - return self.stack.DataDir(), nil -} - -func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { - for _, b := range bs { - if !chain.HasBlock(b.Hash()) { - return false - } - } - return true -} - -func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) { - args := new(ImportExportChainArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - fh, err := os.Open(args.Filename) - if err != nil { - return false, err - } - defer fh.Close() - stream := rlp.NewStream(fh, 0) - - // Run actual the import. - blocks := make(types.Blocks, importBatchSize) - n := 0 - for batch := 0; ; batch++ { - - i := 0 - for ; i < importBatchSize; i++ { - var b types.Block - if err := stream.Decode(&b); err == io.EOF { - break - } else if err != nil { - return false, fmt.Errorf("at block %d: %v", n, err) - } - blocks[i] = &b - n++ - } - if i == 0 { - break - } - // Import the batch. - if hasAllBlocks(self.ethereum.BlockChain(), blocks[:i]) { - continue - } - if _, err := self.ethereum.BlockChain().InsertChain(blocks[:i]); err != nil { - return false, fmt.Errorf("invalid block %d: %v", n, err) - } - } - return true, nil -} - -func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) { - args := new(ImportExportChainArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) - if err != nil { - return false, err - } - defer fh.Close() - if err := self.ethereum.BlockChain().Export(fh); err != nil { - return false, err - } - - return true, nil -} - -func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) { - args := new(SetSolcArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - solc, err := self.xeth.SetSolc(args.Path) - if err != nil { - return nil, err - } - return solc.Info(), nil -} - -func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) { - args := new(StartRPCArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - cfg := comms.HttpConfig{ - ListenAddress: args.ListenAddress, - ListenPort: args.ListenPort, - CorsDomain: args.CorsDomain, - } - - apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.stack) - if err != nil { - return false, err - } - - err = comms.StartHttp(cfg, self.codec, Merge(apis...)) - if err == nil { - return true, nil - } - return false, err -} - -func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) { - comms.StopHttp() - return true, nil -} - -func (self *adminApi) SleepBlocks(req *shared.Request) (interface{}, error) { - args := new(SleepBlocksArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - var timer <-chan time.Time - var height *big.Int - var err error - if args.Timeout > 0 { - timer = time.NewTimer(time.Duration(args.Timeout) * time.Second).C - } - - height = new(big.Int).Add(self.xeth.CurrentBlock().Number(), big.NewInt(args.N)) - height, err = sleepBlocks(self.xeth.UpdateState(), height, timer) - if err != nil { - return nil, err - } - return height.Uint64(), nil -} - -func sleepBlocks(wait chan *big.Int, height *big.Int, timer <-chan time.Time) (newHeight *big.Int, err error) { - wait <- height - select { - case <-timer: - // if times out make sure the xeth loop does not block - go func() { - select { - case wait <- nil: - case <-wait: - } - }() - return nil, fmt.Errorf("timeout") - case newHeight = <-wait: - } - return -} - -func (self *adminApi) Sleep(req *shared.Request) (interface{}, error) { - args := new(SleepArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - time.Sleep(time.Duration(args.S) * time.Second) - return nil, nil -} - -func (self *adminApi) SetGlobalRegistrar(req *shared.Request) (interface{}, error) { - args := new(SetGlobalRegistrarArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - sender := common.HexToAddress(args.ContractAddress) - - reg := registrar.New(self.xeth) - txhash, err := reg.SetGlobalRegistrar(args.NameReg, sender) - if err != nil { - return false, err - } - - return txhash, nil -} - -func (self *adminApi) SetHashReg(req *shared.Request) (interface{}, error) { - args := new(SetHashRegArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - reg := registrar.New(self.xeth) - sender := common.HexToAddress(args.Sender) - txhash, err := reg.SetHashReg(args.HashReg, sender) - if err != nil { - return false, err - } - - return txhash, nil -} - -func (self *adminApi) SetUrlHint(req *shared.Request) (interface{}, error) { - args := new(SetUrlHintArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - urlHint := args.UrlHint - sender := common.HexToAddress(args.Sender) - - reg := registrar.New(self.xeth) - txhash, err := reg.SetUrlHint(urlHint, sender) - if err != nil { - return nil, err - } - - return txhash, nil -} - -func (self *adminApi) SaveInfo(req *shared.Request) (interface{}, error) { - args := new(SaveInfoArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - contenthash, err := compiler.SaveInfo(&args.ContractInfo, args.Filename) - if err != nil { - return nil, err - } - - return contenthash.Hex(), nil -} - -func (self *adminApi) Register(req *shared.Request) (interface{}, error) { - args := new(RegisterArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - sender := common.HexToAddress(args.Sender) - // sender and contract address are passed as hex strings - codeb := self.xeth.CodeAtBytes(args.Address) - codeHash := common.BytesToHash(crypto.Sha3(codeb)) - contentHash := common.HexToHash(args.ContentHashHex) - registry := registrar.New(self.xeth) - - _, err := registry.SetHashToHash(sender, codeHash, contentHash) - if err != nil { - return false, err - } - - return true, nil -} - -func (self *adminApi) RegisterUrl(req *shared.Request) (interface{}, error) { - args := new(RegisterUrlArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - sender := common.HexToAddress(args.Sender) - registry := registrar.New(self.xeth) - _, err := registry.SetUrlToHash(sender, common.HexToHash(args.ContentHash), args.Url) - if err != nil { - return false, err - } - - return true, nil -} - -func (self *adminApi) StartNatSpec(req *shared.Request) (interface{}, error) { - self.ethereum.NatSpec = true - return true, nil -} - -func (self *adminApi) StopNatSpec(req *shared.Request) (interface{}, error) { - self.ethereum.NatSpec = false - return true, nil -} - -func (self *adminApi) GetContractInfo(req *shared.Request) (interface{}, error) { - args := new(GetContractInfoArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - infoDoc, err := natspec.FetchDocsForContract(args.Contract, self.xeth, self.ethereum.HTTPClient()) - if err != nil { - return nil, err - } - - var info interface{} - err = self.coder.Decode(infoDoc, &info) - if err != nil { - return nil, err - } - - return info, nil -} - -func (self *adminApi) HttpGet(req *shared.Request) (interface{}, error) { - args := new(HttpGetArgs) - if err := self.coder.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - resp, err := self.ethereum.HTTPClient().Get(args.Uri, args.Path) - if err != nil { - return nil, err - } - - return string(resp), nil -} - -func (self *adminApi) EnableUserAgent(req *shared.Request) (interface{}, error) { - if fe, ok := self.xeth.Frontend().(*useragent.RemoteFrontend); ok { - fe.Enable() - } - return true, nil -} diff --git a/rpc/api/admin_args.go b/rpc/api/admin_args.go deleted file mode 100644 index e09597ad4..000000000 --- a/rpc/api/admin_args.go +++ /dev/null @@ -1,468 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/common/compiler" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type AddPeerArgs struct { - Url string -} - -func (args *AddPeerArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) != 1 { - return shared.NewDecodeParamError("Expected enode as argument") - } - - urlstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("url", "not a string") - } - args.Url = urlstr - - return nil -} - -type ImportExportChainArgs struct { - Filename string -} - -func (args *ImportExportChainArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) != 1 { - return shared.NewDecodeParamError("Expected filename as argument") - } - - filename, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("filename", "not a string") - } - args.Filename = filename - - return nil -} - -type SetSolcArgs struct { - Path string -} - -func (args *SetSolcArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) != 1 { - return shared.NewDecodeParamError("Expected path as argument") - } - - if pathstr, ok := obj[0].(string); ok { - args.Path = pathstr - return nil - } - - return shared.NewInvalidTypeError("path", "not a string") -} - -type StartRPCArgs struct { - ListenAddress string - ListenPort uint - CorsDomain string - Apis string -} - -func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - args.ListenAddress = "127.0.0.1" - args.ListenPort = 8545 - args.Apis = "net,eth,web3" - - if len(obj) >= 1 && obj[0] != nil { - if addr, ok := obj[0].(string); ok { - args.ListenAddress = addr - } else { - return shared.NewInvalidTypeError("listenAddress", "not a string") - } - } - - if len(obj) >= 2 && obj[1] != nil { - if port, ok := obj[1].(float64); ok && port >= 0 && port <= 64*1024 { - args.ListenPort = uint(port) - } else { - return shared.NewInvalidTypeError("listenPort", "not a valid port number") - } - } - - if len(obj) >= 3 && obj[2] != nil { - if corsDomain, ok := obj[2].(string); ok { - args.CorsDomain = corsDomain - } else { - return shared.NewInvalidTypeError("corsDomain", "not a string") - } - } - - if len(obj) >= 4 && obj[3] != nil { - if apis, ok := obj[3].(string); ok { - args.Apis = apis - } else { - return shared.NewInvalidTypeError("apis", "not a string") - } - } - - return nil -} - -type SleepArgs struct { - S int -} - -func (args *SleepArgs) UnmarshalJSON(b []byte) (err error) { - - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - if len(obj) >= 1 { - if obj[0] != nil { - if n, err := numString(obj[0]); err == nil { - args.S = int(n.Int64()) - } else { - return shared.NewInvalidTypeError("N", "not an integer: "+err.Error()) - } - } else { - return shared.NewInsufficientParamsError(0, 1) - } - } - return nil -} - -type SleepBlocksArgs struct { - N int64 - Timeout int64 -} - -func (args *SleepBlocksArgs) UnmarshalJSON(b []byte) (err error) { - - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - args.N = 1 - args.Timeout = 0 - if len(obj) >= 1 && obj[0] != nil { - if n, err := numString(obj[0]); err == nil { - args.N = n.Int64() - } else { - return shared.NewInvalidTypeError("N", "not an integer: "+err.Error()) - } - } - - if len(obj) >= 2 && obj[1] != nil { - if n, err := numString(obj[1]); err == nil { - args.Timeout = n.Int64() - } else { - return shared.NewInvalidTypeError("Timeout", "not an integer: "+err.Error()) - } - } - - return nil -} - -type SetGlobalRegistrarArgs struct { - NameReg string - ContractAddress string -} - -func (args *SetGlobalRegistrarArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) == 0 { - return shared.NewDecodeParamError("Expected namereg address") - } - - if len(obj) >= 1 { - if namereg, ok := obj[0].(string); ok { - args.NameReg = namereg - } else { - return shared.NewInvalidTypeError("NameReg", "not a string") - } - } - - if len(obj) >= 2 && obj[1] != nil { - if addr, ok := obj[1].(string); ok { - args.ContractAddress = addr - } else { - return shared.NewInvalidTypeError("ContractAddress", "not a string") - } - } - - return nil -} - -type SetHashRegArgs struct { - HashReg string - Sender string -} - -func (args *SetHashRegArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) >= 1 && obj[0] != nil { - if hashreg, ok := obj[0].(string); ok { - args.HashReg = hashreg - } else { - return shared.NewInvalidTypeError("HashReg", "not a string") - } - } - - if len(obj) >= 2 && obj[1] != nil { - if sender, ok := obj[1].(string); ok { - args.Sender = sender - } else { - return shared.NewInvalidTypeError("Sender", "not a string") - } - } - - return nil -} - -type SetUrlHintArgs struct { - UrlHint string - Sender string -} - -func (args *SetUrlHintArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) >= 1 && obj[0] != nil { - if urlhint, ok := obj[0].(string); ok { - args.UrlHint = urlhint - } else { - return shared.NewInvalidTypeError("UrlHint", "not a string") - } - } - - if len(obj) >= 2 && obj[1] != nil { - if sender, ok := obj[1].(string); ok { - args.Sender = sender - } else { - return shared.NewInvalidTypeError("Sender", "not a string") - } - } - - return nil -} - -type SaveInfoArgs struct { - ContractInfo compiler.ContractInfo - Filename string -} - -func (args *SaveInfoArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - if jsonraw, err := json.Marshal(obj[0]); err == nil { - if err = json.Unmarshal(jsonraw, &args.ContractInfo); err != nil { - return err - } - } else { - return err - } - - if filename, ok := obj[1].(string); ok { - args.Filename = filename - } else { - return shared.NewInvalidTypeError("Filename", "not a string") - } - - return nil -} - -type RegisterArgs struct { - Sender string - Address string - ContentHashHex string -} - -func (args *RegisterArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 3 { - return shared.NewInsufficientParamsError(len(obj), 3) - } - - if len(obj) >= 1 { - if sender, ok := obj[0].(string); ok { - args.Sender = sender - } else { - return shared.NewInvalidTypeError("Sender", "not a string") - } - } - - if len(obj) >= 2 { - if address, ok := obj[1].(string); ok { - args.Address = address - } else { - return shared.NewInvalidTypeError("Address", "not a string") - } - } - - if len(obj) >= 3 { - if hex, ok := obj[2].(string); ok { - args.ContentHashHex = hex - } else { - return shared.NewInvalidTypeError("ContentHashHex", "not a string") - } - } - - return nil -} - -type RegisterUrlArgs struct { - Sender string - ContentHash string - Url string -} - -func (args *RegisterUrlArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) >= 1 { - if sender, ok := obj[0].(string); ok { - args.Sender = sender - } else { - return shared.NewInvalidTypeError("Sender", "not a string") - } - } - - if len(obj) >= 2 { - if sender, ok := obj[1].(string); ok { - args.ContentHash = sender - } else { - return shared.NewInvalidTypeError("ContentHash", "not a string") - } - } - - if len(obj) >= 3 { - if sender, ok := obj[2].(string); ok { - args.Url = sender - } else { - return shared.NewInvalidTypeError("Url", "not a string") - } - } - - return nil -} - -type GetContractInfoArgs struct { - Contract string -} - -func (args *GetContractInfoArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - if len(obj) >= 1 { - if contract, ok := obj[0].(string); ok { - args.Contract = contract - } else { - return shared.NewInvalidTypeError("Contract", "not a string") - } - } - - return nil -} - -type HttpGetArgs struct { - Uri string - Path string -} - -func (args *HttpGetArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - if len(obj) >= 1 { - if uri, ok := obj[0].(string); ok { - args.Uri = uri - } else { - return shared.NewInvalidTypeError("Uri", "not a string") - } - } - - if len(obj) >= 2 && obj[1] != nil { - if path, ok := obj[1].(string); ok { - args.Path = path - } else { - return shared.NewInvalidTypeError("Path", "not a string") - } - } - - return nil -} diff --git a/rpc/api/admin_js.go b/rpc/api/admin_js.go deleted file mode 100644 index e6171cc74..000000000 --- a/rpc/api/admin_js.go +++ /dev/null @@ -1,143 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const Admin_JS = ` -web3._extend({ - property: 'admin', - methods: - [ - new web3._extend.Method({ - name: 'addPeer', - call: 'admin_addPeer', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'exportChain', - call: 'admin_exportChain', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'importChain', - call: 'admin_importChain', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'sleepBlocks', - call: 'admin_sleepBlocks', - params: 2, - inputFormatter: [null, null] - }), - new web3._extend.Method({ - name: 'setSolc', - call: 'admin_setSolc', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'startRPC', - call: 'admin_startRPC', - params: 4, - inputFormatter: [null, null, null, null] - }), - new web3._extend.Method({ - name: 'stopRPC', - call: 'admin_stopRPC', - params: 0, - inputFormatter: [] - }), - new web3._extend.Method({ - name: 'setGlobalRegistrar', - call: 'admin_setGlobalRegistrar', - params: 2, - inputFormatter: [null,null] - }), - new web3._extend.Method({ - name: 'setHashReg', - call: 'admin_setHashReg', - params: 2, - inputFormatter: [null,null] - }), - new web3._extend.Method({ - name: 'setUrlHint', - call: 'admin_setUrlHint', - params: 2, - inputFormatter: [null,null] - }), - new web3._extend.Method({ - name: 'saveInfo', - call: 'admin_saveInfo', - params: 2, - inputFormatter: [null,null] - }), - new web3._extend.Method({ - name: 'register', - call: 'admin_register', - params: 3, - inputFormatter: [null,null,null] - }), - new web3._extend.Method({ - name: 'registerUrl', - call: 'admin_registerUrl', - params: 3, - inputFormatter: [null,null,null] - }), - new web3._extend.Method({ - name: 'startNatSpec', - call: 'admin_startNatSpec', - params: 0, - inputFormatter: [] - }), - new web3._extend.Method({ - name: 'stopNatSpec', - call: 'admin_stopNatSpec', - params: 0, - inputFormatter: [] - }), - new web3._extend.Method({ - name: 'getContractInfo', - call: 'admin_getContractInfo', - params: 1, - inputFormatter: [null], - }), - new web3._extend.Method({ - name: 'httpGet', - call: 'admin_httpGet', - params: 2, - inputFormatter: [null, null] - }) - ], - properties: - [ - new web3._extend.Property({ - name: 'nodeInfo', - getter: 'admin_nodeInfo' - }), - new web3._extend.Property({ - name: 'peers', - getter: 'admin_peers' - }), - new web3._extend.Property({ - name: 'datadir', - getter: 'admin_datadir' - }) - ] -}); -` diff --git a/rpc/api/api.go b/rpc/api/api.go deleted file mode 100644 index e03250ec6..000000000 --- a/rpc/api/api.go +++ /dev/null @@ -1,26 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "github.com/ethereum/go-ethereum/rpc/shared" -) - -// Merge multiple API's to a single API instance -func Merge(apis ...shared.EthereumApi) shared.EthereumApi { - return newMergedApi(apis...) -} diff --git a/rpc/api/api_test.go b/rpc/api/api_test.go deleted file mode 100644 index eb63e8151..000000000 --- a/rpc/api/api_test.go +++ /dev/null @@ -1,170 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "testing" - - "encoding/json" - "strconv" - - "github.com/ethereum/go-ethereum/common/compiler" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" -) - -func TestParseApiString(t *testing.T) { - apis, err := ParseApiString("", codec.JSON, nil, nil) - if err == nil { - t.Errorf("Expected an err from parsing empty API string but got nil") - } - - if len(apis) != 0 { - t.Errorf("Expected 0 apis from empty API string") - } - - apis, err = ParseApiString("eth", codec.JSON, nil, nil) - if err != nil { - t.Errorf("Expected nil err from parsing empty API string but got %v", err) - } - - if len(apis) != 1 { - t.Errorf("Expected 1 apis but got %d - %v", apis, apis) - } - - apis, err = ParseApiString("eth,eth", codec.JSON, nil, nil) - if err != nil { - t.Errorf("Expected nil err from parsing empty API string but got \"%v\"", err) - } - - if len(apis) != 2 { - t.Errorf("Expected 2 apis but got %d - %v", apis, apis) - } - - apis, err = ParseApiString("eth,invalid", codec.JSON, nil, nil) - if err == nil { - t.Errorf("Expected an err but got no err") - } - -} - -const solcVersion = "0.9.23" - -func TestCompileSolidity(t *testing.T) { - - solc, err := compiler.New("") - if solc == nil { - t.Skip("no solc found: skip") - } else if solc.Version() != solcVersion { - t.Skip("WARNING: skipping test because of solc different version (%v, test written for %v, may need to update)", solc.Version(), solcVersion) - } - source := `contract test {\n` + - " /// @notice Will multiply `a` by 7." + `\n` + - ` function multiply(uint a) returns(uint d) {\n` + - ` return a * 7;\n` + - ` }\n` + - `}\n` - - jsonstr := `{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["` + source + `"],"id":64}` - - expCode := "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056" - expAbiDefinition := `[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]` - expUserDoc := `{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}}` - expDeveloperDoc := `{"methods":{}}` - expCompilerVersion := solc.Version() - expLanguage := "Solidity" - expLanguageVersion := "0" - expSource := source - - eth := ð.Ethereum{} - xeth := xeth.NewTest(nil, nil) - api := NewEthApi(xeth, eth, codec.JSON) - - var rpcRequest shared.Request - json.Unmarshal([]byte(jsonstr), &rpcRequest) - - response, err := api.CompileSolidity(&rpcRequest) - if err != nil { - t.Errorf("Execution failed, %v", err) - } - - respjson, err := json.Marshal(response) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - var contracts = make(map[string]*compiler.Contract) - err = json.Unmarshal(respjson, &contracts) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - if len(contracts) != 1 { - t.Errorf("expected one contract, got %v", len(contracts)) - } - - contract := contracts["test"] - - if contract.Code != expCode { - t.Errorf("Expected \n%s got \n%s", expCode, contract.Code) - } - - if strconv.Quote(contract.Info.Source) != `"`+expSource+`"` { - t.Errorf("Expected \n'%s' got \n'%s'", expSource, strconv.Quote(contract.Info.Source)) - } - - if contract.Info.Language != expLanguage { - t.Errorf("Expected %s got %s", expLanguage, contract.Info.Language) - } - - if contract.Info.LanguageVersion != expLanguageVersion { - t.Errorf("Expected %s got %s", expLanguageVersion, contract.Info.LanguageVersion) - } - - if contract.Info.CompilerVersion != expCompilerVersion { - t.Errorf("Expected %s got %s", expCompilerVersion, contract.Info.CompilerVersion) - } - - userdoc, err := json.Marshal(contract.Info.UserDoc) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - devdoc, err := json.Marshal(contract.Info.DeveloperDoc) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - abidef, err := json.Marshal(contract.Info.AbiDefinition) - if err != nil { - t.Errorf("expected no error, got %v", err) - } - - if string(abidef) != expAbiDefinition { - t.Errorf("Expected \n'%s' got \n'%s'", expAbiDefinition, string(abidef)) - } - - if string(userdoc) != expUserDoc { - t.Errorf("Expected \n'%s' got \n'%s'", expUserDoc, string(userdoc)) - } - - if string(devdoc) != expDeveloperDoc { - t.Errorf("Expected %s got %s", expDeveloperDoc, string(devdoc)) - } -} diff --git a/rpc/api/args.go b/rpc/api/args.go deleted file mode 100644 index 20f073b67..000000000 --- a/rpc/api/args.go +++ /dev/null @@ -1,74 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type CompileArgs struct { - Source string -} - -func (args *CompileArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - argstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("arg0", "is not a string") - } - args.Source = argstr - - return nil -} - -type FilterStringArgs struct { - Word string -} - -func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - var argstr string - argstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("filter", "not a string") - } - switch argstr { - case "latest", "pending": - break - default: - return shared.NewValidationError("Word", "Must be `latest` or `pending`") - } - args.Word = argstr - return nil -} diff --git a/rpc/api/args_test.go b/rpc/api/args_test.go deleted file mode 100644 index 130315bd9..000000000 --- a/rpc/api/args_test.go +++ /dev/null @@ -1,2649 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "bytes" - "encoding/json" - "fmt" - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/rpc/shared" -) - -func TestBlockheightInvalidString(t *testing.T) { - v := "foo" - var num int64 - - str := ExpectInvalidTypeError(blockHeight(v, &num)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockheightEarliest(t *testing.T) { - v := "earliest" - e := int64(0) - var num int64 - - err := blockHeight(v, &num) - if err != nil { - t.Error(err) - } - - if num != e { - t.Errorf("Expected %s but got %s", e, num) - } -} - -func TestBlockheightLatest(t *testing.T) { - v := "latest" - e := int64(-1) - var num int64 - - err := blockHeight(v, &num) - if err != nil { - t.Error(err) - } - - if num != e { - t.Errorf("Expected %s but got %s", e, num) - } -} - -func TestBlockheightPending(t *testing.T) { - v := "pending" - e := int64(-2) - var num int64 - - err := blockHeight(v, &num) - if err != nil { - t.Error(err) - } - - if num != e { - t.Errorf("Expected %s but got %s", e, num) - } -} - -func ExpectValidationError(err error) string { - var str string - switch err.(type) { - case nil: - str = "Expected error but didn't get one" - case *shared.ValidationError: - break - default: - str = fmt.Sprintf("Expected *rpc.ValidationError but got %T with message `%s`", err, err.Error()) - } - return str -} - -func ExpectInvalidTypeError(err error) string { - var str string - switch err.(type) { - case nil: - str = "Expected error but didn't get one" - case *shared.InvalidTypeError: - break - default: - str = fmt.Sprintf("Expected *rpc.InvalidTypeError but got %T with message `%s`", err, err.Error()) - } - return str -} - -func ExpectInsufficientParamsError(err error) string { - var str string - switch err.(type) { - case nil: - str = "Expected error but didn't get one" - case *shared.InsufficientParamsError: - break - default: - str = fmt.Sprintf("Expected *rpc.InsufficientParamsError but got %T with message %s", err, err.Error()) - } - return str -} - -func ExpectDecodeParamError(err error) string { - var str string - switch err.(type) { - case nil: - str = "Expected error but didn't get one" - case *shared.DecodeParamError: - break - default: - str = fmt.Sprintf("Expected *rpc.DecodeParamError but got %T with message `%s`", err, err.Error()) - } - return str -} - -func TestSha3(t *testing.T) { - input := `["0x68656c6c6f20776f726c64"]` - expected := "0x68656c6c6f20776f726c64" - - args := new(Sha3Args) - json.Unmarshal([]byte(input), &args) - - if args.Data != expected { - t.Error("got %s expected %s", input, expected) - } -} - -func TestSha3ArgsInvalid(t *testing.T) { - input := `{}` - - args := new(Sha3Args) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSha3ArgsEmpty(t *testing.T) { - input := `[]` - - args := new(Sha3Args) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} -func TestSha3ArgsDataInvalid(t *testing.T) { - input := `[4]` - - args := new(Sha3Args) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBalanceArgs(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x1f"]` - expected := new(GetBalanceArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.BlockNumber = 31 - - args := new(GetBalanceArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.Address != expected.Address { - t.Errorf("Address should be %v but is %v", expected.Address, args.Address) - } - - if args.BlockNumber != expected.BlockNumber { - t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetBalanceArgsBlocknumMissing(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1"]` - expected := new(GetBalanceArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.BlockNumber = -1 - - args := new(GetBalanceArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.Address != expected.Address { - t.Errorf("Address should be %v but is %v", expected.Address, args.Address) - } - - if args.BlockNumber != expected.BlockNumber { - t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetBalanceArgsLatest(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]` - expected := new(GetBalanceArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.BlockNumber = -1 - - args := new(GetBalanceArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.Address != expected.Address { - t.Errorf("Address should be %v but is %v", expected.Address, args.Address) - } - - if args.BlockNumber != expected.BlockNumber { - t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetBalanceArgsEmpty(t *testing.T) { - input := `[]` - - args := new(GetBalanceArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBalanceArgsInvalid(t *testing.T) { - input := `6` - - args := new(GetBalanceArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBalanceArgsBlockInvalid(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", false]` - - args := new(GetBalanceArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBalanceArgsAddressInvalid(t *testing.T) { - input := `[-9, "latest"]` - - args := new(GetBalanceArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBlockByHashArgs(t *testing.T) { - input := `["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true]` - expected := new(GetBlockByHashArgs) - expected.BlockHash = "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" - expected.IncludeTxs = true - - args := new(GetBlockByHashArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.BlockHash != expected.BlockHash { - t.Errorf("BlockHash should be %v but is %v", expected.BlockHash, args.BlockHash) - } - - if args.IncludeTxs != expected.IncludeTxs { - t.Errorf("IncludeTxs should be %v but is %v", expected.IncludeTxs, args.IncludeTxs) - } -} - -func TestGetBlockByHashArgsEmpty(t *testing.T) { - input := `[]` - - args := new(GetBlockByHashArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBlockByHashArgsInvalid(t *testing.T) { - input := `{}` - - args := new(GetBlockByHashArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBlockByHashArgsHashInt(t *testing.T) { - input := `[8]` - - args := new(GetBlockByHashArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBlockByHashArgsHashBool(t *testing.T) { - input := `[false, true]` - - args := new(GetBlockByHashArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBlockByNumberArgsBlockNum(t *testing.T) { - input := `[436, false]` - expected := new(GetBlockByNumberArgs) - expected.BlockNumber = 436 - expected.IncludeTxs = false - - args := new(GetBlockByNumberArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.BlockNumber != expected.BlockNumber { - t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber) - } - - if args.IncludeTxs != expected.IncludeTxs { - t.Errorf("IncludeTxs should be %v but is %v", expected.IncludeTxs, args.IncludeTxs) - } -} - -func TestGetBlockByNumberArgsBlockHex(t *testing.T) { - input := `["0x1b4", false]` - expected := new(GetBlockByNumberArgs) - expected.BlockNumber = 436 - expected.IncludeTxs = false - - args := new(GetBlockByNumberArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.BlockNumber != expected.BlockNumber { - t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber) - } - - if args.IncludeTxs != expected.IncludeTxs { - t.Errorf("IncludeTxs should be %v but is %v", expected.IncludeTxs, args.IncludeTxs) - } -} -func TestGetBlockByNumberArgsWords(t *testing.T) { - input := `["earliest", true]` - expected := new(GetBlockByNumberArgs) - expected.BlockNumber = 0 - expected.IncludeTxs = true - - args := new(GetBlockByNumberArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.BlockNumber != expected.BlockNumber { - t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber) - } - - if args.IncludeTxs != expected.IncludeTxs { - t.Errorf("IncludeTxs should be %v but is %v", expected.IncludeTxs, args.IncludeTxs) - } -} - -func TestGetBlockByNumberEmpty(t *testing.T) { - input := `[]` - - args := new(GetBlockByNumberArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBlockByNumberShort(t *testing.T) { - input := `["0xbbb"]` - - args := new(GetBlockByNumberArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetBlockByNumberBool(t *testing.T) { - input := `[true, true]` - - args := new(GetBlockByNumberArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} -func TestGetBlockByNumberBlockObject(t *testing.T) { - input := `{}` - - args := new(GetBlockByNumberArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestNewTxArgs(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, - "0x10"]` - expected := new(NewTxArgs) - expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155" - expected.To = "0xd46e8dd67c5d32be8058bb8eb970870f072445675" - expected.Gas = big.NewInt(30400) - expected.GasPrice = big.NewInt(10000000000000) - expected.Value = big.NewInt(10000000000000) - expected.Data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - expected.BlockNumber = big.NewInt(16).Int64() - - args := new(NewTxArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.From != args.From { - t.Errorf("From shoud be %#v but is %#v", expected.From, args.From) - } - - if expected.To != args.To { - t.Errorf("To shoud be %#v but is %#v", expected.To, args.To) - } - - if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { - t.Errorf("Gas shoud be %#v but is %#v", expected.Gas.Bytes(), args.Gas.Bytes()) - } - - if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 { - t.Errorf("GasPrice shoud be %#v but is %#v", expected.GasPrice, args.GasPrice) - } - - if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 { - t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value) - } - - if expected.Data != args.Data { - t.Errorf("Data shoud be %#v but is %#v", expected.Data, args.Data) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestNewTxArgsInt(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": 100, - "gasPrice": 50, - "value": 8765456789, - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, - 5]` - expected := new(NewTxArgs) - expected.Gas = big.NewInt(100) - expected.GasPrice = big.NewInt(50) - expected.Value = big.NewInt(8765456789) - expected.BlockNumber = int64(5) - - args := new(NewTxArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { - t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas) - } - - if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 { - t.Errorf("GasPrice shoud be %v but is %v", expected.GasPrice, args.GasPrice) - } - - if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 { - t.Errorf("Value shoud be %v but is %v", expected.Value, args.Value) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %v but is %v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestNewTxArgsBlockBool(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, - false]` - - args := new(NewTxArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestNewTxArgsGasInvalid(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": false, - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(NewTxArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestNewTxArgsGaspriceInvalid(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": false, - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(NewTxArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestNewTxArgsValueInvalid(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "value": false, - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(NewTxArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestNewTxArgsGasMissing(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - expected := new(NewTxArgs) - expected.Gas = nil - - args := new(NewTxArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.Gas != expected.Gas { - // if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { - t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas) - } -} - -func TestNewTxArgsBlockGaspriceMissing(t *testing.T) { - input := `[{ - "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - expected := new(NewTxArgs) - expected.GasPrice = nil - - args := new(NewTxArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.GasPrice != expected.GasPrice { - // if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 { - t.Errorf("GasPrice shoud be %v but is %v", expected.GasPrice, args.GasPrice) - } - -} - -func TestNewTxArgsValueMissing(t *testing.T) { - input := `[{ - "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - expected := new(NewTxArgs) - expected.Value = big.NewInt(0) - - args := new(NewTxArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 { - t.Errorf("Value shoud be %v but is %v", expected.Value, args.Value) - } - -} - -func TestNewTxArgsEmpty(t *testing.T) { - input := `[]` - - args := new(NewTxArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestNewTxArgsInvalid(t *testing.T) { - input := `{}` - - args := new(NewTxArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} -func TestNewTxArgsNotStrings(t *testing.T) { - input := `[{"from":6}]` - - args := new(NewTxArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestNewTxArgsFromEmpty(t *testing.T) { - input := `[{"to": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]` - - args := new(NewTxArgs) - str := ExpectValidationError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCallArgs(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, - "0x10"]` - expected := new(CallArgs) - expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155" - expected.To = "0xd46e8dd67c5d32be8058bb8eb970870f072445675" - expected.Gas = big.NewInt(30400) - expected.GasPrice = big.NewInt(10000000000000) - expected.Value = big.NewInt(10000000000000) - expected.Data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - expected.BlockNumber = big.NewInt(16).Int64() - - args := new(CallArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.To != args.To { - t.Errorf("To shoud be %#v but is %#v", expected.To, args.To) - } - - if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { - t.Errorf("Gas shoud be %#v but is %#v", expected.Gas.Bytes(), args.Gas.Bytes()) - } - - if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 { - t.Errorf("GasPrice shoud be %#v but is %#v", expected.GasPrice, args.GasPrice) - } - - if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 { - t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value) - } - - if expected.Data != args.Data { - t.Errorf("Data shoud be %#v but is %#v", expected.Data, args.Data) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestCallArgsInt(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": 100, - "gasPrice": 50, - "value": 8765456789, - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, - 5]` - expected := new(CallArgs) - expected.Gas = big.NewInt(100) - expected.GasPrice = big.NewInt(50) - expected.Value = big.NewInt(8765456789) - expected.BlockNumber = int64(5) - - args := new(CallArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { - t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas) - } - - if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 { - t.Errorf("GasPrice shoud be %v but is %v", expected.GasPrice, args.GasPrice) - } - - if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 { - t.Errorf("Value shoud be %v but is %v", expected.Value, args.Value) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %v but is %v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestCallArgsBlockBool(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, - false]` - - args := new(CallArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCallArgsGasInvalid(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": false, - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(CallArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCallArgsGaspriceInvalid(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": false, - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(CallArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCallArgsValueInvalid(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "value": false, - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(CallArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCallArgsGasMissing(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(CallArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - expected := new(CallArgs) - expected.Gas = nil - - if args.Gas != expected.Gas { - // if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 { - t.Errorf("Gas shoud be %v but is %v", expected.Gas, args.Gas) - } - -} - -func TestCallArgsBlockGaspriceMissing(t *testing.T) { - input := `[{ - "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(CallArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - expected := new(CallArgs) - expected.GasPrice = nil - - if args.GasPrice != expected.GasPrice { - // if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 { - t.Errorf("GasPrice shoud be %v but is %v", expected.GasPrice, args.GasPrice) - } -} - -func TestCallArgsValueMissing(t *testing.T) { - input := `[{ - "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" - }]` - - args := new(CallArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - expected := new(CallArgs) - expected.Value = big.NewInt(int64(0)) - - if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 { - t.Errorf("GasPrice shoud be %v but is %v", expected.Value, args.Value) - } -} - -func TestCallArgsEmpty(t *testing.T) { - input := `[]` - - args := new(CallArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCallArgsInvalid(t *testing.T) { - input := `{}` - - args := new(CallArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} -func TestCallArgsNotStrings(t *testing.T) { - input := `[{"from":6}]` - - args := new(CallArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCallArgsToEmpty(t *testing.T) { - input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}]` - args := new(CallArgs) - err := json.Unmarshal([]byte(input), &args) - if err != nil { - t.Error("Did not expect error. Got", err) - } -} - -func TestGetStorageArgs(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]` - expected := new(GetStorageArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.BlockNumber = -1 - - args := new(GetStorageArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetStorageArgsMissingBlocknum(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1"]` - expected := new(GetStorageArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.BlockNumber = -1 - - args := new(GetStorageArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetStorageInvalidArgs(t *testing.T) { - input := `{}` - - args := new(GetStorageArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageInvalidBlockheight(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", {}]` - - args := new(GetStorageArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageEmptyArgs(t *testing.T) { - input := `[]` - - args := new(GetStorageArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageAddressInt(t *testing.T) { - input := `[32456785432456, "latest"]` - - args := new(GetStorageArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageAtArgs(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0", "0x2"]` - expected := new(GetStorageAtArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.Key = "0x0" - expected.BlockNumber = 2 - - args := new(GetStorageAtArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.Key != args.Key { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetStorageAtArgsMissingBlocknum(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0"]` - expected := new(GetStorageAtArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.Key = "0x0" - expected.BlockNumber = -1 - - args := new(GetStorageAtArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.Key != args.Key { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetStorageAtEmptyArgs(t *testing.T) { - input := `[]` - - args := new(GetStorageAtArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageAtArgsInvalid(t *testing.T) { - input := `{}` - - args := new(GetStorageAtArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageAtArgsAddressNotString(t *testing.T) { - input := `[true, "0x0", "0x2"]` - - args := new(GetStorageAtArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageAtArgsKeyNotString(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", true, "0x2"]` - - args := new(GetStorageAtArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetStorageAtArgsValueNotString(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x1", true]` - - args := new(GetStorageAtArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetTxCountArgs(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "pending"]` - expected := new(GetTxCountArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.BlockNumber = -2 - - args := new(GetTxCountArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetTxCountEmptyArgs(t *testing.T) { - input := `[]` - - args := new(GetTxCountArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetTxCountEmptyArgsInvalid(t *testing.T) { - input := `false` - - args := new(GetTxCountArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetTxCountAddressNotString(t *testing.T) { - input := `[false, "pending"]` - - args := new(GetTxCountArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetTxCountBlockheightMissing(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1"]` - expected := new(GetTxCountArgs) - expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" - expected.BlockNumber = -1 - - args := new(GetTxCountArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetTxCountBlockheightInvalid(t *testing.T) { - input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", {}]` - - args := new(GetTxCountArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetDataArgs(t *testing.T) { - input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", "latest"]` - expected := new(GetDataArgs) - expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8" - expected.BlockNumber = -1 - - args := new(GetDataArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetDataArgsBlocknumMissing(t *testing.T) { - input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"]` - expected := new(GetDataArgs) - expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8" - expected.BlockNumber = -1 - - args := new(GetDataArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Address != args.Address { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestGetDataArgsEmpty(t *testing.T) { - input := `[]` - - args := new(GetDataArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetDataArgsInvalid(t *testing.T) { - input := `{}` - - args := new(GetDataArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetDataArgsAddressNotString(t *testing.T) { - input := `[12, "latest"]` - - args := new(GetDataArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestGetDataArgsBlocknumberNotString(t *testing.T) { - input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", false]` - - args := new(GetDataArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgs(t *testing.T) { - input := `[{ - "fromBlock": "0x1", - "toBlock": "0x2", - "limit": "0x3", - "offset": "0x0", - "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", - "topics": - [ - ["0xAA", "0xBB"], - ["0xCC", "0xDD"] - ] - }]` - - expected := new(BlockFilterArgs) - expected.Earliest = 1 - expected.Latest = 2 - expected.Max = 3 - expected.Skip = 0 - expected.Address = []string{"0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"} - expected.Topics = [][]string{ - []string{"0xAA", "0xBB"}, - []string{"0xCC", "0xDD"}, - } - - args := new(BlockFilterArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Earliest != args.Earliest { - t.Errorf("Earliest shoud be %#v but is %#v", expected.Earliest, args.Earliest) - } - - if expected.Latest != args.Latest { - t.Errorf("Latest shoud be %#v but is %#v", expected.Latest, args.Latest) - } - - if expected.Max != args.Max { - t.Errorf("Max shoud be %#v but is %#v", expected.Max, args.Max) - } - - if expected.Skip != args.Skip { - t.Errorf("Skip shoud be %#v but is %#v", expected.Skip, args.Skip) - } - - if expected.Address[0] != args.Address[0] { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.Topics[0][0] != args.Topics[0][0] { - t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) - } - if expected.Topics[0][1] != args.Topics[0][1] { - t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) - } - if expected.Topics[1][0] != args.Topics[1][0] { - t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) - } - if expected.Topics[1][1] != args.Topics[1][1] { - t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) - } - -} - -func TestBlockFilterArgsDefaults(t *testing.T) { - input := `[{ - "address": ["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"], - "topics": ["0xAA","0xBB"] - }]` - expected := new(BlockFilterArgs) - expected.Earliest = -1 - expected.Latest = -1 - expected.Max = 100 - expected.Skip = 0 - expected.Address = []string{"0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"} - expected.Topics = [][]string{[]string{"0xAA"}, []string{"0xBB"}} - - args := new(BlockFilterArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Earliest != args.Earliest { - t.Errorf("Earliest shoud be %#v but is %#v", expected.Earliest, args.Earliest) - } - - if expected.Latest != args.Latest { - t.Errorf("Latest shoud be %#v but is %#v", expected.Latest, args.Latest) - } - - if expected.Max != args.Max { - t.Errorf("Max shoud be %#v but is %#v", expected.Max, args.Max) - } - - if expected.Skip != args.Skip { - t.Errorf("Skip shoud be %#v but is %#v", expected.Skip, args.Skip) - } - - if expected.Address[0] != args.Address[0] { - t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) - } - - if expected.Topics[0][0] != args.Topics[0][0] { - t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) - } - - if expected.Topics[1][0] != args.Topics[1][0] { - t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) - } -} - -func TestBlockFilterArgsWords(t *testing.T) { - input := `[{"fromBlock": "latest", "toBlock": "latest"}]` - expected := new(BlockFilterArgs) - expected.Earliest = -1 - expected.Latest = -1 - - args := new(BlockFilterArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Earliest != args.Earliest { - t.Errorf("Earliest shoud be %#v but is %#v", expected.Earliest, args.Earliest) - } - - input = `[{"toBlock": "pending"}]` - if err := json.Unmarshal([]byte(input), &args); err == nil { - t.Errorf("Pending isn't currently supported and should raise an unsupported error") - } -} - -func TestBlockFilterArgsInvalid(t *testing.T) { - input := `{}` - - args := new(BlockFilterArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsFromBool(t *testing.T) { - input := `[{ - "fromBlock": true, - "toBlock": "pending" - }]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsToBool(t *testing.T) { - input := `[{ - "fromBlock": "pending", - "toBlock": true - }]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsEmptyArgs(t *testing.T) { - input := `[]` - - args := new(BlockFilterArgs) - err := json.Unmarshal([]byte(input), &args) - if err == nil { - t.Error("Expected error but didn't get one") - } -} - -func TestBlockFilterArgsLimitInvalid(t *testing.T) { - input := `[{"limit": false}]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsOffsetInvalid(t *testing.T) { - input := `[{"offset": true}]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsAddressInt(t *testing.T) { - input := `[{ - "address": 1, - "topics": "0x12341234"}]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsAddressSliceInt(t *testing.T) { - input := `[{ - "address": [1], - "topics": "0x12341234"}]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsTopicInt(t *testing.T) { - input := `[{ - "address": ["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"], - "topics": 1}]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsTopicSliceInt(t *testing.T) { - input := `[{ - "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", - "topics": [1]}]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsTopicSliceInt2(t *testing.T) { - input := `[{ - "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", - "topics": ["0xAA", [1]]}]` - - args := new(BlockFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockFilterArgsTopicComplex(t *testing.T) { - input := `[{ - "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", - "topics": ["0xAA", ["0xBB", "0xCC"]] - }]` - - args := new(BlockFilterArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - fmt.Printf("%v\n", args) - return - } - - if args.Topics[0][0] != "0xAA" { - t.Errorf("Topic should be %s but is %s", "0xAA", args.Topics[0][0]) - } - - if args.Topics[1][0] != "0xBB" { - t.Errorf("Topic should be %s but is %s", "0xBB", args.Topics[0][0]) - } - - if args.Topics[1][1] != "0xCC" { - t.Errorf("Topic should be %s but is %s", "0xCC", args.Topics[0][0]) - } -} - -func TestDbArgs(t *testing.T) { - input := `["testDB","myKey","0xbeef"]` - expected := new(DbArgs) - expected.Database = "testDB" - expected.Key = "myKey" - expected.Value = []byte("0xbeef") - - args := new(DbArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if err := args.requirements(); err != nil { - t.Error(err) - } - - if expected.Database != args.Database { - t.Errorf("Database shoud be %#v but is %#v", expected.Database, args.Database) - } - - if expected.Key != args.Key { - t.Errorf("Key shoud be %#v but is %#v", expected.Key, args.Key) - } - - if bytes.Compare(expected.Value, args.Value) != 0 { - t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value) - } -} - -func TestDbArgsInvalid(t *testing.T) { - input := `{}` - - args := new(DbArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbArgsEmpty(t *testing.T) { - input := `[]` - - args := new(DbArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbArgsDatabaseType(t *testing.T) { - input := `[true, "keyval", "valval"]` - - args := new(DbArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbArgsKeyType(t *testing.T) { - input := `["dbval", 3, "valval"]` - - args := new(DbArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbArgsValType(t *testing.T) { - input := `["dbval", "keyval", {}]` - - args := new(DbArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbArgsDatabaseEmpty(t *testing.T) { - input := `["", "keyval", "valval"]` - - args := new(DbArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err.Error()) - } - - str := ExpectValidationError(args.requirements()) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbArgsKeyEmpty(t *testing.T) { - input := `["dbval", "", "valval"]` - - args := new(DbArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err.Error()) - } - - str := ExpectValidationError(args.requirements()) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbHexArgs(t *testing.T) { - input := `["testDB","myKey","0xbeef"]` - expected := new(DbHexArgs) - expected.Database = "testDB" - expected.Key = "myKey" - expected.Value = []byte{0xbe, 0xef} - - args := new(DbHexArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if err := args.requirements(); err != nil { - t.Error(err) - } - - if expected.Database != args.Database { - t.Errorf("Database shoud be %#v but is %#v", expected.Database, args.Database) - } - - if expected.Key != args.Key { - t.Errorf("Key shoud be %#v but is %#v", expected.Key, args.Key) - } - - if bytes.Compare(expected.Value, args.Value) != 0 { - t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value) - } -} - -func TestDbHexArgsInvalid(t *testing.T) { - input := `{}` - - args := new(DbHexArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbHexArgsEmpty(t *testing.T) { - input := `[]` - - args := new(DbHexArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbHexArgsDatabaseType(t *testing.T) { - input := `[true, "keyval", "valval"]` - - args := new(DbHexArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbHexArgsKeyType(t *testing.T) { - input := `["dbval", 3, "valval"]` - - args := new(DbHexArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbHexArgsValType(t *testing.T) { - input := `["dbval", "keyval", {}]` - - args := new(DbHexArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbHexArgsDatabaseEmpty(t *testing.T) { - input := `["", "keyval", "valval"]` - - args := new(DbHexArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err.Error()) - } - - str := ExpectValidationError(args.requirements()) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDbHexArgsKeyEmpty(t *testing.T) { - input := `["dbval", "", "valval"]` - - args := new(DbHexArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err.Error()) - } - - str := ExpectValidationError(args.requirements()) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperMessageArgs(t *testing.T) { - input := `[{"from":"0xc931d93e97ab07fe42d923478ba2465f2", - "topics": ["0x68656c6c6f20776f726c64"], - "payload":"0x68656c6c6f20776f726c64", - "ttl": "0x64", - "priority": "0x64"}]` - expected := new(WhisperMessageArgs) - expected.From = "0xc931d93e97ab07fe42d923478ba2465f2" - expected.To = "" - expected.Payload = "0x68656c6c6f20776f726c64" - expected.Priority = 100 - expected.Ttl = 100 - // expected.Topics = []string{"0x68656c6c6f20776f726c64"} - - args := new(WhisperMessageArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.From != args.From { - t.Errorf("From shoud be %#v but is %#v", expected.From, args.From) - } - - if expected.To != args.To { - t.Errorf("To shoud be %#v but is %#v", expected.To, args.To) - } - - if expected.Payload != args.Payload { - t.Errorf("Value shoud be %#v but is %#v", expected.Payload, args.Payload) - } - - if expected.Ttl != args.Ttl { - t.Errorf("Ttl shoud be %#v but is %#v", expected.Ttl, args.Ttl) - } - - if expected.Priority != args.Priority { - t.Errorf("Priority shoud be %#v but is %#v", expected.Priority, args.Priority) - } - - // if expected.Topics != args.Topics { - // t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic) - // } -} - -func TestWhisperMessageArgsInt(t *testing.T) { - input := `[{"from":"0xc931d93e97ab07fe42d923478ba2465f2", - "topics": ["0x68656c6c6f20776f726c64"], - "payload":"0x68656c6c6f20776f726c64", - "ttl": 12, - "priority": 16}]` - expected := new(WhisperMessageArgs) - expected.From = "0xc931d93e97ab07fe42d923478ba2465f2" - expected.To = "" - expected.Payload = "0x68656c6c6f20776f726c64" - expected.Priority = 16 - expected.Ttl = 12 - // expected.Topics = []string{"0x68656c6c6f20776f726c64"} - - args := new(WhisperMessageArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.From != args.From { - t.Errorf("From shoud be %#v but is %#v", expected.From, args.From) - } - - if expected.To != args.To { - t.Errorf("To shoud be %#v but is %#v", expected.To, args.To) - } - - if expected.Payload != args.Payload { - t.Errorf("Value shoud be %#v but is %#v", expected.Payload, args.Payload) - } - - if expected.Ttl != args.Ttl { - t.Errorf("Ttl shoud be %v but is %v", expected.Ttl, args.Ttl) - } - - if expected.Priority != args.Priority { - t.Errorf("Priority shoud be %v but is %v", expected.Priority, args.Priority) - } - - // if expected.Topics != args.Topics { - // t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic) - // } -} - -func TestWhisperMessageArgsInvalid(t *testing.T) { - input := `{}` - - args := new(WhisperMessageArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperMessageArgsEmpty(t *testing.T) { - input := `[]` - - args := new(WhisperMessageArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperMessageArgsTtlBool(t *testing.T) { - input := `[{"from":"0xc931d93e97ab07fe42d923478ba2465f2", - "topics": ["0x68656c6c6f20776f726c64"], - "payload":"0x68656c6c6f20776f726c64", - "ttl": true, - "priority": "0x64"}]` - args := new(WhisperMessageArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperMessageArgsPriorityBool(t *testing.T) { - input := `[{"from":"0xc931d93e97ab07fe42d923478ba2465f2", - "topics": ["0x68656c6c6f20776f726c64"], - "payload":"0x68656c6c6f20776f726c64", - "ttl": "0x12", - "priority": true}]` - args := new(WhisperMessageArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestFilterIdArgs(t *testing.T) { - input := `["0x7"]` - expected := new(FilterIdArgs) - expected.Id = 7 - - args := new(FilterIdArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Id != args.Id { - t.Errorf("Id shoud be %#v but is %#v", expected.Id, args.Id) - } -} - -func TestFilterIdArgsInvalid(t *testing.T) { - input := `{}` - - args := new(FilterIdArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestFilterIdArgsEmpty(t *testing.T) { - input := `[]` - - args := new(FilterIdArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestFilterIdArgsBool(t *testing.T) { - input := `[true]` - - args := new(FilterIdArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestWhisperFilterArgs(t *testing.T) { - input := `[{"topics": ["0x68656c6c6f20776f726c64"], "to": "0x34ag445g3455b34"}]` - expected := new(WhisperFilterArgs) - expected.To = "0x34ag445g3455b34" - expected.Topics = [][]string{[]string{"0x68656c6c6f20776f726c64"}} - - args := new(WhisperFilterArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.To != args.To { - t.Errorf("To shoud be %#v but is %#v", expected.To, args.To) - } - - // if expected.Topics != args.Topics { - // t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) - // } -} - -func TestWhisperFilterArgsInvalid(t *testing.T) { - input := `{}` - - args := new(WhisperFilterArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperFilterArgsEmpty(t *testing.T) { - input := `[]` - - args := new(WhisperFilterArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperFilterArgsToInt(t *testing.T) { - input := `[{"to": 2}]` - - args := new(WhisperFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperFilterArgsToBool(t *testing.T) { - input := `[{"topics": ["0x68656c6c6f20776f726c64"], "to": false}]` - - args := new(WhisperFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestWhisperFilterArgsToMissing(t *testing.T) { - input := `[{"topics": ["0x68656c6c6f20776f726c64"]}]` - expected := new(WhisperFilterArgs) - expected.To = "" - - args := new(WhisperFilterArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if args.To != expected.To { - t.Errorf("To shoud be %v but is %v", expected.To, args.To) - } -} - -func TestWhisperFilterArgsTopicInt(t *testing.T) { - input := `[{"topics": [6], "to": "0x34ag445g3455b34"}]` - - args := new(WhisperFilterArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCompileArgs(t *testing.T) { - input := `["contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"]` - expected := new(CompileArgs) - expected.Source = `contract test { function multiply(uint a) returns(uint d) { return a * 7; } }` - - args := new(CompileArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Source != args.Source { - t.Errorf("Source shoud be %#v but is %#v", expected.Source, args.Source) - } -} - -func TestCompileArgsInvalid(t *testing.T) { - input := `{}` - - args := new(CompileArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCompileArgsEmpty(t *testing.T) { - input := `[]` - - args := new(CompileArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestCompileArgsBool(t *testing.T) { - input := `[false]` - - args := new(CompileArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestFilterStringArgs(t *testing.T) { - input := `["pending"]` - expected := new(FilterStringArgs) - expected.Word = "pending" - - args := new(FilterStringArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Word != args.Word { - t.Errorf("Word shoud be %#v but is %#v", expected.Word, args.Word) - } -} - -func TestFilterStringEmptyArgs(t *testing.T) { - input := `[]` - - args := new(FilterStringArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestFilterStringInvalidArgs(t *testing.T) { - input := `{}` - - args := new(FilterStringArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestFilterStringWordInt(t *testing.T) { - input := `[7]` - - args := new(FilterStringArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestFilterStringWordWrong(t *testing.T) { - input := `["foo"]` - - args := new(FilterStringArgs) - str := ExpectValidationError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestWhisperIdentityArgs(t *testing.T) { - input := `["0xc931d93e97ab07fe42d923478ba2465f283"]` - expected := new(WhisperIdentityArgs) - expected.Identity = "0xc931d93e97ab07fe42d923478ba2465f283" - - args := new(WhisperIdentityArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Identity != args.Identity { - t.Errorf("Identity shoud be %#v but is %#v", expected.Identity, args.Identity) - } -} - -func TestWhisperIdentityArgsInvalid(t *testing.T) { - input := `{}` - - args := new(WhisperIdentityArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestWhisperIdentityArgsEmpty(t *testing.T) { - input := `[]` - - args := new(WhisperIdentityArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestWhisperIdentityArgsInt(t *testing.T) { - input := `[4]` - - args := new(WhisperIdentityArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Errorf(str) - } -} - -func TestBlockNumArgs(t *testing.T) { - input := `["0x29a"]` - expected := new(BlockNumIndexArgs) - expected.BlockNumber = 666 - - args := new(BlockNumArg) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestBlockNumArgsWord(t *testing.T) { - input := `["pending"]` - expected := new(BlockNumIndexArgs) - expected.BlockNumber = -2 - - args := new(BlockNumArg) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } -} - -func TestBlockNumArgsInvalid(t *testing.T) { - input := `{}` - - args := new(BlockNumArg) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockNumArgsEmpty(t *testing.T) { - input := `[]` - - args := new(BlockNumArg) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} -func TestBlockNumArgsBool(t *testing.T) { - input := `[true]` - - args := new(BlockNumArg) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockNumIndexArgs(t *testing.T) { - input := `["0x29a", "0x0"]` - expected := new(BlockNumIndexArgs) - expected.BlockNumber = 666 - expected.Index = 0 - - args := new(BlockNumIndexArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } - - if expected.Index != args.Index { - t.Errorf("Index shoud be %#v but is %#v", expected.Index, args.Index) - } -} - -func TestBlockNumIndexArgsWord(t *testing.T) { - input := `["latest", 67]` - expected := new(BlockNumIndexArgs) - expected.BlockNumber = -1 - expected.Index = 67 - - args := new(BlockNumIndexArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.BlockNumber != args.BlockNumber { - t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) - } - - if expected.Index != args.Index { - t.Errorf("Index shoud be %#v but is %#v", expected.Index, args.Index) - } -} - -func TestBlockNumIndexArgsEmpty(t *testing.T) { - input := `[]` - - args := new(BlockNumIndexArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockNumIndexArgsInvalid(t *testing.T) { - input := `"foo"` - - args := new(BlockNumIndexArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockNumIndexArgsBlocknumInvalid(t *testing.T) { - input := `[{}, "0x1"]` - - args := new(BlockNumIndexArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockNumIndexArgsIndexInvalid(t *testing.T) { - input := `["0x29a", true]` - - args := new(BlockNumIndexArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestHashIndexArgs(t *testing.T) { - input := `["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "0x1"]` - expected := new(HashIndexArgs) - expected.Hash = "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b" - expected.Index = 1 - - args := new(HashIndexArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Hash != args.Hash { - t.Errorf("Hash shoud be %#v but is %#v", expected.Hash, args.Hash) - } - - if expected.Index != args.Index { - t.Errorf("Index shoud be %#v but is %#v", expected.Index, args.Index) - } -} - -func TestHashIndexArgsEmpty(t *testing.T) { - input := `[]` - - args := new(HashIndexArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestHashIndexArgsInvalid(t *testing.T) { - input := `{}` - - args := new(HashIndexArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestHashIndexArgsInvalidHash(t *testing.T) { - input := `[7, "0x1"]` - - args := new(HashIndexArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestHashIndexArgsInvalidIndex(t *testing.T) { - input := `["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", false]` - - args := new(HashIndexArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestHashArgs(t *testing.T) { - input := `["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"]` - expected := new(HashIndexArgs) - expected.Hash = "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b" - - args := new(HashArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Hash != args.Hash { - t.Errorf("Hash shoud be %#v but is %#v", expected.Hash, args.Hash) - } -} - -func TestHashArgsEmpty(t *testing.T) { - input := `[]` - - args := new(HashArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestHashArgsInvalid(t *testing.T) { - input := `{}` - - args := new(HashArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestHashArgsInvalidHash(t *testing.T) { - input := `[7]` - - args := new(HashArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSubmitWorkArgs(t *testing.T) { - input := `["0x0000000000000001", "0x1234567890abcdef1234567890abcdef", "0xD1GE5700000000000000000000000000"]` - expected := new(SubmitWorkArgs) - expected.Nonce = 1 - expected.Header = "0x1234567890abcdef1234567890abcdef" - expected.Digest = "0xD1GE5700000000000000000000000000" - - args := new(SubmitWorkArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Nonce != args.Nonce { - t.Errorf("Nonce shoud be %d but is %d", expected.Nonce, args.Nonce) - } - - if expected.Header != args.Header { - t.Errorf("Header shoud be %#v but is %#v", expected.Header, args.Header) - } - - if expected.Digest != args.Digest { - t.Errorf("Digest shoud be %#v but is %#v", expected.Digest, args.Digest) - } -} - -func TestSubmitWorkArgsInvalid(t *testing.T) { - input := `{}` - - args := new(SubmitWorkArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSubmitWorkArgsEmpty(t *testing.T) { - input := `[]` - - args := new(SubmitWorkArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSubmitWorkArgsNonceInt(t *testing.T) { - input := `[1, "0x1234567890abcdef1234567890abcdef", "0xD1GE5700000000000000000000000000"]` - - args := new(SubmitWorkArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} -func TestSubmitWorkArgsHeaderInt(t *testing.T) { - input := `["0x0000000000000001", 1, "0xD1GE5700000000000000000000000000"]` - - args := new(SubmitWorkArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} -func TestSubmitWorkArgsDigestInt(t *testing.T) { - input := `["0x0000000000000001", "0x1234567890abcdef1234567890abcdef", 1]` - - args := new(SubmitWorkArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestBlockHeightFromJsonInvalid(t *testing.T) { - var num int64 - var msg json.RawMessage = []byte(`}{`) - str := ExpectDecodeParamError(blockHeightFromJson(msg, &num)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSourceArgsEmpty(t *testing.T) { - input := `[]` - - args := new(SourceArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSigArgs(t *testing.T) { - input := `["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0"]` - expected := new(NewSigArgs) - expected.From = "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" - expected.Data = "0x0" - - args := new(NewSigArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.From != args.From { - t.Errorf("From should be %v but is %v", expected.From, args.From) - } - - if expected.Data != args.Data { - t.Errorf("Data should be %v but is %v", expected.Data, args.Data) - } -} - -func TestSigArgsEmptyData(t *testing.T) { - input := `["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", ""]` - - args := new(NewSigArgs) - str := ExpectValidationError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSigArgsDataType(t *testing.T) { - input := `["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 13]` - - args := new(NewSigArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSigArgsEmptyFrom(t *testing.T) { - input := `["", "0x0"]` - - args := new(NewSigArgs) - str := ExpectValidationError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSigArgsFromType(t *testing.T) { - input := `[false, "0x0"]` - - args := new(NewSigArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestSigArgsEmpty(t *testing.T) { - input := `[]` - args := new(NewSigArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDataArgs(t *testing.T) { - input := `["0x0123"]` - expected := new(NewDataArgs) - expected.Data = "0x0123" - - args := new(NewDataArgs) - if err := json.Unmarshal([]byte(input), &args); err != nil { - t.Error(err) - } - - if expected.Data != args.Data { - t.Errorf("Data should be %v but is %v", expected.Data, args.Data) - } -} - -func TestDataArgsEmptyData(t *testing.T) { - input := `[""]` - - args := new(NewDataArgs) - str := ExpectValidationError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDataArgsDataType(t *testing.T) { - input := `[13]` - - args := new(NewDataArgs) - str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDataArgsEmpty(t *testing.T) { - input := `[]` - args := new(NewDataArgs) - str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} - -func TestDataArgsInvalid(t *testing.T) { - input := `{}` - - args := new(NewDataArgs) - str := ExpectDecodeParamError(json.Unmarshal([]byte(input), args)) - if len(str) > 0 { - t.Error(str) - } -} diff --git a/rpc/api/db.go b/rpc/api/db.go deleted file mode 100644 index 0eddc410e..000000000 --- a/rpc/api/db.go +++ /dev/null @@ -1,144 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" -) - -const ( - DbApiversion = "1.0" -) - -var ( - // mapping between methods and handlers - DbMapping = map[string]dbhandler{ - "db_getString": (*dbApi).GetString, - "db_putString": (*dbApi).PutString, - "db_getHex": (*dbApi).GetHex, - "db_putHex": (*dbApi).PutHex, - } -) - -// db callback handler -type dbhandler func(*dbApi, *shared.Request) (interface{}, error) - -// db api provider -type dbApi struct { - xeth *xeth.XEth - ethereum *eth.Ethereum - methods map[string]dbhandler - codec codec.ApiCoder -} - -// create a new db api instance -func NewDbApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *dbApi { - return &dbApi{ - xeth: xeth, - ethereum: ethereum, - methods: DbMapping, - codec: coder.New(nil), - } -} - -// collection with supported methods -func (self *dbApi) 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 *dbApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, &shared.NotImplementedError{req.Method} -} - -func (self *dbApi) Name() string { - return shared.DbApiName -} - -func (self *dbApi) ApiVersion() string { - return DbApiversion -} - -func (self *dbApi) GetString(req *shared.Request) (interface{}, error) { - args := new(DbArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - if err := args.requirements(); err != nil { - return nil, err - } - - ret, err := self.xeth.DbGet([]byte(args.Database + args.Key)) - return string(ret), err -} - -func (self *dbApi) PutString(req *shared.Request) (interface{}, error) { - args := new(DbArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - if err := args.requirements(); err != nil { - return nil, err - } - - return self.xeth.DbPut([]byte(args.Database+args.Key), args.Value), nil -} - -func (self *dbApi) GetHex(req *shared.Request) (interface{}, error) { - args := new(DbHexArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - if err := args.requirements(); err != nil { - return nil, err - } - - if res, err := self.xeth.DbGet([]byte(args.Database + args.Key)); err == nil { - return newHexData(res), nil - } else { - return nil, err - } -} - -func (self *dbApi) PutHex(req *shared.Request) (interface{}, error) { - args := new(DbHexArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - if err := args.requirements(); err != nil { - return nil, err - } - - return self.xeth.DbPut([]byte(args.Database+args.Key), args.Value), nil -} diff --git a/rpc/api/db_args.go b/rpc/api/db_args.go deleted file mode 100644 index d61ea77ee..000000000 --- a/rpc/api/db_args.go +++ /dev/null @@ -1,126 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type DbArgs struct { - Database string - Key string - Value []byte -} - -func (args *DbArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - var objstr string - var ok bool - - if objstr, ok = obj[0].(string); !ok { - return shared.NewInvalidTypeError("database", "not a string") - } - args.Database = objstr - - if objstr, ok = obj[1].(string); !ok { - return shared.NewInvalidTypeError("key", "not a string") - } - args.Key = objstr - - if len(obj) > 2 { - objstr, ok = obj[2].(string) - if !ok { - return shared.NewInvalidTypeError("value", "not a string") - } - - args.Value = []byte(objstr) - } - - return nil -} - -func (a *DbArgs) requirements() error { - if len(a.Database) == 0 { - return shared.NewValidationError("Database", "cannot be blank") - } - if len(a.Key) == 0 { - return shared.NewValidationError("Key", "cannot be blank") - } - return nil -} - -type DbHexArgs struct { - Database string - Key string - Value []byte -} - -func (args *DbHexArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - var objstr string - var ok bool - - if objstr, ok = obj[0].(string); !ok { - return shared.NewInvalidTypeError("database", "not a string") - } - args.Database = objstr - - if objstr, ok = obj[1].(string); !ok { - return shared.NewInvalidTypeError("key", "not a string") - } - args.Key = objstr - - if len(obj) > 2 { - objstr, ok = obj[2].(string) - if !ok { - return shared.NewInvalidTypeError("value", "not a string") - } - - args.Value = common.FromHex(objstr) - } - - return nil -} - -func (a *DbHexArgs) requirements() error { - if len(a.Database) == 0 { - return shared.NewValidationError("Database", "cannot be blank") - } - if len(a.Key) == 0 { - return shared.NewValidationError("Key", "cannot be blank") - } - return nil -} diff --git a/rpc/api/db_js.go b/rpc/api/db_js.go deleted file mode 100644 index 899f8abd9..000000000 --- a/rpc/api/db_js.go +++ /dev/null @@ -1,29 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const Db_JS = ` -web3._extend({ - property: 'db', - methods: - [ - ], - properties: - [ - ] -}); -` diff --git a/rpc/api/debug.go b/rpc/api/debug.go deleted file mode 100644 index a6faa335e..000000000 --- a/rpc/api/debug.go +++ /dev/null @@ -1,303 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "fmt" - "strings" - "time" - - "github.com/ethereum/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" - "github.com/rcrowley/go-metrics" -) - -const ( - DebugApiVersion = "1.0" -) - -var ( - // mapping between methods and handlers - DebugMapping = map[string]debughandler{ - "debug_dumpBlock": (*debugApi).DumpBlock, - "debug_getBlockRlp": (*debugApi).GetBlockRlp, - "debug_printBlock": (*debugApi).PrintBlock, - "debug_processBlock": (*debugApi).ProcessBlock, - "debug_seedHash": (*debugApi).SeedHash, - "debug_setHead": (*debugApi).SetHead, - "debug_metrics": (*debugApi).Metrics, - } -) - -// debug callback handler -type debughandler func(*debugApi, *shared.Request) (interface{}, error) - -// admin api provider -type debugApi struct { - xeth *xeth.XEth - ethereum *eth.Ethereum - methods map[string]debughandler - codec codec.ApiCoder -} - -// create a new debug api instance -func NewDebugApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *debugApi { - return &debugApi{ - xeth: xeth, - ethereum: ethereum, - methods: DebugMapping, - codec: coder.New(nil), - } -} - -// collection with supported methods -func (self *debugApi) 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 *debugApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, &shared.NotImplementedError{req.Method} -} - -func (self *debugApi) Name() string { - return shared.DebugApiName -} - -func (self *debugApi) ApiVersion() string { - return DebugApiVersion -} - -func (self *debugApi) PrintBlock(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByNumber(args.BlockNumber) - return fmt.Sprintf("%s", block), nil -} - -func (self *debugApi) DumpBlock(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByNumber(args.BlockNumber) - if block == nil { - return nil, fmt.Errorf("block #%d not found", args.BlockNumber) - } - - stateDb, err := state.New(block.Root(), self.ethereum.ChainDb()) - if err != nil { - return nil, err - } - - return stateDb.RawDump(), nil -} - -func (self *debugApi) GetBlockRlp(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByNumber(args.BlockNumber) - if block == nil { - return nil, fmt.Errorf("block #%d not found", args.BlockNumber) - } - encoded, err := rlp.EncodeToBytes(block) - return fmt.Sprintf("%x", encoded), err -} - -func (self *debugApi) SetHead(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - self.ethereum.BlockChain().SetHead(uint64(args.BlockNumber)) - - return nil, nil -} - -func (self *debugApi) ProcessBlock(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByNumber(args.BlockNumber) - if block == nil { - return nil, fmt.Errorf("block #%d not found", args.BlockNumber) - } - - old := vm.Debug - defer func() { vm.Debug = old }() - vm.Debug = true - - var ( - blockchain = self.ethereum.BlockChain() - validator = blockchain.Validator() - processor = blockchain.Processor() - ) - - err := core.ValidateHeader(blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash()), true, false) - if err != nil { - return false, err - } - statedb, err := state.New(blockchain.GetBlock(block.ParentHash()).Root(), self.ethereum.ChainDb()) - if err != nil { - return false, err - } - receipts, _, usedGas, err := processor.Process(block, statedb) - if err != nil { - return false, err - } - err = validator.ValidateState(block, blockchain.GetBlock(block.ParentHash()), statedb, receipts, usedGas) - if err != nil { - return false, err - } - - return true, nil -} - -func (self *debugApi) SeedHash(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - if hash, err := ethash.GetSeedHash(uint64(args.BlockNumber)); err == nil { - return fmt.Sprintf("0x%x", hash), nil - } else { - return nil, err - } -} - -func (self *debugApi) Metrics(req *shared.Request) (interface{}, error) { - args := new(MetricsArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - // Create a rate formatter - units := []string{"", "K", "M", "G", "T", "E", "P"} - round := func(value float64, prec int) string { - unit := 0 - for value >= 1000 { - unit, value, prec = unit+1, value/1000, 2 - } - return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) - } - format := func(total float64, rate float64) string { - return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) - } - // Iterate over all the metrics, and just dump for now - counters := make(map[string]interface{}) - metrics.DefaultRegistry.Each(func(name string, metric interface{}) { - // Create or retrieve the counter hierarchy for this metric - root, parts := counters, strings.Split(name, "/") - for _, part := range parts[:len(parts)-1] { - if _, ok := root[part]; !ok { - root[part] = make(map[string]interface{}) - } - root = root[part].(map[string]interface{}) - } - name = parts[len(parts)-1] - - // Fill the counter with the metric details, formatting if requested - if args.Raw { - switch metric := metric.(type) { - case metrics.Meter: - root[name] = map[string]interface{}{ - "AvgRate01Min": metric.Rate1(), - "AvgRate05Min": metric.Rate5(), - "AvgRate15Min": metric.Rate15(), - "MeanRate": metric.RateMean(), - "Overall": float64(metric.Count()), - } - - case metrics.Timer: - root[name] = map[string]interface{}{ - "AvgRate01Min": metric.Rate1(), - "AvgRate05Min": metric.Rate5(), - "AvgRate15Min": metric.Rate15(), - "MeanRate": metric.RateMean(), - "Overall": float64(metric.Count()), - "Percentiles": map[string]interface{}{ - "5": metric.Percentile(0.05), - "20": metric.Percentile(0.2), - "50": metric.Percentile(0.5), - "80": metric.Percentile(0.8), - "95": metric.Percentile(0.95), - }, - } - - default: - root[name] = "Unknown metric type" - } - } else { - switch metric := metric.(type) { - case metrics.Meter: - root[name] = map[string]interface{}{ - "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), - "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), - "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), - "Overall": format(float64(metric.Count()), metric.RateMean()), - } - - case metrics.Timer: - root[name] = map[string]interface{}{ - "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), - "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), - "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), - "Overall": format(float64(metric.Count()), metric.RateMean()), - "Maximum": time.Duration(metric.Max()).String(), - "Minimum": time.Duration(metric.Min()).String(), - "Percentiles": map[string]interface{}{ - "5": time.Duration(metric.Percentile(0.05)).String(), - "20": time.Duration(metric.Percentile(0.2)).String(), - "50": time.Duration(metric.Percentile(0.5)).String(), - "80": time.Duration(metric.Percentile(0.8)).String(), - "95": time.Duration(metric.Percentile(0.95)).String(), - }, - } - - default: - root[name] = "Unknown metric type" - } - } - }) - return counters, nil -} diff --git a/rpc/api/debug_args.go b/rpc/api/debug_args.go deleted file mode 100644 index 041ad6b6a..000000000 --- a/rpc/api/debug_args.go +++ /dev/null @@ -1,87 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - "fmt" - "math/big" - "reflect" - - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type WaitForBlockArgs struct { - MinHeight int - Timeout int // in seconds -} - -func (args *WaitForBlockArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) > 2 { - return fmt.Errorf("waitForArgs needs 0, 1, 2 arguments") - } - - // default values when not provided - args.MinHeight = -1 - args.Timeout = -1 - - if len(obj) >= 1 { - var minHeight *big.Int - if minHeight, err = numString(obj[0]); err != nil { - return err - } - args.MinHeight = int(minHeight.Int64()) - } - - if len(obj) >= 2 { - timeout, err := numString(obj[1]) - if err != nil { - return err - } - args.Timeout = int(timeout.Int64()) - } - - return nil -} - -type MetricsArgs struct { - Raw bool -} - -func (args *MetricsArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - if len(obj) > 1 { - return fmt.Errorf("metricsArgs needs 0, 1 arguments") - } - // default values when not provided - if len(obj) >= 1 && obj[0] != nil { - if value, ok := obj[0].(bool); !ok { - return fmt.Errorf("invalid argument %v", reflect.TypeOf(obj[0])) - } else { - args.Raw = value - } - } - return nil -} diff --git a/rpc/api/debug_js.go b/rpc/api/debug_js.go deleted file mode 100644 index 030511add..000000000 --- a/rpc/api/debug_js.go +++ /dev/null @@ -1,83 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const Debug_JS = ` -web3._extend({ - property: 'debug', - methods: - [ - new web3._extend.Method({ - name: 'printBlock', - call: 'debug_printBlock', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'getBlockRlp', - call: 'debug_getBlockRlp', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'setHead', - call: 'debug_setHead', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'processBlock', - call: 'debug_processBlock', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'seedHash', - call: 'debug_seedHash', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'dumpBlock', - call: 'debug_dumpBlock', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'metrics', - call: 'debug_metrics', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'verbosity', - call: 'debug_verbosity', - params: 1, - inputFormatter: [web3._extend.utils.fromDecimal] - }), - new web3._extend.Method({ - name: 'vmodule', - call: 'debug_vmodule', - params: 1, - inputFormatter: [null] - }), - ], - properties: - [ - ] -}); -` diff --git a/rpc/api/eth.go b/rpc/api/eth.go deleted file mode 100644 index db7a643d8..000000000 --- a/rpc/api/eth.go +++ /dev/null @@ -1,721 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "bytes" - "encoding/json" - "math/big" - - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/natspec" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" - "gopkg.in/fatih/set.v0" -) - -const ( - EthApiVersion = "1.0" -) - -// eth api provider -// See https://github.com/ethereum/wiki/wiki/JSON-RPC -type ethApi struct { - xeth *xeth.XEth - ethereum *eth.Ethereum - methods map[string]ethhandler - codec codec.ApiCoder -} - -// eth callback handler -type ethhandler func(*ethApi, *shared.Request) (interface{}, error) - -var ( - ethMapping = map[string]ethhandler{ - "eth_accounts": (*ethApi).Accounts, - "eth_blockNumber": (*ethApi).BlockNumber, - "eth_getBalance": (*ethApi).GetBalance, - "eth_protocolVersion": (*ethApi).ProtocolVersion, - "eth_coinbase": (*ethApi).Coinbase, - "eth_mining": (*ethApi).IsMining, - "eth_syncing": (*ethApi).IsSyncing, - "eth_gasPrice": (*ethApi).GasPrice, - "eth_getStorage": (*ethApi).GetStorage, - "eth_storageAt": (*ethApi).GetStorage, - "eth_getStorageAt": (*ethApi).GetStorageAt, - "eth_getTransactionCount": (*ethApi).GetTransactionCount, - "eth_getBlockTransactionCountByHash": (*ethApi).GetBlockTransactionCountByHash, - "eth_getBlockTransactionCountByNumber": (*ethApi).GetBlockTransactionCountByNumber, - "eth_getUncleCountByBlockHash": (*ethApi).GetUncleCountByBlockHash, - "eth_getUncleCountByBlockNumber": (*ethApi).GetUncleCountByBlockNumber, - "eth_getData": (*ethApi).GetData, - "eth_getCode": (*ethApi).GetData, - "eth_getNatSpec": (*ethApi).GetNatSpec, - "eth_sign": (*ethApi).Sign, - "eth_sendRawTransaction": (*ethApi).SubmitTransaction, - "eth_submitTransaction": (*ethApi).SubmitTransaction, - "eth_sendTransaction": (*ethApi).SendTransaction, - "eth_signTransaction": (*ethApi).SignTransaction, - "eth_transact": (*ethApi).SendTransaction, - "eth_estimateGas": (*ethApi).EstimateGas, - "eth_call": (*ethApi).Call, - "eth_flush": (*ethApi).Flush, - "eth_getBlockByHash": (*ethApi).GetBlockByHash, - "eth_getBlockByNumber": (*ethApi).GetBlockByNumber, - "eth_getTransactionByHash": (*ethApi).GetTransactionByHash, - "eth_getTransactionByBlockNumberAndIndex": (*ethApi).GetTransactionByBlockNumberAndIndex, - "eth_getTransactionByBlockHashAndIndex": (*ethApi).GetTransactionByBlockHashAndIndex, - "eth_getUncleByBlockHashAndIndex": (*ethApi).GetUncleByBlockHashAndIndex, - "eth_getUncleByBlockNumberAndIndex": (*ethApi).GetUncleByBlockNumberAndIndex, - "eth_getCompilers": (*ethApi).GetCompilers, - "eth_compileSolidity": (*ethApi).CompileSolidity, - "eth_newFilter": (*ethApi).NewFilter, - "eth_newBlockFilter": (*ethApi).NewBlockFilter, - "eth_newPendingTransactionFilter": (*ethApi).NewPendingTransactionFilter, - "eth_uninstallFilter": (*ethApi).UninstallFilter, - "eth_getFilterChanges": (*ethApi).GetFilterChanges, - "eth_getFilterLogs": (*ethApi).GetFilterLogs, - "eth_getLogs": (*ethApi).GetLogs, - "eth_hashrate": (*ethApi).Hashrate, - "eth_getWork": (*ethApi).GetWork, - "eth_submitWork": (*ethApi).SubmitWork, - "eth_submitHashrate": (*ethApi).SubmitHashrate, - "eth_resend": (*ethApi).Resend, - "eth_pendingTransactions": (*ethApi).PendingTransactions, - "eth_getTransactionReceipt": (*ethApi).GetTransactionReceipt, - } -) - -// create new ethApi instance -func NewEthApi(xeth *xeth.XEth, eth *eth.Ethereum, codec codec.Codec) *ethApi { - return ðApi{xeth, eth, ethMapping, codec.New(nil)} -} - -// collection with supported methods -func (self *ethApi) 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 *ethApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, shared.NewNotImplementedError(req.Method) -} - -func (self *ethApi) Name() string { - return shared.EthApiName -} - -func (self *ethApi) ApiVersion() string { - return EthApiVersion -} - -func (self *ethApi) Accounts(req *shared.Request) (interface{}, error) { - return self.xeth.Accounts(), nil -} - -func (self *ethApi) Hashrate(req *shared.Request) (interface{}, error) { - return newHexNum(self.xeth.HashRate()), nil -} - -func (self *ethApi) BlockNumber(req *shared.Request) (interface{}, error) { - num := self.xeth.CurrentBlock().Number() - return newHexNum(num.Bytes()), nil -} - -func (self *ethApi) GetBalance(req *shared.Request) (interface{}, error) { - args := new(GetBalanceArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - return self.xeth.AtStateNum(args.BlockNumber).BalanceAt(args.Address), nil -} - -func (self *ethApi) ProtocolVersion(req *shared.Request) (interface{}, error) { - return self.xeth.EthVersion(), nil -} - -func (self *ethApi) Coinbase(req *shared.Request) (interface{}, error) { - return newHexData(self.xeth.Coinbase()), nil -} - -func (self *ethApi) IsMining(req *shared.Request) (interface{}, error) { - return self.xeth.IsMining(), nil -} - -func (self *ethApi) IsSyncing(req *shared.Request) (interface{}, error) { - origin, current, height := self.ethereum.Downloader().Progress() - if current < height { - return map[string]interface{}{ - "startingBlock": newHexNum(big.NewInt(int64(origin)).Bytes()), - "currentBlock": newHexNum(big.NewInt(int64(current)).Bytes()), - "highestBlock": newHexNum(big.NewInt(int64(height)).Bytes()), - }, nil - } - return false, nil -} - -func (self *ethApi) GasPrice(req *shared.Request) (interface{}, error) { - return newHexNum(self.xeth.DefaultGasPrice().Bytes()), nil -} - -func (self *ethApi) GetStorage(req *shared.Request) (interface{}, error) { - args := new(GetStorageArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - return self.xeth.AtStateNum(args.BlockNumber).State().SafeGet(args.Address).Storage(), nil -} - -func (self *ethApi) GetStorageAt(req *shared.Request) (interface{}, error) { - args := new(GetStorageAtArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - return self.xeth.AtStateNum(args.BlockNumber).StorageAt(args.Address, args.Key), nil -} - -func (self *ethApi) GetTransactionCount(req *shared.Request) (interface{}, error) { - args := new(GetTxCountArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - count := self.xeth.AtStateNum(args.BlockNumber).TxCountAt(args.Address) - return fmt.Sprintf("%#x", count), nil -} - -func (self *ethApi) GetBlockTransactionCountByHash(req *shared.Request) (interface{}, error) { - args := new(HashArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - block := self.xeth.EthBlockByHash(args.Hash) - if block == nil { - return nil, nil - } - return fmt.Sprintf("%#x", len(block.Transactions())), nil -} - -func (self *ethApi) GetBlockTransactionCountByNumber(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByNumber(args.BlockNumber) - if block == nil { - return nil, nil - } - return fmt.Sprintf("%#x", len(block.Transactions())), nil -} - -func (self *ethApi) GetUncleCountByBlockHash(req *shared.Request) (interface{}, error) { - args := new(HashArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByHash(args.Hash) - if block == nil { - return nil, nil - } - return fmt.Sprintf("%#x", len(block.Uncles())), nil -} - -func (self *ethApi) GetUncleCountByBlockNumber(req *shared.Request) (interface{}, error) { - args := new(BlockNumArg) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByNumber(args.BlockNumber) - if block == nil { - return nil, nil - } - return fmt.Sprintf("%#x", len(block.Uncles())), nil -} - -func (self *ethApi) GetData(req *shared.Request) (interface{}, error) { - args := new(GetDataArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - v := self.xeth.AtStateNum(args.BlockNumber).CodeAtBytes(args.Address) - return newHexData(v), nil -} - -func (self *ethApi) Sign(req *shared.Request) (interface{}, error) { - args := new(NewSigArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - v, err := self.xeth.Sign(args.From, args.Data, false) - if err != nil { - return nil, err - } - return v, nil -} - -func (self *ethApi) SubmitTransaction(req *shared.Request) (interface{}, error) { - args := new(NewDataArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - v, err := self.xeth.PushTx(args.Data) - if err != nil { - return nil, err - } - return v, nil -} - -// JsonTransaction is returned as response by the JSON RPC. It contains the -// signed RLP encoded transaction as Raw and the signed transaction object as Tx. -type JsonTransaction struct { - Raw string `json:"raw"` - Tx *tx `json:"tx"` -} - -func (self *ethApi) SignTransaction(req *shared.Request) (interface{}, error) { - args := new(NewTxArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - // nonce may be nil ("guess" mode) - var nonce string - if args.Nonce != nil { - nonce = args.Nonce.String() - } - - var gas, price string - if args.Gas != nil { - gas = args.Gas.String() - } - if args.GasPrice != nil { - price = args.GasPrice.String() - } - tx, err := self.xeth.SignTransaction(args.From, args.To, nonce, args.Value.String(), gas, price, args.Data) - if err != nil { - return nil, err - } - - data, err := rlp.EncodeToBytes(tx) - if err != nil { - return nil, err - } - - return JsonTransaction{"0x" + common.Bytes2Hex(data), newTx(tx)}, nil -} - -func (self *ethApi) SendTransaction(req *shared.Request) (interface{}, error) { - args := new(NewTxArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - // nonce may be nil ("guess" mode) - var nonce string - if args.Nonce != nil { - nonce = args.Nonce.String() - } - - var gas, price string - if args.Gas != nil { - gas = args.Gas.String() - } - if args.GasPrice != nil { - price = args.GasPrice.String() - } - v, err := self.xeth.Transact(args.From, args.To, nonce, args.Value.String(), gas, price, args.Data) - if err != nil { - return nil, err - } - return v, nil -} - -func (self *ethApi) GetNatSpec(req *shared.Request) (interface{}, error) { - args := new(NewTxArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - var jsontx = fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, args.To, args.Data) - notice := natspec.GetNotice(self.xeth, jsontx, self.ethereum.HTTPClient()) - - return notice, nil -} - -func (self *ethApi) EstimateGas(req *shared.Request) (interface{}, error) { - _, gas, err := self.doCall(req.Params) - if err != nil { - return nil, err - } - - // TODO unwrap the parent method's ToHex call - if len(gas) == 0 { - return newHexNum(0), nil - } else { - return newHexNum(common.String2Big(gas)), err - } -} - -func (self *ethApi) Call(req *shared.Request) (interface{}, error) { - v, _, err := self.doCall(req.Params) - if err != nil { - return nil, err - } - - // TODO unwrap the parent method's ToHex call - if v == "0x0" { - return newHexData([]byte{}), nil - } else { - return newHexData(common.FromHex(v)), nil - } -} - -func (self *ethApi) Flush(req *shared.Request) (interface{}, error) { - return nil, shared.NewNotImplementedError(req.Method) -} - -func (self *ethApi) doCall(params json.RawMessage) (string, string, error) { - args := new(CallArgs) - if err := self.codec.Decode(params, &args); err != nil { - return "", "", err - } - - return self.xeth.AtStateNum(args.BlockNumber).Call(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data) -} - -func (self *ethApi) GetBlockByHash(req *shared.Request) (interface{}, error) { - args := new(GetBlockByHashArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - block := self.xeth.EthBlockByHash(args.BlockHash) - if block == nil { - return nil, nil - } - return NewBlockRes(block, self.xeth.Td(block.Hash()), args.IncludeTxs), nil -} - -func (self *ethApi) GetBlockByNumber(req *shared.Request) (interface{}, error) { - args := new(GetBlockByNumberArgs) - if err := json.Unmarshal(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - block := self.xeth.EthBlockByNumber(args.BlockNumber) - if block == nil { - return nil, nil - } - return NewBlockRes(block, self.xeth.Td(block.Hash()), args.IncludeTxs), nil -} - -func (self *ethApi) GetTransactionByHash(req *shared.Request) (interface{}, error) { - args := new(HashArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - tx, bhash, bnum, txi := self.xeth.EthTransactionByHash(args.Hash) - if tx != nil { - v := NewTransactionRes(tx) - // if the blockhash is 0, assume this is a pending transaction - if bytes.Compare(bhash.Bytes(), bytes.Repeat([]byte{0}, 32)) != 0 { - v.BlockHash = newHexData(bhash) - v.BlockNumber = newHexNum(bnum) - v.TxIndex = newHexNum(txi) - } - return v, nil - } - return nil, nil -} - -func (self *ethApi) GetTransactionByBlockHashAndIndex(req *shared.Request) (interface{}, error) { - args := new(HashIndexArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - raw := self.xeth.EthBlockByHash(args.Hash) - if raw == nil { - return nil, nil - } - block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), true) - if args.Index >= int64(len(block.Transactions)) || args.Index < 0 { - return nil, nil - } else { - return block.Transactions[args.Index], nil - } -} - -func (self *ethApi) GetTransactionByBlockNumberAndIndex(req *shared.Request) (interface{}, error) { - args := new(BlockNumIndexArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - raw := self.xeth.EthBlockByNumber(args.BlockNumber) - if raw == nil { - return nil, nil - } - block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), true) - if args.Index >= int64(len(block.Transactions)) || args.Index < 0 { - // return NewValidationError("Index", "does not exist") - return nil, nil - } - return block.Transactions[args.Index], nil -} - -func (self *ethApi) GetUncleByBlockHashAndIndex(req *shared.Request) (interface{}, error) { - args := new(HashIndexArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - raw := self.xeth.EthBlockByHash(args.Hash) - if raw == nil { - return nil, nil - } - block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), false) - if args.Index >= int64(len(block.Uncles)) || args.Index < 0 { - // return NewValidationError("Index", "does not exist") - return nil, nil - } - return block.Uncles[args.Index], nil -} - -func (self *ethApi) GetUncleByBlockNumberAndIndex(req *shared.Request) (interface{}, error) { - args := new(BlockNumIndexArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - raw := self.xeth.EthBlockByNumber(args.BlockNumber) - if raw == nil { - return nil, nil - } - block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), true) - if args.Index >= int64(len(block.Uncles)) || args.Index < 0 { - return nil, nil - } else { - return block.Uncles[args.Index], nil - } -} - -func (self *ethApi) GetCompilers(req *shared.Request) (interface{}, error) { - var lang string - if solc, _ := self.xeth.Solc(); solc != nil { - lang = "Solidity" - } - c := []string{lang} - return c, nil -} - -func (self *ethApi) CompileSolidity(req *shared.Request) (interface{}, error) { - solc, _ := self.xeth.Solc() - if solc == nil { - return nil, shared.NewNotAvailableError(req.Method, "solc (solidity compiler) not found") - } - - args := new(SourceArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - contracts, err := solc.Compile(args.Source) - if err != nil { - return nil, err - } - return contracts, nil -} - -func (self *ethApi) NewFilter(req *shared.Request) (interface{}, error) { - args := new(BlockFilterArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - id := self.xeth.NewLogFilter(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics) - return newHexNum(big.NewInt(int64(id)).Bytes()), nil -} - -func (self *ethApi) NewBlockFilter(req *shared.Request) (interface{}, error) { - return newHexNum(self.xeth.NewBlockFilter()), nil -} - -func (self *ethApi) NewPendingTransactionFilter(req *shared.Request) (interface{}, error) { - return newHexNum(self.xeth.NewTransactionFilter()), nil -} - -func (self *ethApi) UninstallFilter(req *shared.Request) (interface{}, error) { - args := new(FilterIdArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - return self.xeth.UninstallFilter(args.Id), nil -} - -func (self *ethApi) GetFilterChanges(req *shared.Request) (interface{}, error) { - args := new(FilterIdArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - switch self.xeth.GetFilterType(args.Id) { - case xeth.BlockFilterTy: - return NewHashesRes(self.xeth.BlockFilterChanged(args.Id)), nil - case xeth.TransactionFilterTy: - return NewHashesRes(self.xeth.TransactionFilterChanged(args.Id)), nil - case xeth.LogFilterTy: - return NewLogsRes(self.xeth.LogFilterChanged(args.Id)), nil - default: - return []string{}, nil // reply empty string slice - } -} - -func (self *ethApi) GetFilterLogs(req *shared.Request) (interface{}, error) { - args := new(FilterIdArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - return NewLogsRes(self.xeth.Logs(args.Id)), nil -} - -func (self *ethApi) GetLogs(req *shared.Request) (interface{}, error) { - args := new(BlockFilterArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - return NewLogsRes(self.xeth.AllLogs(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics)), nil -} - -func (self *ethApi) GetWork(req *shared.Request) (interface{}, error) { - self.xeth.SetMining(true, 0) - ret, err := self.xeth.RemoteMining().GetWork() - if err != nil { - return nil, shared.NewNotReadyError("mining work") - } else { - return ret, nil - } -} - -func (self *ethApi) SubmitWork(req *shared.Request) (interface{}, error) { - args := new(SubmitWorkArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - return self.xeth.RemoteMining().SubmitWork(args.Nonce, common.HexToHash(args.Digest), common.HexToHash(args.Header)), nil -} - -func (self *ethApi) SubmitHashrate(req *shared.Request) (interface{}, error) { - args := new(SubmitHashRateArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return false, shared.NewDecodeParamError(err.Error()) - } - self.xeth.RemoteMining().SubmitHashrate(common.HexToHash(args.Id), args.Rate) - return true, nil -} - -func (self *ethApi) Resend(req *shared.Request) (interface{}, error) { - args := new(ResendArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - from := common.HexToAddress(args.Tx.From) - - pending := self.ethereum.TxPool().GetTransactions() - for _, p := range pending { - if pFrom, err := p.From(); err == nil && pFrom == from && p.SigHash() == args.Tx.tx.SigHash() { - self.ethereum.TxPool().RemoveTx(common.HexToHash(args.Tx.Hash)) - return self.xeth.Transact(args.Tx.From, args.Tx.To, args.Tx.Nonce, args.Tx.Value, args.GasLimit, args.GasPrice, args.Tx.Data) - } - } - - return nil, fmt.Errorf("Transaction %s not found", args.Tx.Hash) -} - -func (self *ethApi) PendingTransactions(req *shared.Request) (interface{}, error) { - txs := self.ethereum.TxPool().GetTransactions() - - // grab the accounts from the account manager. This will help with determining which - // transactions should be returned. - accounts, err := self.ethereum.AccountManager().Accounts() - if err != nil { - return nil, err - } - - // Add the accouns to a new set - accountSet := set.New() - for _, account := range accounts { - accountSet.Add(account.Address) - } - - var ltxs []*tx - for _, tx := range txs { - if from, _ := tx.From(); accountSet.Has(from) { - ltxs = append(ltxs, newTx(tx)) - } - } - - return ltxs, nil -} - -func (self *ethApi) GetTransactionReceipt(req *shared.Request) (interface{}, error) { - args := new(HashArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - txhash := common.BytesToHash(common.FromHex(args.Hash)) - tx, bhash, bnum, txi := self.xeth.EthTransactionByHash(args.Hash) - rec := self.xeth.GetTxReceipt(txhash) - // We could have an error of "not found". Should disambiguate - // if err != nil { - // return err, nil - // } - if rec != nil && tx != nil { - v := NewReceiptRes(rec) - v.BlockHash = newHexData(bhash) - v.BlockNumber = newHexNum(bnum) - v.TransactionIndex = newHexNum(txi) - return v, nil - } - - return nil, nil -} diff --git a/rpc/api/eth_args.go b/rpc/api/eth_args.go deleted file mode 100644 index ed3d761f1..000000000 --- a/rpc/api/eth_args.go +++ /dev/null @@ -1,1104 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - "fmt" - "math/big" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -const ( - defaultLogLimit = 100 - defaultLogOffset = 0 -) - -type GetBalanceArgs struct { - Address string - BlockNumber int64 -} - -func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - addstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("address", "not a string") - } - args.Address = addstr - - if len(obj) > 1 { - if err := blockHeight(obj[1], &args.BlockNumber); err != nil { - return err - } - } else { - args.BlockNumber = -1 - } - - return nil -} - -type GetStorageArgs struct { - Address string - BlockNumber int64 -} - -func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - addstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("address", "not a string") - } - args.Address = addstr - - if len(obj) > 1 { - if err := blockHeight(obj[1], &args.BlockNumber); err != nil { - return err - } - } else { - args.BlockNumber = -1 - } - - return nil -} - -type GetStorageAtArgs struct { - Address string - BlockNumber int64 - Key string -} - -func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - addstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("address", "not a string") - } - args.Address = addstr - - keystr, ok := obj[1].(string) - if !ok { - return shared.NewInvalidTypeError("key", "not a string") - } - args.Key = keystr - - if len(obj) > 2 { - if err := blockHeight(obj[2], &args.BlockNumber); err != nil { - return err - } - } else { - args.BlockNumber = -1 - } - - return nil -} - -type GetTxCountArgs struct { - Address string - BlockNumber int64 -} - -func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - addstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("address", "not a string") - } - args.Address = addstr - - if len(obj) > 1 { - if err := blockHeight(obj[1], &args.BlockNumber); err != nil { - return err - } - } else { - args.BlockNumber = -1 - } - - return nil -} - -type SubmitHashRateArgs struct { - Id string - Rate uint64 -} - -func (args *SubmitHashRateArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - arg0, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("hash", "not a string") - } - args.Id = arg0 - - arg1, ok := obj[1].(string) - if !ok { - return shared.NewInvalidTypeError("rate", "not a string") - } - - args.Rate = common.String2Big(arg1).Uint64() - - return nil -} - -type HashArgs struct { - Hash string -} - -func (args *HashArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - arg0, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("hash", "not a string") - } - args.Hash = arg0 - - return nil -} - -type BlockNumArg struct { - BlockNumber int64 -} - -func (args *BlockNumArg) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - if err := blockHeight(obj[0], &args.BlockNumber); err != nil { - return err - } - - return nil -} - -type GetDataArgs struct { - Address string - BlockNumber int64 -} - -func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - addstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("address", "not a string") - } - args.Address = addstr - - if len(obj) > 1 { - if err := blockHeight(obj[1], &args.BlockNumber); err != nil { - return err - } - } else { - args.BlockNumber = -1 - } - - return nil -} - -type NewDataArgs struct { - Data string -} - -func (args *NewDataArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - // Check for sufficient params - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - data, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("data", "not a string") - } - args.Data = data - - if len(args.Data) == 0 { - return shared.NewValidationError("data", "is required") - } - - return nil -} - -type NewSigArgs struct { - From string - Data string -} - -func (args *NewSigArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - // Check for sufficient params - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - from, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("from", "not a string") - } - args.From = from - - if len(args.From) == 0 { - return shared.NewValidationError("from", "is required") - } - - data, ok := obj[1].(string) - if !ok { - return shared.NewInvalidTypeError("data", "not a string") - } - args.Data = data - - if len(args.Data) == 0 { - return shared.NewValidationError("data", "is required") - } - - return nil -} - -type NewTxArgs struct { - From string - To string - Nonce *big.Int - Value *big.Int - Gas *big.Int - GasPrice *big.Int - Data string - - BlockNumber int64 -} - -func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) { - var obj []json.RawMessage - var ext struct { - From string - To string - Nonce interface{} - Value interface{} - Gas interface{} - GasPrice interface{} - Data string - } - - // Decode byte slice to array of RawMessages - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - // Check for sufficient params - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - // Decode 0th RawMessage to temporary struct - if err := json.Unmarshal(obj[0], &ext); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(ext.From) == 0 { - return shared.NewValidationError("from", "is required") - } - - args.From = ext.From - args.To = ext.To - args.Data = ext.Data - - var num *big.Int - if ext.Nonce != nil { - num, err = numString(ext.Nonce) - if err != nil { - return err - } - } - args.Nonce = num - - if ext.Value == nil { - num = big.NewInt(0) - } else { - num, err = numString(ext.Value) - if err != nil { - return err - } - } - args.Value = num - - num = nil - if ext.Gas != nil { - if num, err = numString(ext.Gas); err != nil { - return err - } - } - args.Gas = num - - num = nil - if ext.GasPrice != nil { - if num, err = numString(ext.GasPrice); err != nil { - return err - } - } - args.GasPrice = num - - // Check for optional BlockNumber param - if len(obj) > 1 { - if err := blockHeightFromJson(obj[1], &args.BlockNumber); err != nil { - return err - } - } else { - args.BlockNumber = -1 - } - - return nil -} - -type SourceArgs struct { - Source string -} - -func (args *SourceArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - arg0, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("source code", "not a string") - } - args.Source = arg0 - - return nil -} - -type CallArgs struct { - From string - To string - Value *big.Int - Gas *big.Int - GasPrice *big.Int - Data string - - BlockNumber int64 -} - -func (args *CallArgs) UnmarshalJSON(b []byte) (err error) { - var obj []json.RawMessage - var ext struct { - From string - To string - Value interface{} - Gas interface{} - GasPrice interface{} - Data string - } - - // Decode byte slice to array of RawMessages - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - // Check for sufficient params - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - // Decode 0th RawMessage to temporary struct - if err := json.Unmarshal(obj[0], &ext); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - args.From = ext.From - args.To = ext.To - - var num *big.Int - if ext.Value == nil { - num = big.NewInt(0) - } else { - if num, err = numString(ext.Value); err != nil { - return err - } - } - args.Value = num - - if ext.Gas != nil { - if num, err = numString(ext.Gas); err != nil { - return err - } - } else { - num = nil - } - args.Gas = num - - if ext.GasPrice != nil { - if num, err = numString(ext.GasPrice); err != nil { - return err - } - } else { - num = nil - } - args.GasPrice = num - - args.Data = ext.Data - - // Check for optional BlockNumber param - if len(obj) > 1 { - if err := blockHeightFromJson(obj[1], &args.BlockNumber); err != nil { - return err - } - } else { - args.BlockNumber = -1 - } - - return nil -} - -type HashIndexArgs struct { - Hash string - Index int64 -} - -func (args *HashIndexArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - arg0, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("hash", "not a string") - } - args.Hash = arg0 - - arg1, ok := obj[1].(string) - if !ok { - return shared.NewInvalidTypeError("index", "not a string") - } - args.Index = common.Big(arg1).Int64() - - return nil -} - -type BlockNumIndexArgs struct { - BlockNumber int64 - Index int64 -} - -func (args *BlockNumIndexArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - if err := blockHeight(obj[0], &args.BlockNumber); err != nil { - return err - } - - var arg1 *big.Int - if arg1, err = numString(obj[1]); err != nil { - return err - } - args.Index = arg1.Int64() - - return nil -} - -type GetBlockByHashArgs struct { - BlockHash string - IncludeTxs bool -} - -func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - argstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("blockHash", "not a string") - } - args.BlockHash = argstr - - args.IncludeTxs = obj[1].(bool) - - if inclTx, ok := obj[1].(bool); ok { - args.IncludeTxs = inclTx - return nil - } - - return shared.NewInvalidTypeError("includeTxs", "not a bool") -} - -type GetBlockByNumberArgs struct { - BlockNumber int64 - IncludeTxs bool -} - -func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 2 { - return shared.NewInsufficientParamsError(len(obj), 2) - } - - if err := blockHeight(obj[0], &args.BlockNumber); err != nil { - return err - } - - if inclTx, ok := obj[1].(bool); ok { - args.IncludeTxs = inclTx - return nil - } - - return shared.NewInvalidTypeError("includeTxs", "not a bool") -} - -type BlockFilterArgs struct { - Earliest int64 - Latest int64 - Address []string - Topics [][]string - Skip int - Max int -} - -func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) { - var obj []struct { - FromBlock interface{} `json:"fromBlock"` - ToBlock interface{} `json:"toBlock"` - Limit interface{} `json:"limit"` - Offset interface{} `json:"offset"` - Address interface{} `json:"address"` - Topics interface{} `json:"topics"` - } - - if err = json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - // args.Earliest, err = toNumber(obj[0].ToBlock) - // if err != nil { - // return shared.NewDecodeParamError(fmt.Sprintf("FromBlock %v", err)) - // } - // args.Latest, err = toNumber(obj[0].FromBlock) - // if err != nil { - // return shared.NewDecodeParamError(fmt.Sprintf("ToBlock %v", err)) - - var num int64 - var numBig *big.Int - - // if blank then latest - if obj[0].FromBlock == nil { - num = -1 - } else { - if err := blockHeight(obj[0].FromBlock, &num); err != nil { - return err - } - } - // if -2 or other "silly" number, use latest - if num < 0 { - args.Earliest = -1 //latest block - } else { - args.Earliest = num - } - - // if blank than latest - if obj[0].ToBlock == nil { - num = -1 - } else { - if err := blockHeight(obj[0].ToBlock, &num); err != nil { - return err - } - } - - if num == -2 { - return fmt.Errorf("\"pending\" is unsupported") - } else if num < -2 { - return fmt.Errorf("Invalid to block number") - } - - args.Latest = num - - if obj[0].Limit == nil { - numBig = big.NewInt(defaultLogLimit) - } else { - if numBig, err = numString(obj[0].Limit); err != nil { - return err - } - } - args.Max = int(numBig.Int64()) - - if obj[0].Offset == nil { - numBig = big.NewInt(defaultLogOffset) - } else { - if numBig, err = numString(obj[0].Offset); err != nil { - return err - } - } - args.Skip = int(numBig.Int64()) - - if obj[0].Address != nil { - marg, ok := obj[0].Address.([]interface{}) - if ok { - v := make([]string, len(marg)) - for i, arg := range marg { - argstr, ok := arg.(string) - if !ok { - return shared.NewInvalidTypeError(fmt.Sprintf("address[%d]", i), "is not a string") - } - v[i] = argstr - } - args.Address = v - } else { - argstr, ok := obj[0].Address.(string) - if ok { - v := make([]string, 1) - v[0] = argstr - args.Address = v - } else { - return shared.NewInvalidTypeError("address", "is not a string or array") - } - } - } - - if obj[0].Topics != nil { - other, ok := obj[0].Topics.([]interface{}) - if ok { - topicdbl := make([][]string, len(other)) - for i, iv := range other { - if argstr, ok := iv.(string); ok { - // Found a string, push into first element of array - topicsgl := make([]string, 1) - topicsgl[0] = argstr - topicdbl[i] = topicsgl - } else if argarray, ok := iv.([]interface{}); ok { - // Found an array of other - topicdbl[i] = make([]string, len(argarray)) - for j, jv := range argarray { - if v, ok := jv.(string); ok { - topicdbl[i][j] = v - } else if jv == nil { - topicdbl[i][j] = "" - } else { - return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d][%d]", i, j), "is not a string") - } - } - } else if iv == nil { - topicdbl[i] = []string{""} - } else { - return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d]", i), "not a string or array") - } - } - args.Topics = topicdbl - return nil - } else { - return shared.NewInvalidTypeError("topic", "is not a string or array") - } - } - - return nil -} - -type FilterIdArgs struct { - Id int -} - -func (args *FilterIdArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - var num *big.Int - if num, err = numString(obj[0]); err != nil { - return err - } - args.Id = int(num.Int64()) - - return nil -} - -type LogRes struct { - Address *hexdata `json:"address"` - Topics []*hexdata `json:"topics"` - Data *hexdata `json:"data"` - BlockNumber *hexnum `json:"blockNumber"` - LogIndex *hexnum `json:"logIndex"` - BlockHash *hexdata `json:"blockHash"` - TransactionHash *hexdata `json:"transactionHash"` - TransactionIndex *hexnum `json:"transactionIndex"` -} - -func NewLogRes(log *vm.Log) LogRes { - var l LogRes - l.Topics = make([]*hexdata, len(log.Topics)) - for j, topic := range log.Topics { - l.Topics[j] = newHexData(topic) - } - l.Address = newHexData(log.Address) - l.Data = newHexData(log.Data) - l.BlockNumber = newHexNum(log.BlockNumber) - l.LogIndex = newHexNum(log.Index) - l.TransactionHash = newHexData(log.TxHash) - l.TransactionIndex = newHexNum(log.TxIndex) - l.BlockHash = newHexData(log.BlockHash) - - return l -} - -func NewLogsRes(logs vm.Logs) (ls []LogRes) { - ls = make([]LogRes, len(logs)) - - for i, log := range logs { - ls[i] = NewLogRes(log) - } - - return -} - -func NewHashesRes(hs []common.Hash) []string { - hashes := make([]string, len(hs)) - - for i, hash := range hs { - hashes[i] = hash.Hex() - } - - return hashes -} - -type SubmitWorkArgs struct { - Nonce uint64 - Header string - Digest string -} - -func (args *SubmitWorkArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err = json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 3 { - return shared.NewInsufficientParamsError(len(obj), 3) - } - - var objstr string - var ok bool - if objstr, ok = obj[0].(string); !ok { - return shared.NewInvalidTypeError("nonce", "not a string") - } - - args.Nonce = common.String2Big(objstr).Uint64() - if objstr, ok = obj[1].(string); !ok { - return shared.NewInvalidTypeError("header", "not a string") - } - - args.Header = objstr - - if objstr, ok = obj[2].(string); !ok { - return shared.NewInvalidTypeError("digest", "not a string") - } - - args.Digest = objstr - - return nil -} - -type tx struct { - tx *types.Transaction - - To string `json:"to"` - From string `json:"from"` - Nonce string `json:"nonce"` - Value string `json:"value"` - Data string `json:"data"` - GasLimit string `json:"gas"` - GasPrice string `json:"gasPrice"` - Hash string `json:"hash"` -} - -func newTx(t *types.Transaction) *tx { - from, _ := t.From() - var to string - if t := t.To(); t != nil { - to = t.Hex() - } - - return &tx{ - tx: t, - To: to, - From: from.Hex(), - Value: t.Value().String(), - Nonce: strconv.Itoa(int(t.Nonce())), - Data: "0x" + common.Bytes2Hex(t.Data()), - GasLimit: t.Gas().String(), - GasPrice: t.GasPrice().String(), - Hash: t.Hash().Hex(), - } -} - -type ResendArgs struct { - Tx *tx - GasPrice string - GasLimit string -} - -func (tx *tx) UnmarshalJSON(b []byte) (err error) { - var fields map[string]interface{} - if err := json.Unmarshal(b, &fields); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - var ( - nonce uint64 - to common.Address - amount = new(big.Int).Set(common.Big0) - gasLimit = new(big.Int).Set(common.Big0) - gasPrice = new(big.Int).Set(common.Big0) - data []byte - contractCreation = true - ) - - if val, found := fields["Hash"]; found { - if hashVal, ok := val.(string); ok { - tx.Hash = hashVal - } - } - - if val, found := fields["To"]; found { - if strVal, ok := val.(string); ok && len(strVal) > 0 { - tx.To = strVal - to = common.HexToAddress(strVal) - contractCreation = false - } - } - - if val, found := fields["From"]; found { - if strVal, ok := val.(string); ok { - tx.From = strVal - } - } - - if val, found := fields["Nonce"]; found { - if strVal, ok := val.(string); ok { - tx.Nonce = strVal - if nonce, err = strconv.ParseUint(strVal, 10, 64); err != nil { - return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.Nonce - %v", err)) - } - } - } else { - return shared.NewDecodeParamError("tx.Nonce not found") - } - - var parseOk bool - if val, found := fields["Value"]; found { - if strVal, ok := val.(string); ok { - tx.Value = strVal - if _, parseOk = amount.SetString(strVal, 0); !parseOk { - return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.Amount - %v", err)) - } - } - } - - if val, found := fields["Data"]; found { - if strVal, ok := val.(string); ok { - tx.Data = strVal - if strings.HasPrefix(strVal, "0x") { - data = common.Hex2Bytes(strVal[2:]) - } else { - data = common.Hex2Bytes(strVal) - } - } - } - - if val, found := fields["GasLimit"]; found { - if strVal, ok := val.(string); ok { - tx.GasLimit = strVal - if _, parseOk = gasLimit.SetString(strVal, 0); !parseOk { - return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.GasLimit - %v", err)) - } - } - } - - if val, found := fields["GasPrice"]; found { - if strVal, ok := val.(string); ok { - tx.GasPrice = strVal - if _, parseOk = gasPrice.SetString(strVal, 0); !parseOk { - return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.GasPrice - %v", err)) - } - } - } - - if contractCreation { - tx.tx = types.NewContractCreation(nonce, amount, gasLimit, gasPrice, data) - } else { - tx.tx = types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data) - } - - return nil -} - -func (args *ResendArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err = json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - data, err := json.Marshal(obj[0]) - if err != nil { - return shared.NewDecodeParamError("Unable to parse transaction object") - } - - trans := new(tx) - err = json.Unmarshal(data, trans) - if err != nil { - return shared.NewDecodeParamError("Unable to parse transaction object") - } - - if trans == nil || trans.tx == nil { - return shared.NewDecodeParamError("Unable to parse transaction object") - } - - gasLimit, gasPrice := trans.GasLimit, trans.GasPrice - - if len(obj) > 1 && obj[1] != nil { - if gp, ok := obj[1].(string); ok { - gasPrice = gp - } else { - return shared.NewInvalidTypeError("gasPrice", "not a string") - } - } - if len(obj) > 2 && obj[2] != nil { - if gl, ok := obj[2].(string); ok { - gasLimit = gl - } else { - return shared.NewInvalidTypeError("gasLimit", "not a string") - } - } - - args.Tx = trans - args.GasPrice = gasPrice - args.GasLimit = gasLimit - - return nil -} diff --git a/rpc/api/eth_js.go b/rpc/api/eth_js.go deleted file mode 100644 index dfc104ad8..000000000 --- a/rpc/api/eth_js.go +++ /dev/null @@ -1,66 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -// JS api provided by web3.js -// eth_sign not standard - -const Eth_JS = ` -web3._extend({ - property: 'eth', - methods: - [ - new web3._extend.Method({ - name: 'sign', - call: 'eth_sign', - params: 2, - inputFormatter: [web3._extend.utils.toAddress, null] - }), - new web3._extend.Method({ - name: 'resend', - call: 'eth_resend', - params: 3, - inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal] - }), - new web3._extend.Method({ - name: 'getNatSpec', - call: 'eth_getNatSpec', - params: 1, - inputFormatter: [web3._extend.formatters.inputTransactionFormatter] - }), - new web3._extend.Method({ - name: 'signTransaction', - call: 'eth_signTransaction', - params: 1, - inputFormatter: [web3._extend.formatters.inputTransactionFormatter] - }), - new web3._extend.Method({ - name: 'submitTransaction', - call: 'eth_submitTransaction', - params: 1, - inputFormatter: [web3._extend.formatters.inputTransactionFormatter] - }) - ], - properties: - [ - new web3._extend.Property({ - name: 'pendingTransactions', - getter: 'eth_pendingTransactions' - }) - ] -}); -` diff --git a/rpc/api/mergedapi.go b/rpc/api/mergedapi.go deleted file mode 100644 index 92e1e2bb7..000000000 --- a/rpc/api/mergedapi.go +++ /dev/null @@ -1,88 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -const ( - MergedApiVersion = "1.0" -) - -// combines multiple API's -type MergedApi struct { - apis map[string]string - methods map[string]shared.EthereumApi -} - -// create new merged api instance -func newMergedApi(apis ...shared.EthereumApi) *MergedApi { - mergedApi := new(MergedApi) - mergedApi.apis = make(map[string]string, len(apis)) - mergedApi.methods = make(map[string]shared.EthereumApi) - - for _, api := range apis { - if api != nil { - mergedApi.apis[api.Name()] = api.ApiVersion() - for _, method := range api.Methods() { - mergedApi.methods[method] = api - } - } - } - return mergedApi -} - -// Supported RPC methods -func (self *MergedApi) Methods() []string { - all := make([]string, len(self.methods)) - for method, _ := range self.methods { - all = append(all, method) - } - return all -} - -// Call the correct API's Execute method for the given request -func (self *MergedApi) Execute(req *shared.Request) (interface{}, error) { - glog.V(logger.Detail).Infof("%s %s", req.Method, req.Params) - - if res, _ := self.handle(req); res != nil { - return res, nil - } - if api, found := self.methods[req.Method]; found { - return api.Execute(req) - } - return nil, shared.NewNotImplementedError(req.Method) -} - -func (self *MergedApi) Name() string { - return shared.MergedApiName -} - -func (self *MergedApi) ApiVersion() string { - return MergedApiVersion -} - -func (self *MergedApi) handle(req *shared.Request) (interface{}, error) { - if req.Method == "modules" { // provided API's - return self.apis, nil - } - - return nil, nil -} diff --git a/rpc/api/miner.go b/rpc/api/miner.go deleted file mode 100644 index e07855dd2..000000000 --- a/rpc/api/miner.go +++ /dev/null @@ -1,177 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "github.com/ethereum/ethash" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -const ( - MinerApiVersion = "1.0" -) - -var ( - // mapping between methods and handlers - MinerMapping = map[string]minerhandler{ - "miner_hashrate": (*minerApi).Hashrate, - "miner_makeDAG": (*minerApi).MakeDAG, - "miner_setExtra": (*minerApi).SetExtra, - "miner_setGasPrice": (*minerApi).SetGasPrice, - "miner_setEtherbase": (*minerApi).SetEtherbase, - "miner_startAutoDAG": (*minerApi).StartAutoDAG, - "miner_start": (*minerApi).StartMiner, - "miner_stopAutoDAG": (*minerApi).StopAutoDAG, - "miner_stop": (*minerApi).StopMiner, - } -) - -// miner callback handler -type minerhandler func(*minerApi, *shared.Request) (interface{}, error) - -// miner api provider -type minerApi struct { - ethereum *eth.Ethereum - methods map[string]minerhandler - codec codec.ApiCoder -} - -// create a new miner api instance -func NewMinerApi(ethereum *eth.Ethereum, coder codec.Codec) *minerApi { - return &minerApi{ - ethereum: ethereum, - methods: MinerMapping, - codec: coder.New(nil), - } -} - -// Execute given request -func (self *minerApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, &shared.NotImplementedError{req.Method} -} - -// collection with supported methods -func (self *minerApi) Methods() []string { - methods := make([]string, len(self.methods)) - i := 0 - for k := range self.methods { - methods[i] = k - i++ - } - return methods -} - -func (self *minerApi) Name() string { - return shared.MinerApiName -} - -func (self *minerApi) ApiVersion() string { - return MinerApiVersion -} - -func (self *minerApi) StartMiner(req *shared.Request) (interface{}, error) { - args := new(StartMinerArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - if args.Threads == -1 { // (not specified by user, use default) - args.Threads = self.ethereum.MinerThreads - } - - self.ethereum.StartAutoDAG() - err := self.ethereum.StartMining(args.Threads, "") - if err == nil { - return true, nil - } - - return false, err -} - -func (self *minerApi) StopMiner(req *shared.Request) (interface{}, error) { - self.ethereum.StopMining() - return true, nil -} - -func (self *minerApi) Hashrate(req *shared.Request) (interface{}, error) { - return self.ethereum.Miner().HashRate(), nil -} - -func (self *minerApi) SetExtra(req *shared.Request) (interface{}, error) { - args := new(SetExtraArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - - if err := self.ethereum.Miner().SetExtra([]byte(args.Data)); err != nil { - return false, err - } - - return true, nil -} - -func (self *minerApi) SetGasPrice(req *shared.Request) (interface{}, error) { - args := new(GasPriceArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return false, err - } - - self.ethereum.Miner().SetGasPrice(common.String2Big(args.Price)) - return true, nil -} - -func (self *minerApi) SetEtherbase(req *shared.Request) (interface{}, error) { - args := new(SetEtherbaseArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return false, err - } - self.ethereum.SetEtherbase(args.Etherbase) - return nil, nil -} - -func (self *minerApi) StartAutoDAG(req *shared.Request) (interface{}, error) { - self.ethereum.StartAutoDAG() - return true, nil -} - -func (self *minerApi) StopAutoDAG(req *shared.Request) (interface{}, error) { - self.ethereum.StopAutoDAG() - return true, nil -} - -func (self *minerApi) MakeDAG(req *shared.Request) (interface{}, error) { - args := new(MakeDAGArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - - if args.BlockNumber < 0 { - return false, shared.NewValidationError("BlockNumber", "BlockNumber must be positive") - } - - err := ethash.MakeDAG(uint64(args.BlockNumber), "") - if err == nil { - return true, nil - } - return false, err -} diff --git a/rpc/api/miner_args.go b/rpc/api/miner_args.go deleted file mode 100644 index 5ceb244fe..000000000 --- a/rpc/api/miner_args.go +++ /dev/null @@ -1,142 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type StartMinerArgs struct { - Threads int -} - -func (args *StartMinerArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) == 0 || obj[0] == nil { - args.Threads = -1 - return nil - } - - var num *big.Int - if num, err = numString(obj[0]); err != nil { - return err - } - args.Threads = int(num.Int64()) - return nil -} - -type SetExtraArgs struct { - Data string -} - -func (args *SetExtraArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - extrastr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("Price", "not a string") - } - args.Data = extrastr - - return nil -} - -type GasPriceArgs struct { - Price string -} - -func (args *GasPriceArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - if pricestr, ok := obj[0].(string); ok { - args.Price = pricestr - return nil - } - - return shared.NewInvalidTypeError("Price", "not a string") -} - -type SetEtherbaseArgs struct { - Etherbase common.Address -} - -func (args *SetEtherbaseArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - if addr, ok := obj[0].(string); ok { - args.Etherbase = common.HexToAddress(addr) - if (args.Etherbase == common.Address{}) { - return shared.NewInvalidTypeError("Etherbase", "not a valid address") - } - return nil - } - - return shared.NewInvalidTypeError("Etherbase", "not a string") -} - -type MakeDAGArgs struct { - BlockNumber int64 -} - -func (args *MakeDAGArgs) UnmarshalJSON(b []byte) (err error) { - args.BlockNumber = -1 - var obj []interface{} - - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - if err := blockHeight(obj[0], &args.BlockNumber); err != nil { - return err - } - - return nil -} diff --git a/rpc/api/miner_js.go b/rpc/api/miner_js.go deleted file mode 100644 index 0998a9f41..000000000 --- a/rpc/api/miner_js.go +++ /dev/null @@ -1,83 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const Miner_JS = ` -web3._extend({ - property: 'miner', - methods: - [ - new web3._extend.Method({ - name: 'start', - call: 'miner_start', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'stop', - call: 'miner_stop', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'setEtherbase', - call: 'miner_setEtherbase', - params: 1, - inputFormatter: [web3._extend.formatters.formatInputInt], - outputFormatter: web3._extend.formatters.formatOutputBool - }), - new web3._extend.Method({ - name: 'setExtra', - call: 'miner_setExtra', - params: 1, - inputFormatter: [null] - }), - new web3._extend.Method({ - name: 'setGasPrice', - call: 'miner_setGasPrice', - params: 1, - inputFormatter: [web3._extend.utils.fromDecial] - }), - new web3._extend.Method({ - name: 'startAutoDAG', - call: 'miner_startAutoDAG', - params: 0, - inputFormatter: [] - }), - new web3._extend.Method({ - name: 'stopAutoDAG', - call: 'miner_stopAutoDAG', - params: 0, - inputFormatter: [] - }), - new web3._extend.Method({ - name: 'makeDAG', - call: 'miner_makeDAG', - params: 1, - inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter] - }) - ], - properties: - [ - new web3._extend.Property({ - name: 'hashrate', - getter: 'miner_hashrate', - outputFormatter: web3._extend.utils.toDecimal - }) - ] -}); -` diff --git a/rpc/api/net.go b/rpc/api/net.go deleted file mode 100644 index 9c6369615..000000000 --- a/rpc/api/net.go +++ /dev/null @@ -1,99 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" -) - -const ( - NetApiVersion = "1.0" -) - -var ( - // mapping between methods and handlers - netMapping = map[string]nethandler{ - "net_peerCount": (*netApi).PeerCount, - "net_listening": (*netApi).IsListening, - "net_version": (*netApi).Version, - } -) - -// net callback handler -type nethandler func(*netApi, *shared.Request) (interface{}, error) - -// net api provider -type netApi struct { - xeth *xeth.XEth - ethereum *eth.Ethereum - methods map[string]nethandler - codec codec.ApiCoder -} - -// create a new net api instance -func NewNetApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *netApi { - return &netApi{ - xeth: xeth, - ethereum: eth, - methods: netMapping, - codec: coder.New(nil), - } -} - -// collection with supported methods -func (self *netApi) 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 *netApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, shared.NewNotImplementedError(req.Method) -} - -func (self *netApi) Name() string { - return shared.NetApiName -} - -func (self *netApi) ApiVersion() string { - return NetApiVersion -} - -// Number of connected peers -func (self *netApi) PeerCount(req *shared.Request) (interface{}, error) { - return newHexNum(self.xeth.PeerCount()), nil -} - -func (self *netApi) IsListening(req *shared.Request) (interface{}, error) { - return self.xeth.IsListening(), nil -} - -func (self *netApi) Version(req *shared.Request) (interface{}, error) { - return self.xeth.NetworkVersion(), nil -} diff --git a/rpc/api/net_js.go b/rpc/api/net_js.go deleted file mode 100644 index 2ee1f0041..000000000 --- a/rpc/api/net_js.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const Net_JS = ` -web3._extend({ - property: 'net', - methods: - [ - new web3._extend.Method({ - name: 'addPeer', - call: 'net_addPeer', - params: 1, - inputFormatter: [null] - }) - ], - properties: - [ - new web3._extend.Property({ - name: 'version', - getter: 'net_version' - }) - ] -}); -` diff --git a/rpc/api/parsing.go b/rpc/api/parsing.go deleted file mode 100644 index 7667616ff..000000000 --- a/rpc/api/parsing.go +++ /dev/null @@ -1,522 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "bytes" - "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"` - ReceiptRoot *hexdata `json:"receiptRoot"` - 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"` - ReceiptRoot *hexdata `json:"receiptRoot"` - 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.ReceiptRoot = b.ReceiptRoot - 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"` - ReceiptRoot *hexdata `json:"receiptRoot"` - 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.ReceiptRoot = b.ReceiptRoot - 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, td *big.Int, 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.UncleHash()) - res.LogsBloom = newHexData(block.Bloom()) - res.TransactionRoot = newHexData(block.TxHash()) - res.StateRoot = newHexData(block.Root()) - res.ReceiptRoot = newHexData(block.ReceiptHash()) - res.Miner = newHexData(block.Coinbase()) - res.Difficulty = newHexNum(block.Difficulty()) - res.TotalDifficulty = newHexNum(td) - res.Size = newHexNum(block.Size().Int64()) - res.ExtraData = newHexData(block.Extra()) - res.GasLimit = newHexNum(block.GasLimit()) - res.GasUsed = newHexNum(block.GasUsed()) - res.UnixTimestamp = newHexNum(block.Time()) - - txs := block.Transactions() - res.Transactions = make([]*TransactionRes, len(txs)) - for i, tx := range txs { - res.Transactions[i] = NewTransactionRes(tx) - res.Transactions[i].BlockHash = res.BlockHash - res.Transactions[i].BlockNumber = res.BlockNumber - res.Transactions[i].TxIndex = newHexNum(i) - } - - uncles := block.Uncles() - res.Uncles = make([]*UncleRes, len(uncles)) - for i, uncle := range 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"` -// } - -type ReceiptRes struct { - TransactionHash *hexdata `json:"transactionHash"` - TransactionIndex *hexnum `json:"transactionIndex"` - BlockNumber *hexnum `json:"blockNumber"` - BlockHash *hexdata `json:"blockHash"` - CumulativeGasUsed *hexnum `json:"cumulativeGasUsed"` - GasUsed *hexnum `json:"gasUsed"` - ContractAddress *hexdata `json:"contractAddress"` - Logs *[]interface{} `json:"logs"` -} - -func NewReceiptRes(rec *types.Receipt) *ReceiptRes { - if rec == nil { - return nil - } - - var v = new(ReceiptRes) - v.TransactionHash = newHexData(rec.TxHash) - if rec.GasUsed != nil { - v.GasUsed = newHexNum(rec.GasUsed.Bytes()) - } - v.CumulativeGasUsed = newHexNum(rec.CumulativeGasUsed) - - // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation - if bytes.Compare(rec.ContractAddress.Bytes(), bytes.Repeat([]byte{0}, 20)) != 0 { - v.ContractAddress = newHexData(rec.ContractAddress) - } - - logs := make([]interface{}, len(rec.Logs)) - for i, log := range rec.Logs { - logs[i] = NewLogRes(log) - } - v.Logs = &logs - - return v -} - -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) -} diff --git a/rpc/api/personal.go b/rpc/api/personal.go deleted file mode 100644 index 4f347c610..000000000 --- a/rpc/api/personal.go +++ /dev/null @@ -1,139 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "fmt" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" -) - -const ( - PersonalApiVersion = "1.0" -) - -var ( - // mapping between methods and handlers - personalMapping = map[string]personalhandler{ - "personal_listAccounts": (*personalApi).ListAccounts, - "personal_newAccount": (*personalApi).NewAccount, - "personal_unlockAccount": (*personalApi).UnlockAccount, - } -) - -// net callback handler -type personalhandler func(*personalApi, *shared.Request) (interface{}, error) - -// net api provider -type personalApi struct { - xeth *xeth.XEth - ethereum *eth.Ethereum - methods map[string]personalhandler - codec codec.ApiCoder -} - -// create a new net api instance -func NewPersonalApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *personalApi { - return &personalApi{ - xeth: xeth, - ethereum: eth, - methods: personalMapping, - codec: coder.New(nil), - } -} - -// collection with supported methods -func (self *personalApi) 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 *personalApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, shared.NewNotImplementedError(req.Method) -} - -func (self *personalApi) Name() string { - return shared.PersonalApiName -} - -func (self *personalApi) ApiVersion() string { - return PersonalApiVersion -} - -func (self *personalApi) ListAccounts(req *shared.Request) (interface{}, error) { - return self.xeth.Accounts(), nil -} - -func (self *personalApi) NewAccount(req *shared.Request) (interface{}, error) { - args := new(NewAccountArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - var passwd string - if args.Passphrase == nil { - fe := self.xeth.Frontend() - if fe == nil { - return false, fmt.Errorf("unable to create account: unable to interact with user") - } - var ok bool - passwd, ok = fe.AskPassword() - if !ok { - return false, fmt.Errorf("unable to create account: no password given") - } - } else { - passwd = *args.Passphrase - } - am := self.ethereum.AccountManager() - acc, err := am.NewAccount(passwd) - return acc.Address.Hex(), err -} - -func (self *personalApi) UnlockAccount(req *shared.Request) (interface{}, error) { - args := new(UnlockAccountArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, shared.NewDecodeParamError(err.Error()) - } - - if args.Passphrase == nil { - fe := self.xeth.Frontend() - if fe == nil { - return false, fmt.Errorf("No password provided") - } - return fe.UnlockAccount(common.HexToAddress(args.Address).Bytes()), nil - } - - am := self.ethereum.AccountManager() - addr := common.HexToAddress(args.Address) - - err := am.TimedUnlock(addr, *args.Passphrase, time.Duration(args.Duration)*time.Second) - return err == nil, err -} diff --git a/rpc/api/personal_args.go b/rpc/api/personal_args.go deleted file mode 100644 index 5d215c71d..000000000 --- a/rpc/api/personal_args.go +++ /dev/null @@ -1,85 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type NewAccountArgs struct { - Passphrase *string -} - -func (args *NewAccountArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) >= 1 && obj[0] != nil { - if passphrasestr, ok := obj[0].(string); ok { - args.Passphrase = &passphrasestr - } else { - return shared.NewInvalidTypeError("passphrase", "not a string") - } - } - - return nil -} - -type UnlockAccountArgs struct { - Address string - Passphrase *string - Duration int -} - -func (args *UnlockAccountArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - args.Duration = 0 - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - if addrstr, ok := obj[0].(string); ok { - args.Address = addrstr - } else { - return shared.NewInvalidTypeError("address", "not a string") - } - - if len(obj) >= 2 && obj[1] != nil { - if passphrasestr, ok := obj[1].(string); ok { - args.Passphrase = &passphrasestr - } else { - return shared.NewInvalidTypeError("passphrase", "not a string") - } - } - - if len(obj) >= 3 && obj[2] != nil { - if duration, ok := obj[2].(float64); ok { - args.Duration = int(duration) - } - } - - return nil -} diff --git a/rpc/api/personal_js.go b/rpc/api/personal_js.go deleted file mode 100644 index 84c669af7..000000000 --- a/rpc/api/personal_js.go +++ /dev/null @@ -1,51 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const Personal_JS = ` -web3._extend({ - property: 'personal', - methods: - [ - new web3._extend.Method({ - name: 'newAccount', - call: 'personal_newAccount', - params: 1, - inputFormatter: [null], - outputFormatter: web3._extend.utils.toAddress - }), - new web3._extend.Method({ - name: 'unlockAccount', - call: 'personal_unlockAccount', - params: 3, - inputFormatter: [null, null, null] - }), - new web3._extend.Method({ - name: 'lockAccount', - call: 'personal_lockAccount', - params: 1 - }) - ], - properties: - [ - new web3._extend.Property({ - name: 'listAccounts', - getter: 'personal_listAccounts' - }) - ] -}); -` diff --git a/rpc/api/shh.go b/rpc/api/shh.go deleted file mode 100644 index 60e805605..000000000 --- a/rpc/api/shh.go +++ /dev/null @@ -1,196 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" -) - -const ( - ShhApiVersion = "1.0" -) - -var ( - // mapping between methods and handlers - shhMapping = map[string]shhhandler{ - "shh_version": (*shhApi).Version, - "shh_post": (*shhApi).Post, - "shh_hasIdentity": (*shhApi).HasIdentity, - "shh_newIdentity": (*shhApi).NewIdentity, - "shh_newFilter": (*shhApi).NewFilter, - "shh_uninstallFilter": (*shhApi).UninstallFilter, - "shh_getMessages": (*shhApi).GetMessages, - "shh_getFilterChanges": (*shhApi).GetFilterChanges, - } -) - -func newWhisperOfflineError(method string) error { - return shared.NewNotAvailableError(method, "whisper offline") -} - -// net callback handler -type shhhandler func(*shhApi, *shared.Request) (interface{}, error) - -// shh api provider -type shhApi struct { - xeth *xeth.XEth - ethereum *eth.Ethereum - methods map[string]shhhandler - codec codec.ApiCoder -} - -// create a new whisper api instance -func NewShhApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *shhApi { - return &shhApi{ - xeth: xeth, - ethereum: eth, - methods: shhMapping, - codec: coder.New(nil), - } -} - -// collection with supported methods -func (self *shhApi) 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 *shhApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, shared.NewNotImplementedError(req.Method) -} - -func (self *shhApi) Name() string { - return shared.ShhApiName -} - -func (self *shhApi) ApiVersion() string { - return ShhApiVersion -} - -func (self *shhApi) Version(req *shared.Request) (interface{}, error) { - w := self.xeth.Whisper() - if w == nil { - return nil, newWhisperOfflineError(req.Method) - } - - return w.Version(), nil -} - -func (self *shhApi) Post(req *shared.Request) (interface{}, error) { - w := self.xeth.Whisper() - if w == nil { - return nil, newWhisperOfflineError(req.Method) - } - - args := new(WhisperMessageArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - - err := w.Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl) - if err != nil { - return false, err - } - - return true, nil -} - -func (self *shhApi) HasIdentity(req *shared.Request) (interface{}, error) { - w := self.xeth.Whisper() - if w == nil { - return nil, newWhisperOfflineError(req.Method) - } - - args := new(WhisperIdentityArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - - return w.HasIdentity(args.Identity), nil -} - -func (self *shhApi) NewIdentity(req *shared.Request) (interface{}, error) { - w := self.xeth.Whisper() - if w == nil { - return nil, newWhisperOfflineError(req.Method) - } - - return w.NewIdentity(), nil -} - -func (self *shhApi) NewFilter(req *shared.Request) (interface{}, error) { - args := new(WhisperFilterArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - - id := self.xeth.NewWhisperFilter(args.To, args.From, args.Topics) - return newHexNum(big.NewInt(int64(id)).Bytes()), nil -} - -func (self *shhApi) UninstallFilter(req *shared.Request) (interface{}, error) { - args := new(FilterIdArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - return self.xeth.UninstallWhisperFilter(args.Id), nil -} - -func (self *shhApi) GetFilterChanges(req *shared.Request) (interface{}, error) { - w := self.xeth.Whisper() - if w == nil { - return nil, newWhisperOfflineError(req.Method) - } - - // Retrieve all the new messages arrived since the last request - args := new(FilterIdArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - - return self.xeth.WhisperMessagesChanged(args.Id), nil -} - -func (self *shhApi) GetMessages(req *shared.Request) (interface{}, error) { - w := self.xeth.Whisper() - if w == nil { - return nil, newWhisperOfflineError(req.Method) - } - - // Retrieve all the cached messages matching a specific, existing filter - args := new(FilterIdArgs) - if err := self.codec.Decode(req.Params, &args); err != nil { - return nil, err - } - - return self.xeth.WhisperMessages(args.Id), nil -} diff --git a/rpc/api/shh_args.go b/rpc/api/shh_args.go deleted file mode 100644 index 468a0b98f..000000000 --- a/rpc/api/shh_args.go +++ /dev/null @@ -1,174 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "encoding/json" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type WhisperMessageArgs struct { - Payload string - To string - From string - Topics []string - Priority uint32 - Ttl uint32 -} - -func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) { - var obj []struct { - Payload string - To string - From string - Topics []string - Priority interface{} - Ttl interface{} - } - - if err = json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - args.Payload = obj[0].Payload - args.To = obj[0].To - args.From = obj[0].From - args.Topics = obj[0].Topics - - var num *big.Int - if num, err = numString(obj[0].Priority); err != nil { - return err - } - args.Priority = uint32(num.Int64()) - - if num, err = numString(obj[0].Ttl); err != nil { - return err - } - args.Ttl = uint32(num.Int64()) - - return nil -} - -type WhisperIdentityArgs struct { - Identity string -} - -func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - - argstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("arg0", "not a string") - } - - args.Identity = argstr - - return nil -} - -type WhisperFilterArgs struct { - To string - From string - Topics [][]string -} - -// UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a -// JSON message blob into a WhisperFilterArgs structure. -func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) { - // Unmarshal the JSON message and sanity check - var obj []struct { - To interface{} `json:"to"` - From interface{} `json:"from"` - Topics interface{} `json:"topics"` - } - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) - } - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) - } - // Retrieve the simple data contents of the filter arguments - if obj[0].To == nil { - args.To = "" - } else { - argstr, ok := obj[0].To.(string) - if !ok { - return shared.NewInvalidTypeError("to", "is not a string") - } - args.To = argstr - } - if obj[0].From == nil { - args.From = "" - } else { - argstr, ok := obj[0].From.(string) - if !ok { - return shared.NewInvalidTypeError("from", "is not a string") - } - args.From = argstr - } - // Construct the nested topic array - if obj[0].Topics != nil { - // Make sure we have an actual topic array - list, ok := obj[0].Topics.([]interface{}) - if !ok { - return shared.NewInvalidTypeError("topics", "is not an array") - } - // Iterate over each topic and handle nil, string or array - topics := make([][]string, len(list)) - for idx, field := range list { - switch value := field.(type) { - case nil: - topics[idx] = []string{} - - case string: - topics[idx] = []string{value} - - case []interface{}: - topics[idx] = make([]string, len(value)) - for i, nested := range value { - switch value := nested.(type) { - case nil: - topics[idx][i] = "" - - case string: - topics[idx][i] = value - - default: - return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d][%d]", idx, i), "is not a string") - } - } - default: - return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d]", idx), "not a string or array") - } - } - args.Topics = topics - } - return nil -} diff --git a/rpc/api/shh_js.go b/rpc/api/shh_js.go deleted file mode 100644 index a92ad1644..000000000 --- a/rpc/api/shh_js.go +++ /dev/null @@ -1,34 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const Shh_JS = ` -web3._extend({ - property: 'shh', - methods: - [ - - ], - properties: - [ - new web3._extend.Property({ - name: 'version', - getter: 'shh_version' - }) - ] -}); -` diff --git a/rpc/api/txpool.go b/rpc/api/txpool.go deleted file mode 100644 index 27e40cae5..000000000 --- a/rpc/api/txpool.go +++ /dev/null @@ -1,92 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" -) - -const ( - TxPoolApiVersion = "1.0" -) - -var ( - // mapping between methods and handlers - txpoolMapping = map[string]txpoolhandler{ - "txpool_status": (*txPoolApi).Status, - } -) - -// net callback handler -type txpoolhandler func(*txPoolApi, *shared.Request) (interface{}, error) - -// txpool api provider -type txPoolApi struct { - xeth *xeth.XEth - ethereum *eth.Ethereum - methods map[string]txpoolhandler - codec codec.ApiCoder -} - -// create a new txpool api instance -func NewTxPoolApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *txPoolApi { - return &txPoolApi{ - xeth: xeth, - ethereum: eth, - methods: txpoolMapping, - codec: coder.New(nil), - } -} - -// collection with supported methods -func (self *txPoolApi) 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 *txPoolApi) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, shared.NewNotImplementedError(req.Method) -} - -func (self *txPoolApi) Name() string { - return shared.TxPoolApiName -} - -func (self *txPoolApi) ApiVersion() string { - return TxPoolApiVersion -} - -func (self *txPoolApi) Status(req *shared.Request) (interface{}, error) { - pending, queue := self.ethereum.TxPool().Stats() - return map[string]int{ - "pending": pending, - "queued": queue, - }, nil -} diff --git a/rpc/api/txpool_js.go b/rpc/api/txpool_js.go deleted file mode 100644 index b6c29871a..000000000 --- a/rpc/api/txpool_js.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -const TxPool_JS = ` -web3._extend({ - property: 'txpool', - methods: - [ - ], - properties: - [ - new web3._extend.Property({ - name: 'status', - getter: 'txpool_status' - }) - ] -}); -` diff --git a/rpc/api/utils.go b/rpc/api/utils.go deleted file mode 100644 index 794b6abee..000000000 --- a/rpc/api/utils.go +++ /dev/null @@ -1,226 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package api - -import ( - "strings" - - "fmt" - - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/xeth" -) - -var ( - // Mapping between the different methods each api supports - AutoCompletion = map[string][]string{ - "admin": []string{ - "addPeer", - "datadir", - "enableUserAgent", - "exportChain", - "getContractInfo", - "httpGet", - "importChain", - "nodeInfo", - "peers", - "register", - "registerUrl", - "saveInfo", - "setGlobalRegistrar", - "setHashReg", - "setUrlHint", - "setSolc", - "sleep", - "sleepBlocks", - "startNatSpec", - "startRPC", - "stopNatSpec", - "stopRPC", - "verbosity", - }, - "db": []string{ - "getString", - "putString", - "getHex", - "putHex", - }, - "debug": []string{ - "dumpBlock", - "getBlockRlp", - "metrics", - "printBlock", - "processBlock", - "seedHash", - "setHead", - }, - "eth": []string{ - "accounts", - "blockNumber", - "call", - "contract", - "coinbase", - "compile.lll", - "compile.serpent", - "compile.solidity", - "contract", - "defaultAccount", - "defaultBlock", - "estimateGas", - "filter", - "getBalance", - "getBlock", - "getBlockTransactionCount", - "getBlockUncleCount", - "getCode", - "getNatSpec", - "getCompilers", - "gasPrice", - "getStorageAt", - "getTransaction", - "getTransactionCount", - "getTransactionFromBlock", - "getTransactionReceipt", - "getUncle", - "hashrate", - "mining", - "namereg", - "pendingTransactions", - "resend", - "sendRawTransaction", - "sendTransaction", - "sign", - "syncing", - }, - "miner": []string{ - "hashrate", - "makeDAG", - "setEtherbase", - "setExtra", - "setGasPrice", - "startAutoDAG", - "start", - "stopAutoDAG", - "stop", - }, - "net": []string{ - "peerCount", - "listening", - }, - "personal": []string{ - "listAccounts", - "newAccount", - "unlockAccount", - }, - "shh": []string{ - "post", - "newIdentity", - "hasIdentity", - "newGroup", - "addToGroup", - "filter", - }, - "txpool": []string{ - "status", - }, - "web3": []string{ - "sha3", - "version", - "fromWei", - "toWei", - "toHex", - "toAscii", - "fromAscii", - "toBigNumber", - "isAddress", - }, - } -) - -// Parse a comma separated API string to individual api's -func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, stack *node.Node) ([]shared.EthereumApi, error) { - if len(strings.TrimSpace(apistr)) == 0 { - return nil, fmt.Errorf("Empty apistr provided") - } - - names := strings.Split(apistr, ",") - apis := make([]shared.EthereumApi, len(names)) - - var eth *eth.Ethereum - if stack != nil { - if err := stack.Service(ð); err != nil { - return nil, err - } - } - for i, name := range names { - switch strings.ToLower(strings.TrimSpace(name)) { - case shared.AdminApiName: - apis[i] = NewAdminApi(xeth, stack, codec) - case shared.DebugApiName: - apis[i] = NewDebugApi(xeth, eth, codec) - case shared.DbApiName: - apis[i] = NewDbApi(xeth, eth, codec) - case shared.EthApiName: - apis[i] = NewEthApi(xeth, eth, codec) - case shared.MinerApiName: - apis[i] = NewMinerApi(eth, codec) - case shared.NetApiName: - apis[i] = NewNetApi(xeth, eth, codec) - case shared.ShhApiName: - apis[i] = NewShhApi(xeth, eth, codec) - case shared.TxPoolApiName: - apis[i] = NewTxPoolApi(xeth, eth, codec) - case shared.PersonalApiName: - apis[i] = NewPersonalApi(xeth, eth, codec) - case shared.Web3ApiName: - apis[i] = NewWeb3Api(xeth, codec) - case "rpc": // gives information about the RPC interface - continue - default: - return nil, fmt.Errorf("Unknown API '%s'", name) - } - } - return apis, nil -} - -func Javascript(name string) string { - switch strings.ToLower(strings.TrimSpace(name)) { - case shared.AdminApiName: - return Admin_JS - case shared.DebugApiName: - return Debug_JS - case shared.DbApiName: - return Db_JS - case shared.EthApiName: - return Eth_JS - case shared.MinerApiName: - return Miner_JS - case shared.NetApiName: - return Net_JS - case shared.ShhApiName: - return Shh_JS - case shared.TxPoolApiName: - return TxPool_JS - case shared.PersonalApiName: - return Personal_JS - } - - return "" -} diff --git a/rpc/api/web3.go b/rpc/api/web3.go deleted file mode 100644 index e2d8543d3..000000000 --- a/rpc/api/web3.go +++ /dev/null @@ -1,99 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -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 ( - Web3ApiVersion = "1.0" -) - -var ( - // mapping between methods and handlers - Web3Mapping = map[string]web3handler{ - "web3_sha3": (*web3Api).Sha3, - "web3_clientVersion": (*web3Api).ClientVersion, - } -) - -// web3 callback handler -type web3handler func(*web3Api, *shared.Request) (interface{}, error) - -// web3 api provider -type web3Api struct { - xeth *xeth.XEth - methods map[string]web3handler - codec codec.ApiCoder -} - -// create a new web3 api instance -func NewWeb3Api(xeth *xeth.XEth, coder codec.Codec) *web3Api { - return &web3Api{ - xeth: xeth, - methods: Web3Mapping, - codec: coder.New(nil), - } -} - -// collection with supported methods -func (self *web3Api) 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 *web3Api) Execute(req *shared.Request) (interface{}, error) { - if callback, ok := self.methods[req.Method]; ok { - return callback(self, req) - } - - return nil, &shared.NotImplementedError{req.Method} -} - -func (self *web3Api) Name() string { - return shared.Web3ApiName -} - -func (self *web3Api) ApiVersion() string { - return Web3ApiVersion -} - -// Calculates the sha3 over req.Params.Data -func (self *web3Api) Sha3(req *shared.Request) (interface{}, error) { - args := new(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 *web3Api) ClientVersion(req *shared.Request) (interface{}, error) { - return self.xeth.ClientVersion(), nil -} diff --git a/rpc/codec/codec.go b/rpc/codec/codec.go deleted file mode 100644 index 786080b44..000000000 --- a/rpc/codec/codec.go +++ /dev/null @@ -1,65 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -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, bool, error) - // Parse response message from underlying stream - ReadResponse() (interface{}, error) - // Read raw message from underlying stream - Recv() (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") -} diff --git a/rpc/codec/json.go b/rpc/codec/json.go deleted file mode 100644 index cfc449143..000000000 --- a/rpc/codec/json.go +++ /dev/null @@ -1,149 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package codec - -import ( - "encoding/json" - "fmt" - "net" - "time" - "strings" - - "github.com/ethereum/go-ethereum/rpc/shared" -) - -const ( - READ_TIMEOUT = 60 // in seconds - MAX_REQUEST_SIZE = 1024 * 1024 - MAX_RESPONSE_SIZE = 1024 * 1024 -) - -// Json serialization support -type JsonCodec struct { - c net.Conn - d *json.Decoder -} - -// Create new JSON coder instance -func NewJsonCoder(conn net.Conn) ApiCoder { - return &JsonCodec{ - c: conn, - d: json.NewDecoder(conn), - } -} - -// Read incoming request and parse it to RPC request -func (self *JsonCodec) ReadRequest() (requests []*shared.Request, isBatch bool, err error) { - deadline := time.Now().Add(READ_TIMEOUT * time.Second) - if err := self.c.SetDeadline(deadline); err != nil { - return nil, false, err - } - - var incoming json.RawMessage - err = self.d.Decode(&incoming) - if err == nil { - isBatch = incoming[0] == '[' - if isBatch { - requests = make([]*shared.Request, 0) - err = json.Unmarshal(incoming, &requests) - } else { - requests = make([]*shared.Request, 1) - var singleRequest shared.Request - if err = json.Unmarshal(incoming, &singleRequest); err == nil { - requests[0] = &singleRequest - } - } - return - } - - self.c.Close() - return nil, false, err -} - -func (self *JsonCodec) Recv() (interface{}, error) { - var msg json.RawMessage - err := self.d.Decode(&msg) - if err != nil { - self.c.Close() - return nil, err - } - - return msg, err -} - -func (self *JsonCodec) ReadResponse() (interface{}, error) { - in, err := self.Recv() - if err != nil { - return nil, err - } - - if msg, ok := in.(json.RawMessage); ok { - var req *shared.Request - if err = json.Unmarshal(msg, &req); err == nil && strings.HasPrefix(req.Method, "agent_") { - return req, nil - } - - var failure *shared.ErrorResponse - if err = json.Unmarshal(msg, &failure); err == nil && failure.Error != nil { - return failure, fmt.Errorf(failure.Error.Message) - } - - var success *shared.SuccessResponse - if err = json.Unmarshal(msg, &success); err == nil { - return success, nil - } - } - - return in, err -} - -// Decode data -func (self *JsonCodec) Decode(data []byte, msg interface{}) error { - return json.Unmarshal(data, msg) -} - -// Encode message -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 { - data, err := json.Marshal(res) - if err != nil { - self.c.Close() - return err - } - - bytesWritten := 0 - - for bytesWritten < len(data) { - n, err := self.c.Write(data[bytesWritten:]) - if err != nil { - self.c.Close() - return err - } - bytesWritten += n - } - - return nil -} - -// Close decoder and encoder -func (self *JsonCodec) Close() { - self.c.Close() -} diff --git a/rpc/codec/json_test.go b/rpc/codec/json_test.go deleted file mode 100644 index 01ef77e57..000000000 --- a/rpc/codec/json_test.go +++ /dev/null @@ -1,157 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package codec - -import ( - "bytes" - "io" - "net" - "testing" - "time" -) - -type jsonTestConn struct { - buffer *bytes.Buffer -} - -func newJsonTestConn(data []byte) *jsonTestConn { - return &jsonTestConn{ - buffer: bytes.NewBuffer(data), - } -} - -func (self *jsonTestConn) Read(p []byte) (n int, err error) { - return self.buffer.Read(p) -} - -func (self *jsonTestConn) Write(p []byte) (n int, err error) { - return self.buffer.Write(p) -} - -func (self *jsonTestConn) Close() error { - // not implemented - return nil -} - -func (self *jsonTestConn) LocalAddr() net.Addr { - // not implemented - return nil -} - -func (self *jsonTestConn) RemoteAddr() net.Addr { - // not implemented - return nil -} - -func (self *jsonTestConn) SetDeadline(t time.Time) error { - return nil -} - -func (self *jsonTestConn) SetReadDeadline(t time.Time) error { - return nil -} - -func (self *jsonTestConn) SetWriteDeadline(t time.Time) error { - return nil -} - -func TestJsonDecoderWithValidRequest(t *testing.T) { - reqdata := []byte(`{"jsonrpc":"2.0","method":"modules","params":[],"id":64}`) - decoder := newJsonTestConn(reqdata) - - jsonDecoder := NewJsonCoder(decoder) - requests, batch, err := jsonDecoder.ReadRequest() - - if err != nil { - t.Errorf("Read valid request failed - %v", err) - } - - if len(requests) != 1 { - t.Errorf("Expected to get a single request but got %d", len(requests)) - } - - if batch { - t.Errorf("Got batch indication while expecting single request") - } - - if requests[0].Id != float64(64) { - t.Errorf("Expected req.Id == 64 but got %v", requests[0].Id) - } - - if requests[0].Method != "modules" { - t.Errorf("Expected req.Method == 'modules' got '%s'", requests[0].Method) - } -} - -func TestJsonDecoderWithValidBatchRequest(t *testing.T) { - reqdata := []byte(`[{"jsonrpc":"2.0","method":"modules","params":[],"id":64}, - {"jsonrpc":"2.0","method":"modules","params":[],"id":64}]`) - decoder := newJsonTestConn(reqdata) - - jsonDecoder := NewJsonCoder(decoder) - requests, batch, err := jsonDecoder.ReadRequest() - - if err != nil { - t.Errorf("Read valid batch request failed - %v", err) - } - - if len(requests) != 2 { - t.Errorf("Expected to get two requests but got %d", len(requests)) - } - - if !batch { - t.Errorf("Got no batch indication while expecting batch request") - } - - for i := 0; i < len(requests); i++ { - if requests[i].Id != float64(64) { - t.Errorf("Expected req.Id == 64 but got %v", requests[i].Id) - } - - if requests[i].Method != "modules" { - t.Errorf("Expected req.Method == 'modules' got '%s'", requests[i].Method) - } - } -} - -func TestJsonDecoderWithInvalidIncompleteMessage(t *testing.T) { - reqdata := []byte(`{"jsonrpc":"2.0","method":"modules","pa`) - decoder := newJsonTestConn(reqdata) - - jsonDecoder := NewJsonCoder(decoder) - requests, batch, err := jsonDecoder.ReadRequest() - - if err != io.ErrUnexpectedEOF { - t.Errorf("Expected to read an incomplete request err but got %v", err) - } - - // remaining message - decoder.Write([]byte(`rams":[],"id:64"}`)) - requests, batch, err = jsonDecoder.ReadRequest() - - if err == nil { - t.Errorf("Expected an error but got nil") - } - - if len(requests) != 0 { - t.Errorf("Expected to get no requests but got %d", len(requests)) - } - - if batch { - t.Errorf("Got batch indication while expecting non batch") - } -} diff --git a/rpc/comms/comms.go b/rpc/comms/comms.go deleted file mode 100644 index 61fba5722..000000000 --- a/rpc/comms/comms.go +++ /dev/null @@ -1,150 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package comms - -import ( - "io" - "net" - - "fmt" - "strings" - - "strconv" - - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -const ( - maxHttpSizeReqLength = 1024 * 1024 // 1MB -) - -var ( - // List with all API's which are offered over the in proc interface by default - DefaultInProcApis = shared.AllApis - - // List with all API's which are offered over the IPC interface by default - DefaultIpcApis = shared.AllApis - - // List with API's which are offered over thr HTTP/RPC interface by default - DefaultHttpRpcApis = strings.Join([]string{ - shared.DbApiName, shared.EthApiName, shared.NetApiName, shared.Web3ApiName, - }, ",") -) - -type EthereumClient interface { - // Close underlying connection - Close() - // Send request - Send(interface{}) error - // Receive response - Recv() (interface{}, error) - // List with modules this client supports - SupportedModules() (map[string]string, error) -} - -func handle(id int, conn net.Conn, api shared.EthereumApi, c codec.Codec) { - codec := c.New(conn) - - defer func() { - if r := recover(); r != nil { - glog.Errorf("panic: %v\n", r) - } - codec.Close() - }() - - for { - requests, isBatch, err := codec.ReadRequest() - if err == io.EOF { - return - } else if err != nil { - glog.V(logger.Debug).Infof("Closed IPC Conn %06d recv err - %v\n", id, err) - return - } - - if isBatch { - responses := make([]*interface{}, len(requests)) - responseCount := 0 - for _, req := range requests { - res, err := api.Execute(req) - if req.Id != nil { - rpcResponse := shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err) - responses[responseCount] = rpcResponse - responseCount += 1 - } - } - - err = codec.WriteResponse(responses[:responseCount]) - if err != nil { - glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err) - return - } - } else { - var rpcResponse interface{} - res, err := api.Execute(requests[0]) - - rpcResponse = shared.NewRpcResponse(requests[0].Id, requests[0].Jsonrpc, res, err) - err = codec.WriteResponse(rpcResponse) - if err != nil { - glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err) - return - } - } - } -} - -// Endpoint must be in the form of: -// ${protocol}:${path} -// e.g. ipc:/tmp/geth.ipc -// rpc:localhost:8545 -func ClientFromEndpoint(endpoint string, c codec.Codec) (EthereumClient, error) { - if strings.HasPrefix(endpoint, "ipc:") { - cfg := IpcConfig{ - Endpoint: endpoint[4:], - } - return NewIpcClient(cfg, codec.JSON) - } - - if strings.HasPrefix(endpoint, "rpc:") { - parts := strings.Split(endpoint, ":") - addr := "http://localhost" - port := uint(8545) - if len(parts) >= 3 { - addr = parts[1] + ":" + parts[2] - } - - if len(parts) >= 4 { - p, err := strconv.Atoi(parts[3]) - - if err != nil { - return nil, err - } - port = uint(p) - } - - cfg := HttpConfig{ - ListenAddress: addr, - ListenPort: port, - } - - return NewHttpClient(cfg, codec.JSON), nil - } - - return nil, fmt.Errorf("Invalid endpoint") -} diff --git a/rpc/comms/http.go b/rpc/comms/http.go deleted file mode 100644 index f4a930d0e..000000000 --- a/rpc/comms/http.go +++ /dev/null @@ -1,345 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package comms - -import ( - "encoding/json" - "fmt" - "net" - "net/http" - "strings" - "sync" - "time" - - "bytes" - "io" - "io/ioutil" - - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/rs/cors" -) - -const ( - serverIdleTimeout = 10 * time.Second // idle keep-alive connections - serverReadTimeout = 15 * time.Second // per-request read timeout - serverWriteTimeout = 15 * time.Second // per-request read timeout -) - -var ( - httpServerMu sync.Mutex - httpServer *stopServer -) - -type HttpConfig struct { - ListenAddress string - ListenPort uint - CorsDomain string -} - -// stopServer augments http.Server with idle connection tracking. -// Idle keep-alive connections are shut down when Close is called. -type stopServer struct { - *http.Server - l net.Listener - // connection tracking state - mu sync.Mutex - shutdown bool // true when Stop has returned - idle map[net.Conn]struct{} -} - -type handler struct { - codec codec.Codec - api shared.EthereumApi -} - -// StartHTTP starts listening for RPC requests sent via HTTP. -func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.EthereumApi) error { - httpServerMu.Lock() - defer httpServerMu.Unlock() - - addr := fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort) - if httpServer != nil { - if addr != httpServer.Addr { - return fmt.Errorf("RPC service already running on %s ", httpServer.Addr) - } - return nil // RPC service already running on given host/port - } - // Set up the request handler, wrapping it with CORS headers if configured. - handler := http.Handler(&handler{codec, api}) - if len(cfg.CorsDomain) > 0 { - opts := cors.Options{ - AllowedMethods: []string{"POST"}, - AllowedOrigins: strings.Split(cfg.CorsDomain, " "), - } - handler = cors.New(opts).Handler(handler) - } - // Start the server. - s, err := listenHTTP(addr, handler) - if err != nil { - glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", cfg.ListenAddress, cfg.ListenPort, err) - return err - } - httpServer = s - return nil -} - -func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - w.Header().Set("Content-Type", "application/json") - - // Limit request size to resist DoS - if req.ContentLength > maxHttpSizeReqLength { - err := fmt.Errorf("Request too large") - response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) - sendJSON(w, &response) - return - } - - defer req.Body.Close() - payload, err := ioutil.ReadAll(req.Body) - if err != nil { - err := fmt.Errorf("Could not read request body") - response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) - sendJSON(w, &response) - return - } - - c := h.codec.New(nil) - var rpcReq shared.Request - if err = c.Decode(payload, &rpcReq); err == nil { - reply, err := h.api.Execute(&rpcReq) - res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) - sendJSON(w, &res) - return - } - - var reqBatch []shared.Request - if err = c.Decode(payload, &reqBatch); err == nil { - resBatch := make([]*interface{}, len(reqBatch)) - resCount := 0 - for i, rpcReq := range reqBatch { - reply, err := h.api.Execute(&rpcReq) - if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal - resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) - resCount += 1 - } - } - // make response omitting nil entries - sendJSON(w, resBatch[:resCount]) - return - } - - // invalid request - err = fmt.Errorf("Could not decode request") - res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err) - sendJSON(w, res) -} - -func sendJSON(w io.Writer, v interface{}) { - if glog.V(logger.Detail) { - if payload, err := json.MarshalIndent(v, "", "\t"); err == nil { - glog.Infof("Sending payload: %s", payload) - } - } - if err := json.NewEncoder(w).Encode(v); err != nil { - glog.V(logger.Error).Infoln("Error sending JSON:", err) - } -} - -// Stop closes all active HTTP connections and shuts down the server. -func StopHttp() { - httpServerMu.Lock() - defer httpServerMu.Unlock() - if httpServer != nil { - httpServer.Close() - httpServer = nil - } -} - -func listenHTTP(addr string, h http.Handler) (*stopServer, error) { - l, err := net.Listen("tcp", addr) - if err != nil { - return nil, err - } - s := &stopServer{l: l, idle: make(map[net.Conn]struct{})} - s.Server = &http.Server{ - Addr: addr, - Handler: h, - ReadTimeout: serverReadTimeout, - WriteTimeout: serverWriteTimeout, - ConnState: s.connState, - } - go s.Serve(l) - return s, nil -} - -func (s *stopServer) connState(c net.Conn, state http.ConnState) { - s.mu.Lock() - defer s.mu.Unlock() - // Close c immediately if we're past shutdown. - if s.shutdown { - if state != http.StateClosed { - c.Close() - } - return - } - if state == http.StateIdle { - s.idle[c] = struct{}{} - } else { - delete(s.idle, c) - } -} - -func (s *stopServer) Close() { - s.mu.Lock() - defer s.mu.Unlock() - // Shut down the acceptor. No new connections can be created. - s.l.Close() - // Drop all idle connections. Non-idle connections will be - // closed by connState as soon as they become idle. - s.shutdown = true - for c := range s.idle { - glog.V(logger.Detail).Infof("closing idle connection %v", c.RemoteAddr()) - c.Close() - delete(s.idle, c) - } -} - -type httpClient struct { - address string - port uint - codec codec.ApiCoder - lastRes interface{} - lastErr error -} - -// Create a new in process client -func NewHttpClient(cfg HttpConfig, c codec.Codec) *httpClient { - return &httpClient{ - address: cfg.ListenAddress, - port: cfg.ListenPort, - codec: c.New(nil), - } -} - -func (self *httpClient) Close() { - // do nothing -} - -func (self *httpClient) Send(req interface{}) error { - var body []byte - var err error - - self.lastRes = nil - self.lastErr = nil - - if body, err = self.codec.Encode(req); err != nil { - return err - } - - httpReq, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) - if err != nil { - return err - } - httpReq.Header.Set("Content-Type", "application/json") - - client := http.Client{} - resp, err := client.Do(httpReq) - if err != nil { - return err - } - - defer resp.Body.Close() - - if resp.Status == "200 OK" { - reply, _ := ioutil.ReadAll(resp.Body) - var rpcSuccessResponse shared.SuccessResponse - if err = self.codec.Decode(reply, &rpcSuccessResponse); err == nil { - self.lastRes = &rpcSuccessResponse - self.lastErr = err - return nil - } else { - var rpcErrorResponse shared.ErrorResponse - if err = self.codec.Decode(reply, &rpcErrorResponse); err == nil { - self.lastRes = &rpcErrorResponse - self.lastErr = err - return nil - } else { - return err - } - } - } - - return fmt.Errorf("Not implemented") -} - -func (self *httpClient) Recv() (interface{}, error) { - return self.lastRes, self.lastErr -} - -func (self *httpClient) SupportedModules() (map[string]string, error) { - var body []byte - var err error - - payload := shared.Request{ - Id: 1, - Jsonrpc: "2.0", - Method: "modules", - } - - if body, err = self.codec.Encode(payload); err != nil { - return nil, err - } - - req, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", "application/json") - - client := http.Client{} - resp, err := client.Do(req) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - - if resp.Status == "200 OK" { - reply, _ := ioutil.ReadAll(resp.Body) - var rpcRes shared.SuccessResponse - if err = self.codec.Decode(reply, &rpcRes); err != nil { - return nil, err - } - - result := make(map[string]string) - if modules, ok := rpcRes.Result.(map[string]interface{}); ok { - for a, v := range modules { - result[a] = fmt.Sprintf("%s", v) - } - return result, nil - } - err = fmt.Errorf("Unable to parse module response - %v", rpcRes.Result) - } else { - fmt.Printf("resp.Status = %s\n", resp.Status) - fmt.Printf("err = %v\n", err) - } - - return nil, err -} diff --git a/rpc/comms/inproc.go b/rpc/comms/inproc.go deleted file mode 100644 index e8058e32b..000000000 --- a/rpc/comms/inproc.go +++ /dev/null @@ -1,82 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package comms - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type InProcClient struct { - api shared.EthereumApi - codec codec.Codec - lastId interface{} - lastJsonrpc string - lastErr error - lastRes interface{} -} - -// Create a new in process client -func NewInProcClient(codec codec.Codec) *InProcClient { - return &InProcClient{ - codec: codec, - } -} - -func (self *InProcClient) Close() { - // do nothing -} - -// Need to setup api support -func (self *InProcClient) Initialize(offeredApi shared.EthereumApi) { - self.api = offeredApi -} - -func (self *InProcClient) Send(req interface{}) error { - if r, ok := req.(*shared.Request); ok { - self.lastId = r.Id - self.lastJsonrpc = r.Jsonrpc - self.lastRes, self.lastErr = self.api.Execute(r) - return self.lastErr - } - - return fmt.Errorf("Invalid request (%T)", req) -} - -func (self *InProcClient) Recv() (interface{}, error) { - return *shared.NewRpcResponse(self.lastId, self.lastJsonrpc, self.lastRes, self.lastErr), nil -} - -func (self *InProcClient) SupportedModules() (map[string]string, error) { - req := shared.Request{ - Id: 1, - Jsonrpc: "2.0", - Method: "modules", - } - - if res, err := self.api.Execute(&req); err == nil { - if result, ok := res.(map[string]string); ok { - return result, nil - } - } else { - return nil, err - } - - return nil, fmt.Errorf("Invalid response") -} diff --git a/rpc/comms/ipc.go b/rpc/comms/ipc.go deleted file mode 100644 index 3ba747b1d..000000000 --- a/rpc/comms/ipc.go +++ /dev/null @@ -1,158 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package comms - -import ( - "fmt" - "math/rand" - "net" - "os" - - "encoding/json" - - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -type Stopper interface { - Stop() -} - -type InitFunc func(conn net.Conn) (Stopper, shared.EthereumApi, error) - -type IpcConfig struct { - Endpoint string -} - -type ipcClient struct { - endpoint string - c net.Conn - codec codec.Codec - coder codec.ApiCoder -} - -func (self *ipcClient) Close() { - self.coder.Close() -} - -func (self *ipcClient) Send(msg interface{}) error { - var err error - if err = self.coder.WriteResponse(msg); err != nil { - if err = self.reconnect(); err == nil { - err = self.coder.WriteResponse(msg) - } - } - return err -} - -func (self *ipcClient) Recv() (interface{}, error) { - return self.coder.ReadResponse() -} - -func (self *ipcClient) SupportedModules() (map[string]string, error) { - req := shared.Request{ - Id: 1, - Jsonrpc: "2.0", - Method: "rpc_modules", - } - - if err := self.coder.WriteResponse(req); err != nil { - return nil, err - } - - res, _ := self.coder.ReadResponse() - if sucRes, ok := res.(*shared.SuccessResponse); ok { - data, _ := json.Marshal(sucRes.Result) - modules := make(map[string]string) - if err := json.Unmarshal(data, &modules); err == nil { - return modules, nil - } - } - - // old version uses modules instead of rpc_modules, this can be removed after full migration - req.Method = "modules" - if err := self.coder.WriteResponse(req); err != nil { - return nil, err - } - - res, err := self.coder.ReadResponse() - if err != nil { - return nil, err - } - - if sucRes, ok := res.(*shared.SuccessResponse); ok { - data, _ := json.Marshal(sucRes.Result) - modules := make(map[string]string) - err = json.Unmarshal(data, &modules) - if err == nil { - return modules, nil - } - } - - return nil, fmt.Errorf("Invalid response") -} - -// 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, initializer InitFunc) error { - l, err := ipcListen(cfg) - if err != nil { - return err - } - go ipcLoop(cfg, codec, initializer, l) - return nil -} - -// CreateListener creates an listener, on Unix platforms this is a unix socket, on Windows this is a named pipe -func CreateListener(cfg IpcConfig) (net.Listener, error) { - return ipcListen(cfg) -} - -func ipcLoop(cfg IpcConfig, codec codec.Codec, initializer InitFunc, l net.Listener) { - glog.V(logger.Info).Infof("IPC service started (%s)\n", cfg.Endpoint) - defer os.Remove(cfg.Endpoint) - defer l.Close() - for { - conn, err := l.Accept() - if err != nil { - glog.V(logger.Debug).Infof("accept: %v", err) - return - } - id := newIpcConnId() - go func() { - defer conn.Close() - glog.V(logger.Debug).Infof("new connection with id %06d started", id) - stopper, api, err := initializer(conn) - if err != nil { - glog.V(logger.Error).Infof("Unable to initialize IPC connection: %v", err) - return - } - defer stopper.Stop() - handle(id, conn, api, codec) - }() - } -} - -func newIpcConnId() int { - return rand.Int() % 1000000 -} diff --git a/rpc/comms/ipc_unix.go b/rpc/comms/ipc_unix.go deleted file mode 100644 index 4b839572a..000000000 --- a/rpc/comms/ipc_unix.go +++ /dev/null @@ -1,82 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris - -package comms - -import ( - "net" - "os" - "path/filepath" - - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/rpc/useragent" -) - -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 - } - - coder := codec.New(c) - msg := shared.Request{ - Id: 0, - Method: useragent.EnableUserAgentMethod, - Jsonrpc: shared.JsonRpcVersion, - Params: []byte("[]"), - } - - coder.WriteResponse(msg) - coder.Recv() - - return &ipcClient{cfg.Endpoint, c, codec, coder}, nil -} - -func (self *ipcClient) reconnect() error { - self.coder.Close() - c, err := net.DialUnix("unix", nil, &net.UnixAddr{self.endpoint, "unix"}) - if err == nil { - self.coder = self.codec.New(c) - - msg := shared.Request{ - Id: 0, - Method: useragent.EnableUserAgentMethod, - Jsonrpc: shared.JsonRpcVersion, - Params: []byte("[]"), - } - self.coder.WriteResponse(msg) - self.coder.Recv() - } - - return err -} - -func ipcListen(cfg IpcConfig) (net.Listener, error) { - // Ensure the IPC path exists and remove any previous leftover - if err := os.MkdirAll(filepath.Dir(cfg.Endpoint), 0751); err != nil { - return nil, err - } - os.Remove(cfg.Endpoint) - l, err := net.Listen("unix", cfg.Endpoint) - if err != nil { - return nil, err - } - os.Chmod(cfg.Endpoint, 0600) - return l, nil -} diff --git a/rpc/v2/doc.go b/rpc/doc.go index e51494adb..e8f8f977b 100644 --- a/rpc/v2/doc.go +++ b/rpc/doc.go @@ -99,4 +99,130 @@ Subscriptions are deleted when: - the user sends an unsubscribe request - the connection which was used to create the subscription is closed */ -package v2 +package rpc + +var ( + // Mapping between the different methods each api supports + AutoCompletion = map[string][]string{ + "admin": []string{ + "addPeer", + "datadir", + "enableUserAgent", + "exportChain", + "getContractInfo", + "httpGet", + "importChain", + "nodeInfo", + "peers", + "register", + "registerUrl", + "saveInfo", + "setGlobalRegistrar", + "setHashReg", + "setUrlHint", + "setSolc", + "sleep", + "sleepBlocks", + "startNatSpec", + "startRPC", + "stopNatSpec", + "stopRPC", + "verbosity", + }, + "db": []string{ + "getString", + "putString", + "getHex", + "putHex", + }, + "debug": []string{ + "dumpBlock", + "getBlockRlp", + "metrics", + "printBlock", + "processBlock", + "seedHash", + "setHead", + }, + "eth": []string{ + "accounts", + "blockNumber", + "call", + "contract", + "coinbase", + "compile.lll", + "compile.serpent", + "compile.solidity", + "contract", + "defaultAccount", + "defaultBlock", + "estimateGas", + "filter", + "getBalance", + "getBlock", + "getBlockTransactionCount", + "getBlockUncleCount", + "getCode", + "getNatSpec", + "getCompilers", + "gasPrice", + "getStorageAt", + "getTransaction", + "getTransactionCount", + "getTransactionFromBlock", + "getTransactionReceipt", + "getUncle", + "hashrate", + "mining", + "namereg", + "pendingTransactions", + "resend", + "sendRawTransaction", + "sendTransaction", + "sign", + "syncing", + }, + "miner": []string{ + "hashrate", + "makeDAG", + "setEtherbase", + "setExtra", + "setGasPrice", + "startAutoDAG", + "start", + "stopAutoDAG", + "stop", + }, + "net": []string{ + "peerCount", + "listening", + }, + "personal": []string{ + "listAccounts", + "newAccount", + "unlockAccount", + }, + "shh": []string{ + "post", + "newIdentity", + "hasIdentity", + "newGroup", + "addToGroup", + "filter", + }, + "txpool": []string{ + "status", + }, + "web3": []string{ + "sha3", + "version", + "fromWei", + "toWei", + "toHex", + "toAscii", + "fromAscii", + "toBigNumber", + "isAddress", + }, + } +) diff --git a/rpc/v2/errors.go b/rpc/errors.go index a06d19d84..bc352fc45 100644 --- a/rpc/v2/errors.go +++ b/rpc/errors.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package v2 +package rpc import "fmt" @@ -83,3 +83,15 @@ func (e *callbackError) Code() int { func (e *callbackError) Error() string { return e.message } + +// issued when a request is received after the server is issued to stop. +type shutdownError struct { +} + +func (e *shutdownError) Code() int { + return -32000 +} + +func (e *shutdownError) Error() string { + return "server is shutting down" +} diff --git a/rpc/http.go b/rpc/http.go new file mode 100644 index 000000000..e4b25bed8 --- /dev/null +++ b/rpc/http.go @@ -0,0 +1,368 @@ +// 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 <http://www.gnu.org/licenses/>. + +package rpc + +import ( + "bufio" + "fmt" + "io" + "net" + "net/http" + "strconv" + "strings" + "time" + + "errors" + "sync" + + "bytes" + "encoding/json" + "io/ioutil" + "net/url" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "gopkg.in/fatih/set.v0" +) + +const ( + httpReadDeadLine = 60 * time.Second // wait max httpReadDeadeline for next request +) + +var ( + httpServerMu sync.Mutex // prevent concurrent access to the httpListener and httpServer + httpListener net.Listener // listener for the http server + httpRPCServer *Server // the node can only start 1 HTTP RPC server instance +) + +// httpMessageStream is the glue between a HTTP connection which is message based +// and the RPC codecs that expect json requests to be read from a stream. It will +// parse HTTP messages and offer the bodies of these requests as a stream through +// the Read method. This will require full control of the connection and thus need +// a "hijacked" HTTP connection. +type httpMessageStream struct { + conn net.Conn // TCP connection + rw *bufio.ReadWriter // buffered where HTTP requests/responses are read/written from/to + currentReq *http.Request // pending request, codec can pass in a too small buffer for a single read + // we need to keep track of the current requests if it was not read at once + payloadBytesRead int64 // number of bytes which are read from the current request + allowedOrigins *set.Set // allowed CORS domains + origin string // origin of this connection/request +} + +// NewHttpMessageStream will create a new http message stream parser that can be +// used by the codes in the RPC package. It will take full control of the given +// connection and thus needs to be hijacked. It will read and write HTTP messages +// from the passed rwbuf. The allowed origins are the RPC CORS domains the user has supplied. +func NewHTTPMessageStream(c net.Conn, rwbuf *bufio.ReadWriter, initialReq *http.Request, allowdOrigins []string) *httpMessageStream { + r := &httpMessageStream{conn: c, rw: rwbuf, currentReq: initialReq, allowedOrigins: set.New()} + for _, origin := range allowdOrigins { + r.allowedOrigins.Add(origin) + } + return r +} + +// handleOptionsRequest handles the HTTP preflight requests (OPTIONS) that browsers +// make to enforce CORS rules. Only the POST method is allowed and the origin must +// be on the rpccorsdomain list the user has specified. +func (h *httpMessageStream) handleOptionsRequest(req *http.Request) error { + headers := req.Header + + if !strings.EqualFold(req.Method, "OPTIONS") { + return fmt.Errorf("preflight aborted: %s!=OPTIONS", req.Method) + } + + origin := headers.Get("Origin") + if origin == "" { + return fmt.Errorf("preflight aborted: empty origin") + } + + responseHeaders := make(http.Header) + responseHeaders.Set("Access-Control-Allow-Methods", "POST") + if h.allowedOrigins.Has(origin) || h.allowedOrigins.Has("*") { + responseHeaders.Set("Access-Control-Allow-Origin", origin) + } else { + glog.V(logger.Info).Infof("origin '%s' not allowed", origin) + } + responseHeaders.Set("Access-Control-Allow-Headers", "Content-Type") + responseHeaders.Set("Date", string(httpTimestamp(time.Now()))) + responseHeaders.Set("Content-Type", "text/plain; charset=utf-8") + responseHeaders.Set("Content-Length", "0") + responseHeaders.Set("Vary", "Origin") + + defer h.rw.Flush() + + if _, err := h.rw.WriteString("HTTP/1.1 200 OK\r\n"); err != nil { + glog.V(logger.Error).Infof("unable to write OPTIONS response: %v\n", err) + return err + } + if err := responseHeaders.Write(h.rw); err != nil { + glog.V(logger.Error).Infof("unable to write OPTIONS headers: %v\n", err) + } + if _, err := h.rw.WriteString("\r\n"); err != nil { + glog.V(logger.Error).Infof("unable to write OPTIONS response: %v\n", err) + } + + return nil +} + +// Read will read incoming HTTP requests and reads the body data from these requests +// as an endless stream of data. +func (h *httpMessageStream) Read(buf []byte) (n int, err error) { + h.conn.SetReadDeadline(time.Now().Add(httpReadDeadLine)) + for { + // if the last request was read completely try to read the next request + if h.currentReq == nil { + if h.currentReq, err = http.ReadRequest(bufio.NewReader(h.rw)); err != nil { + return 0, err + } + } + + // The "options" method is http specific and not interested for the RPC server. + // Handle it internally and wait for the next request. + if strings.EqualFold(h.currentReq.Method, "OPTIONS") { + if err = h.handleOptionsRequest(h.currentReq); err != nil { + glog.V(logger.Info).Infof("RPC/HTTP OPTIONS error: %v\n", err) + h.currentReq = nil + return 0, err + } + + // processed valid request -> reset deadline + h.conn.SetReadDeadline(time.Now().Add(httpReadDeadLine)) + h.currentReq = nil + continue + } + + if strings.EqualFold(h.currentReq.Method, "POST") { + n, err := h.currentReq.Body.Read(buf) + h.payloadBytesRead += int64(n) + + // entire payload read, read new request next time + if err == io.EOF || h.payloadBytesRead >= h.currentReq.ContentLength { + h.origin = h.currentReq.Header.Get("origin") + h.payloadBytesRead = 0 + h.currentReq.Body.Close() + h.currentReq = nil + err = nil // io.EOF is not an error + } else if err != nil { + // unable to read body + h.currentReq.Body.Close() + h.currentReq = nil + h.payloadBytesRead = 0 + } + + // partial read of body + return n, err + } + + h.currentReq = nil + return 0, fmt.Errorf("unsupported HTTP method '%s'", h.currentReq.Method) + } +} + +// Write will create a HTTP response with the given payload and send it to the peer. +func (h *httpMessageStream) Write(payload []byte) (int, error) { + defer h.rw.Flush() + + responseHeaders := make(http.Header) + responseHeaders.Set("Content-Type", "application/json") + responseHeaders.Set("Content-Length", strconv.Itoa(len(payload))) + if h.origin != "" { + responseHeaders.Set("Access-Control-Allow-Origin", h.origin) + } + + h.rw.WriteString("HTTP/1.1 200 OK\r\n") + responseHeaders.Write(h.rw) + h.rw.WriteString("\r\n") + + return h.rw.Write(payload) +} + +// Close will close the underlying TCP connection this instance has taken ownership over. +func (h *httpMessageStream) Close() error { + h.rw.Flush() + return h.conn.Close() +} + +// TimeFormat is the time format to use with time.Parse and time.Time.Format when +// parsing or generating times in HTTP headers. It is like time.RFC1123 but hard +// codes GMT as the time zone. +const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" + +// httpTimestamp formats the given t as specified in RFC1123. +func httpTimestamp(t time.Time) []byte { + const days = "SunMonTueWedThuFriSat" + const months = "JanFebMarAprMayJunJulAugSepOctNovDec" + + b := make([]byte, 0) + t = t.UTC() + yy, mm, dd := t.Date() + hh, mn, ss := t.Clock() + day := days[3 * t.Weekday():] + mon := months[3 * (mm - 1):] + + return append(b, + day[0], day[1], day[2], ',', ' ', + byte('0' + dd / 10), byte('0' + dd % 10), ' ', + mon[0], mon[1], mon[2], ' ', + byte('0' + yy / 1000), byte('0' + (yy / 100) % 10), byte('0' + (yy / 10) % 10), byte('0' + yy % 10), ' ', + byte('0' + hh / 10), byte('0' + hh % 10), ':', + byte('0' + mn / 10), byte('0' + mn % 10), ':', + byte('0' + ss / 10), byte('0' + ss % 10), ' ', + 'G', 'M', 'T') +} + +// httpConnHijacker is a http.Handler implementation that will hijack the HTTP +// connection, wraps it in a HttpMessageStream that is then wrapped in a JSON +// codec which will be served on the rpcServer. +type httpConnHijacker struct { + corsdomains []string + rpcServer *Server +} + +// ServeHTTP will hijack the connection, wraps the captured connection in a +// HttpMessageStream which is then used as codec. +func (h *httpConnHijacker) ServeHTTP(w http.ResponseWriter, req *http.Request) { + hj, ok := w.(http.Hijacker) + if !ok { + http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError) + return + } + + conn, rwbuf, err := hj.Hijack() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + httpRequestStream := NewHTTPMessageStream(conn, rwbuf, req, h.corsdomains) + + codec := NewJSONCodec(httpRequestStream) + go h.rpcServer.ServeCodec(codec) +} + +// StartHTTP will start the JSONRPC HTTP RPC interface when its not yet running. +func StartHTTP(address string, port int, corsdomains []string, apis []API) error { + httpServerMu.Lock() + defer httpServerMu.Unlock() + + if httpRPCServer != nil { + return fmt.Errorf("HTTP RPC interface already started on %s", httpListener.Addr()) + } + + rpcServer := NewServer() + + for _, api := range apis { + if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil { + return err + } + } + + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", address, port)) + if err != nil { + return err + } + + httpServer := http.Server{Handler: &httpConnHijacker{corsdomains, rpcServer}} + go httpServer.Serve(listener) + + httpListener = listener + httpRPCServer = rpcServer + + return nil +} + +// StopHTTP will stop the running HTTP interface. If it is not running an error will be returned. +func StopHTTP() error { + httpServerMu.Lock() + defer httpServerMu.Unlock() + + if httpRPCServer == nil { + return errors.New("HTTP RPC interface not started") + } + + httpListener.Close() + httpRPCServer.Stop() + + httpRPCServer = nil + httpListener = nil + + return nil +} + +// httpClient connects to a geth RPC server over HTTP. +type httpClient struct { + endpoint *url.URL // HTTP-RPC server endpoint + lastRes []byte // HTTP requests are synchronous, store last response +} + +// NewHTTPClient create a new RPC clients that connection to a geth RPC server +// over HTTP. +func NewHTTPClient(endpoint string) (*httpClient, error) { + url, err := url.Parse(endpoint) + if err != nil { + return nil, err + } + return &httpClient{endpoint: url}, nil +} + +// Send will serialize the given msg to JSON and sends it to the RPC server. +// Since HTTP is synchronous the response is stored until Recv is called. +func (client *httpClient) Send(msg interface{}) error { + var body []byte + var err error + + client.lastRes = nil + + if body, err = json.Marshal(msg); err != nil { + return err + } + + httpReq, err := http.NewRequest("POST", client.endpoint.String(), bytes.NewBuffer(body)) + if err != nil { + return err + } + httpReq.Header.Set("Content-Type", "application/json") + + httpClient := http.Client{} + resp, err := httpClient.Do(httpReq) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusOK { + client.lastRes, err = ioutil.ReadAll(resp.Body) + return err + } + + return fmt.Errorf("unable to handle request") +} + +// Recv will try to deserialize the last received response into the given msg. +func (client *httpClient) Recv(msg interface{}) error { + return json.Unmarshal(client.lastRes, &msg) +} + +// Close is not necessary for httpClient +func (client *httpClient) Close() { +} + +// SupportedModules will return the collection of offered RPC modules. +func (client *httpClient) SupportedModules() (map[string]string, error) { + return SupportedModules(client) +} diff --git a/rpc/ipc.go b/rpc/ipc.go new file mode 100644 index 000000000..b87bfcbd7 --- /dev/null +++ b/rpc/ipc.go @@ -0,0 +1,84 @@ +// 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 <http://www.gnu.org/licenses/>. + +package rpc + +import ( + "encoding/json" + "net" +) + +// CreateIPCListener creates an listener, on Unix platforms this is a unix socket, on Windows this is a named pipe +func CreateIPCListener(endpoint string) (net.Listener, error) { + return ipcListen(endpoint) +} + +// ipcClient represent an IPC RPC client. It will connect to a given endpoint and tries to communicate with a node using +// JSON serialization. +type ipcClient struct { + endpoint string + conn net.Conn + out *json.Encoder + in *json.Decoder +} + +// NewIPCClient create a new IPC client that will connect on the given endpoint. Messages are JSON encoded and encoded. +// On Unix it assumes the endpoint is the full path to a unix socket, and Windows the endpoint is an identifier for a +// named pipe. +func NewIPCClient(endpoint string) (*ipcClient, error) { + conn, err := newIPCConnection(endpoint) + if err != nil { + return nil, err + } + return &ipcClient{endpoint: endpoint, conn: conn, in: json.NewDecoder(conn), out: json.NewEncoder(conn)}, nil +} + +// Send will serialize the given message and send it to the server. +// When sending the message fails it will try to reconnect once and send the message again. +func (client *ipcClient) Send(msg interface{}) error { + if err := client.out.Encode(msg); err == nil { + return nil + } + + // retry once + client.conn.Close() + + conn, err := newIPCConnection(client.endpoint) + if err != nil { + return err + } + + client.conn = conn + client.in = json.NewDecoder(conn) + client.out = json.NewEncoder(conn) + + return client.out.Encode(msg) +} + +// Recv will read a message from the connection and tries to parse it. It assumes the received message is JSON encoded. +func (client *ipcClient) Recv(msg interface{}) error { + return client.in.Decode(&msg) +} + +// Close will close the underlying IPC connection +func (client *ipcClient) Close() { + client.conn.Close() +} + +// SupportedModules will return the collection of offered RPC modules. +func (client *ipcClient) SupportedModules() (map[string]string, error) { + return SupportedModules(client) +} diff --git a/rpc/api/web3_args.go b/rpc/ipc_unix.go index 9e39f7130..310286e96 100644 --- a/rpc/api/web3_args.go +++ b/rpc/ipc_unix.go @@ -14,32 +14,32 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package api +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris -import ( - "encoding/json" +package rpc - "github.com/ethereum/go-ethereum/rpc/shared" +import ( + "net" + "os" + "path/filepath" ) -type Sha3Args struct { - Data string -} - -func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) { - var obj []interface{} - if err := json.Unmarshal(b, &obj); err != nil { - return shared.NewDecodeParamError(err.Error()) +// ipcListen will create a Unix socket on the given endpoint. +func ipcListen(endpoint string) (net.Listener, error) { + // Ensure the IPC path exists and remove any previous leftover + if err := os.MkdirAll(filepath.Dir(endpoint), 0751); err != nil { + return nil, err } - - if len(obj) < 1 { - return shared.NewInsufficientParamsError(len(obj), 1) + os.Remove(endpoint) + l, err := net.Listen("unix", endpoint) + if err != nil { + return nil, err } + os.Chmod(endpoint, 0600) + return l, nil +} - argstr, ok := obj[0].(string) - if !ok { - return shared.NewInvalidTypeError("data", "is not a string") - } - args.Data = argstr - return nil +// newIPCConnection will connect to a Unix socket on the given endpoint. +func newIPCConnection(endpoint string) (net.Conn, error) { + return net.DialUnix("unix", nil, &net.UnixAddr{endpoint, "unix"}) } diff --git a/rpc/comms/ipc_windows.go b/rpc/ipc_windows.go index e25fba253..1d4672ad2 100644 --- a/rpc/comms/ipc_windows.go +++ b/rpc/ipc_windows.go @@ -16,21 +16,16 @@ // +build windows -package comms +package rpc import ( "fmt" "io" "net" - "os" "sync" "syscall" "time" "unsafe" - - "github.com/ethereum/go-ethereum/rpc/codec" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/rpc/useragent" ) var ( @@ -649,49 +644,12 @@ func timeout(addr string) PipeError { return PipeError{fmt.Sprintf("Pipe IO timed out waiting for '%s'", addr), true} } -func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) { - c, err := Dial(cfg.Endpoint) - if err != nil { - return nil, err - } - - coder := codec.New(c) - msg := shared.Request{ - Id: 0, - Method: useragent.EnableUserAgentMethod, - Jsonrpc: shared.JsonRpcVersion, - Params: []byte("[]"), - } - - coder.WriteResponse(msg) - coder.Recv() - - return &ipcClient{cfg.Endpoint, c, codec, coder}, nil -} - -func (self *ipcClient) reconnect() error { - c, err := Dial(self.endpoint) - if err == nil { - self.coder = self.codec.New(c) - - req := shared.Request{ - Id: 0, - Method: useragent.EnableUserAgentMethod, - Jsonrpc: shared.JsonRpcVersion, - Params: []byte("[]"), - } - self.coder.WriteResponse(req) - self.coder.Recv() - } - return err +// ipcListen will create a named pipe on the given endpoint. +func ipcListen(endpoint string) (net.Listener, error) { + return Listen(endpoint) } -func ipcListen(cfg IpcConfig) (net.Listener, error) { - os.Remove(cfg.Endpoint) // in case it still exists from a previous run - l, err := Listen(cfg.Endpoint) - if err != nil { - return nil, err - } - os.Chmod(cfg.Endpoint, 0600) - return l, nil +// newIPCConnection will connect to a named pipe with the given endpoint as name. +func newIPCConnection(endpoint string) (net.Conn, error) { + return Dial(endpoint) } diff --git a/rpc/javascript.go b/rpc/javascript.go new file mode 100644 index 000000000..d147aa045 --- /dev/null +++ b/rpc/javascript.go @@ -0,0 +1,414 @@ +// 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 <http://www.gnu.org/licenses/>. + +package rpc + +var ( + // Holds geth specific RPC extends which can be used to extend web3 + WEB3Extensions = map[string]string{ + "personal": Personal_JS, + "txpool": TxPool_JS, + "admin": Admin_JS, + "db": Db_JS, + "eth": Eth_JS, + "miner": Miner_JS, + "debug": Debug_JS, + "net": Net_JS, + } +) + +const Personal_JS = ` +web3._extend({ + property: 'personal', + methods: + [ + new web3._extend.Method({ + name: 'newAccount', + call: 'personal_newAccount', + params: 1, + outputFormatter: web3._extend.utils.toAddress + }), + new web3._extend.Method({ + name: 'unlockAccount', + call: 'personal_unlockAccount', + params: 3, + }), + new web3._extend.Method({ + name: 'lockAccount', + call: 'personal_lockAccount', + params: 1 + }) + ], + properties: + [ + new web3._extend.Property({ + name: 'listAccounts', + getter: 'personal_listAccounts' + }) + ] +}); +` + +const TxPool_JS = ` +web3._extend({ + property: 'txpool', + methods: + [ + ], + properties: + [ + new web3._extend.Property({ + name: 'status', + getter: 'txpool_status' + outputFormatter: function(status) { + status.pending = web3._extend.utils.toDecimal(status.pending); + status.queued = web3._extend.utils.toDecimal(status.queued); + return status; + } + }) + ] +}); +` + +const Admin_JS = ` +web3._extend({ + property: 'admin', + methods: + [ + new web3._extend.Method({ + name: 'addPeer', + call: 'admin_addPeer', + params: 1 + }), + new web3._extend.Method({ + name: 'exportChain', + call: 'admin_exportChain', + params: 1, + inputFormatter: [null] + }), + new web3._extend.Method({ + name: 'importChain', + call: 'admin_importChain', + params: 1 + }), + new web3._extend.Method({ + name: 'sleepBlocks', + call: 'admin_sleepBlocks', + params: 2 + }), + new web3._extend.Method({ + name: 'verbosity', + call: 'admin_verbosity', + params: 1, + inputFormatter: [web3._extend.utils.fromDecimal] + }), + new web3._extend.Method({ + name: 'setSolc', + call: 'admin_setSolc', + params: 1 + }), + new web3._extend.Method({ + name: 'startRPC', + call: 'admin_startRPC', + params: 4 + }), + new web3._extend.Method({ + name: 'stopRPC', + call: 'admin_stopRPC', + params: 0 + }), + new web3._extend.Method({ + name: 'startWS', + call: 'admin_startWS', + params: 4 + }), + new web3._extend.Method({ + name: 'stopWS', + call: 'admin_stopWS', + params: 0 + }), + new web3._extend.Method({ + name: 'setGlobalRegistrar', + call: 'admin_setGlobalRegistrar', + params: 2 + }), + new web3._extend.Method({ + name: 'setHashReg', + call: 'admin_setHashReg', + params: 2 + }), + new web3._extend.Method({ + name: 'setUrlHint', + call: 'admin_setUrlHint', + params: 2 + }), + new web3._extend.Method({ + name: 'saveInfo', + call: 'admin_saveInfo', + params: 2 + }), + new web3._extend.Method({ + name: 'register', + call: 'admin_register', + params: 3 + }), + new web3._extend.Method({ + name: 'registerUrl', + call: 'admin_registerUrl', + params: 3 + }), + new web3._extend.Method({ + name: 'startNatSpec', + call: 'admin_startNatSpec', + params: 0 + }), + new web3._extend.Method({ + name: 'stopNatSpec', + call: 'admin_stopNatSpec', + params: 0 + }), + new web3._extend.Method({ + name: 'getContractInfo', + call: 'admin_getContractInfo', + params: 1 + }), + new web3._extend.Method({ + name: 'httpGet', + call: 'admin_httpGet', + params: 2 + }) + ], + properties: + [ + new web3._extend.Property({ + name: 'nodeInfo', + getter: 'admin_nodeInfo' + }), + new web3._extend.Property({ + name: 'peers', + getter: 'admin_peers' + }), + new web3._extend.Property({ + name: 'datadir', + getter: 'admin_datadir' + }) + ] +}); +` + +const Db_JS = ` +web3._extend({ + property: 'db', + methods: + [ + ], + properties: + [ + ] +}); +` + +const Eth_JS = ` +web3._extend({ + property: 'eth', + methods: + [ + new web3._extend.Method({ + name: 'sign', + call: 'eth_sign', + params: 2, + inputFormatter: [web3._extend.utils.toAddress, null] + }), + new web3._extend.Method({ + name: 'resend', + call: 'eth_resend', + params: 3, + inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal] + }), + new web3._extend.Method({ + name: 'getNatSpec', + call: 'eth_getNatSpec', + params: 1, + inputFormatter: [web3._extend.formatters.inputTransactionFormatter] + }), + new web3._extend.Method({ + name: 'signTransaction', + call: 'eth_signTransaction', + params: 1, + inputFormatter: [web3._extend.formatters.inputTransactionFormatter] + }), + new web3._extend.Method({ + name: 'submitTransaction', + call: 'eth_submitTransaction', + params: 1, + inputFormatter: [web3._extend.formatters.inputTransactionFormatter] + }) + ], + properties: + [ + new web3._extend.Property({ + name: 'pendingTransactions', + getter: 'eth_pendingTransactions' + }) + ] +}); +` + +const Net_JS = ` +web3._extend({ + property: 'net', + methods: + [ + new web3._extend.Method({ + name: 'addPeer', + call: 'net_addPeer', + params: 1 + }) + ], + properties: + [ + new web3._extend.Property({ + name: 'version', + getter: 'net_version' + }) + ] +}); +` + +const Debug_JS = ` +web3._extend({ + property: 'debug', + methods: + [ + new web3._extend.Method({ + name: 'printBlock', + call: 'debug_printBlock', + params: 1 + }), + new web3._extend.Method({ + name: 'getBlockRlp', + call: 'debug_getBlockRlp', + params: 1 + }), + new web3._extend.Method({ + name: 'setHead', + call: 'debug_setHead', + params: 1 + }), + new web3._extend.Method({ + name: 'processBlock', + call: 'debug_processBlock', + params: 1 + }), + new web3._extend.Method({ + name: 'seedHash', + call: 'debug_seedHash', + params: 1 + }), + new web3._extend.Method({ + name: 'dumpBlock', + call: 'debug_dumpBlock', + params: 1 + }), + new web3._extend.Method({ + name: 'metrics', + call: 'debug_metrics', + params: 1 + }) + ], + properties: + [ + ] +}); +` + +const Miner_JS = ` +web3._extend({ + property: 'miner', + methods: + [ + new web3._extend.Method({ + name: 'start', + call: 'miner_start', + params: 1 + }), + new web3._extend.Method({ + name: 'stop', + call: 'miner_stop', + params: 1 + }), + new web3._extend.Method({ + name: 'setEtherbase', + call: 'miner_setEtherbase', + params: 1, + inputFormatter: [web3._extend.formatters.formatInputInt], + outputFormatter: web3._extend.formatters.formatOutputBool + }), + new web3._extend.Method({ + name: 'setExtra', + call: 'miner_setExtra', + params: 1 + }), + new web3._extend.Method({ + name: 'setGasPrice', + call: 'miner_setGasPrice', + params: 1, + inputFormatter: [web3._extend.utils.fromDecial] + }), + new web3._extend.Method({ + name: 'startAutoDAG', + call: 'miner_startAutoDAG', + params: 0 + }), + new web3._extend.Method({ + name: 'stopAutoDAG', + call: 'miner_stopAutoDAG', + params: 0 + }), + new web3._extend.Method({ + name: 'makeDAG', + call: 'miner_makeDAG', + params: 1, + inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter] + }) + ], + properties: + [ + new web3._extend.Property({ + name: 'hashrate', + getter: 'miner_hashrate', + outputFormatter: web3._extend.utils.toDecimal + }) + ] +}); +` + +const Shh_JS = ` +web3._extend({ + property: 'shh', + methods: + [ + + ], + properties: + [ + new web3._extend.Property({ + name: 'version', + getter: 'shh_version' + }) + ] +}); +` diff --git a/rpc/jeth.go b/rpc/jeth.go deleted file mode 100644 index b195a4965..000000000 --- a/rpc/jeth.go +++ /dev/null @@ -1,324 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package rpc - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/jsre" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" - "github.com/ethereum/go-ethereum/rpc/comms" - "github.com/ethereum/go-ethereum/rpc/shared" - "github.com/ethereum/go-ethereum/rpc/useragent" - "github.com/ethereum/go-ethereum/xeth" - - "github.com/robertkrimen/otto" -) - -type Jeth struct { - ethApi shared.EthereumApi - re *jsre.JSRE - client comms.EthereumClient - fe xeth.Frontend -} - -func NewJeth(ethApi shared.EthereumApi, re *jsre.JSRE, client comms.EthereumClient, fe xeth.Frontend) *Jeth { - return &Jeth{ethApi, re, client, fe} -} - -func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) { - m := shared.NewRpcErrorResponse(id, shared.JsonRpcVersion, code, fmt.Errorf(msg)) - errObj, _ := json.Marshal(m.Error) - errRes, _ := json.Marshal(m) - - call.Otto.Run("ret_error = " + string(errObj)) - res, _ := call.Otto.Run("ret_response = " + string(errRes)) - - return res -} - -// UnlockAccount asks the user for the password and than executes the jeth.UnlockAccount callback in the jsre -func (self *Jeth) UnlockAccount(call otto.FunctionCall) (response otto.Value) { - var cmd, account, passwd string - timeout := int64(300) - var ok bool - - if len(call.ArgumentList) == 0 { - fmt.Println("expected address of account to unlock") - return otto.FalseValue() - } - - if len(call.ArgumentList) >= 1 { - if accountExport, err := call.Argument(0).Export(); err == nil { - if account, ok = accountExport.(string); ok { - if len(call.ArgumentList) == 1 { - fmt.Printf("Unlock account %s\n", account) - passwd, err = utils.PromptPassword("Passphrase: ", true) - if err != nil { - return otto.FalseValue() - } - } - } - } - } - if len(call.ArgumentList) >= 2 { - if passwdExport, err := call.Argument(1).Export(); err == nil { - passwd, _ = passwdExport.(string) - } - } - - if len(call.ArgumentList) >= 3 { - if timeoutExport, err := call.Argument(2).Export(); err == nil { - timeout, _ = timeoutExport.(int64) - } - } - - cmd = fmt.Sprintf("jeth.unlockAccount('%s', '%s', %d)", account, passwd, timeout) - if val, err := call.Otto.Run(cmd); err == nil { - return val - } - - return otto.FalseValue() -} - -// NewAccount asks the user for the password and than executes the jeth.newAccount callback in the jsre -func (self *Jeth) NewAccount(call otto.FunctionCall) (response otto.Value) { - if len(call.ArgumentList) == 0 { - passwd, err := utils.PromptPassword("Passphrase: ", true) - if err != nil { - return otto.FalseValue() - } - passwd2, err := utils.PromptPassword("Repeat passphrase: ", true) - if err != nil { - return otto.FalseValue() - } - - if passwd != passwd2 { - fmt.Println("Passphrases don't match") - return otto.FalseValue() - } - - cmd := fmt.Sprintf("jeth.newAccount('%s')", passwd) - if val, err := call.Otto.Run(cmd); err == nil { - return val - } - } else { - fmt.Println("New account doesn't expect argument(s), you will be prompted for a password") - } - - return otto.FalseValue() -} - -func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) { - reqif, err := call.Argument(0).Export() - if err != nil { - return self.err(call, -32700, err.Error(), nil) - } - - jsonreq, err := json.Marshal(reqif) - var reqs []shared.Request - batch := true - err = json.Unmarshal(jsonreq, &reqs) - if err != nil { - reqs = make([]shared.Request, 1) - err = json.Unmarshal(jsonreq, &reqs[0]) - batch = false - } - - call.Otto.Set("response_len", len(reqs)) - call.Otto.Run("var ret_response = new Array(response_len);") - - for i, req := range reqs { - var respif interface{} - err := self.client.Send(&req) - if err != nil { - return self.err(call, -32603, err.Error(), req.Id) - } - - recv: - respif, err = self.client.Recv() - if err != nil { - return self.err(call, -32603, err.Error(), req.Id) - } - - agentreq, isRequest := respif.(*shared.Request) - if isRequest { - self.handleRequest(agentreq) - goto recv // receive response after agent interaction - } - - sucres, isSuccessResponse := respif.(*shared.SuccessResponse) - errres, isErrorResponse := respif.(*shared.ErrorResponse) - if !isSuccessResponse && !isErrorResponse { - return self.err(call, -32603, fmt.Sprintf("Invalid response type (%T)", respif), req.Id) - } - - call.Otto.Set("ret_jsonrpc", shared.JsonRpcVersion) - call.Otto.Set("ret_id", req.Id) - - var res []byte - if isSuccessResponse { - res, err = json.Marshal(sucres.Result) - } else if isErrorResponse { - res, err = json.Marshal(errres.Error) - } - - call.Otto.Set("ret_result", string(res)) - call.Otto.Set("response_idx", i) - response, err = call.Otto.Run(` - ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) }; - `) - } - - if !batch { - call.Otto.Run("ret_response = ret_response[0];") - } - - if call.Argument(1).IsObject() { - call.Otto.Set("callback", call.Argument(1)) - call.Otto.Run(` - if (Object.prototype.toString.call(callback) == '[object Function]') { - callback(null, ret_response); - } - `) - } - - return -} - -// handleRequest will handle user agent requests by interacting with the user and sending -// the user response back to the geth service -func (self *Jeth) handleRequest(req *shared.Request) bool { - var err error - var args []interface{} - if err = json.Unmarshal(req.Params, &args); err != nil { - glog.V(logger.Info).Infof("Unable to parse agent request - %v\n", err) - return false - } - - switch req.Method { - case useragent.AskPasswordMethod: - return self.askPassword(req.Id, req.Jsonrpc, args) - case useragent.ConfirmTransactionMethod: - return self.confirmTransaction(req.Id, req.Jsonrpc, args) - } - - return false -} - -// askPassword will ask the user to supply the password for a given account -func (self *Jeth) askPassword(id interface{}, jsonrpc string, args []interface{}) bool { - var err error - var passwd string - if len(args) >= 1 { - if account, ok := args[0].(string); ok { - fmt.Printf("Unlock account %s\n", account) - } else { - return false - } - } - passwd, err = utils.PromptPassword("Passphrase: ", true) - - if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil { - glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err) - } - - return err == nil -} - -func (self *Jeth) confirmTransaction(id interface{}, jsonrpc string, args []interface{}) bool { - // Accept all tx which are send from this console - return self.client.Send(shared.NewRpcResponse(id, jsonrpc, true, nil)) == nil -} - -// throwJSExeception panics on an otto value, the Otto VM will then throw msg as a javascript error. -func throwJSExeception(msg interface{}) otto.Value { - p, _ := otto.ToValue(msg) - panic(p) - return p -} - -// Sleep will halt the console for arg[0] seconds. -func (self *Jeth) Sleep(call otto.FunctionCall) (response otto.Value) { - if len(call.ArgumentList) >= 1 { - if call.Argument(0).IsNumber() { - sleep, _ := call.Argument(0).ToInteger() - time.Sleep(time.Duration(sleep) * time.Second) - return otto.TrueValue() - } - } - return throwJSExeception("usage: sleep(<sleep in seconds>)") -} - -// SleepBlocks will wait for a specified number of new blocks or max for a -// given of seconds. sleepBlocks(nBlocks[, maxSleep]). -func (self *Jeth) SleepBlocks(call otto.FunctionCall) (response otto.Value) { - nBlocks := int64(0) - maxSleep := int64(9999999999999999) // indefinitely - - nArgs := len(call.ArgumentList) - - if nArgs == 0 { - throwJSExeception("usage: sleepBlocks(<n blocks>[, max sleep in seconds])") - } - - if nArgs >= 1 { - if call.Argument(0).IsNumber() { - nBlocks, _ = call.Argument(0).ToInteger() - } else { - throwJSExeception("expected number as first argument") - } - } - - if nArgs >= 2 { - if call.Argument(1).IsNumber() { - maxSleep, _ = call.Argument(1).ToInteger() - } else { - throwJSExeception("expected number as second argument") - } - } - - // go through the console, this will allow web3 to call the appropriate - // callbacks if a delayed response or notification is received. - currentBlockNr := func() int64 { - result, err := call.Otto.Run("eth.blockNumber") - if err != nil { - throwJSExeception(err.Error()) - } - blockNr, err := result.ToInteger() - if err != nil { - throwJSExeception(err.Error()) - } - return blockNr - } - - targetBlockNr := currentBlockNr() + nBlocks - deadline := time.Now().Add(time.Duration(maxSleep) * time.Second) - - for time.Now().Before(deadline) { - if currentBlockNr() >= targetBlockNr { - return otto.TrueValue() - } - time.Sleep(time.Second) - } - - return otto.FalseValue() -} diff --git a/rpc/v2/json.go b/rpc/json.go index 9208e2d37..8bdb4665d 100644 --- a/rpc/v2/json.go +++ b/rpc/json.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package v2 +package rpc import ( "encoding/json" @@ -37,7 +37,7 @@ const ( ) // JSON-RPC request -type jsonRequest struct { +type JSONRequest struct { Method string `json:"method"` Version string `json:"jsonrpc"` Id *int64 `json:"id,omitempty"` @@ -45,24 +45,24 @@ type jsonRequest struct { } // JSON-RPC response -type jsonSuccessResponse struct { +type JSONSuccessResponse struct { Version string `json:"jsonrpc"` Id int64 `json:"id"` Result interface{} `json:"result,omitempty"` } // JSON-RPC error object -type jsonError struct { +type JSONError struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data,omitempty"` } // JSON-RPC error response -type jsonErrResponse struct { +type JSONErrResponse struct { Version string `json:"jsonrpc"` Id *int64 `json:"id,omitempty"` - Error jsonError `json:"error"` + Error JSONError `json:"error"` } // JSON-RPC notification payload @@ -85,7 +85,7 @@ type jsonCodec struct { isClosed int32 d *json.Decoder e *json.Encoder - req jsonRequest + req JSONRequest rw io.ReadWriteCloser } @@ -126,7 +126,7 @@ func (c *jsonCodec) ReadRequestHeaders() ([]rpcRequest, bool, RPCError) { // parseRequest will parse a single request from the given RawMessage. It will return the parsed request, an indication // if the request was a batch or an error when the request could not be parsed. func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, RPCError) { - var in jsonRequest + var in JSONRequest if err := json.Unmarshal(incomingMsg, &in); err != nil { return nil, false, &invalidMessageError{err.Error()} } @@ -175,7 +175,7 @@ func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, RPCError) { // parseBatchRequest will parse a batch request into a collection of requests from the given RawMessage, an indication // if the request was a batch or an error when the request could not be read. func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, RPCError) { - var in []jsonRequest + var in []JSONRequest if err := json.Unmarshal(incomingMsg, &in); err != nil { return nil, false, &invalidMessageError{err.Error()} } @@ -296,21 +296,21 @@ func parsePositionalArguments(args json.RawMessage, argTypes []reflect.Type) ([] // CreateResponse will create a JSON-RPC success response with the given id and reply as result. func (c *jsonCodec) CreateResponse(id int64, reply interface{}) interface{} { if isHexNum(reflect.TypeOf(reply)) { - return &jsonSuccessResponse{Version: jsonRPCVersion, Id: id, Result: fmt.Sprintf(`%#x`, reply)} + return &JSONSuccessResponse{Version: jsonRPCVersion, Id: id, Result: fmt.Sprintf(`%#x`, reply)} } - return &jsonSuccessResponse{Version: jsonRPCVersion, Id: id, Result: reply} + return &JSONSuccessResponse{Version: jsonRPCVersion, Id: id, Result: reply} } // CreateErrorResponse will create a JSON-RPC error response with the given id and error. func (c *jsonCodec) CreateErrorResponse(id *int64, err RPCError) interface{} { - return &jsonErrResponse{Version: jsonRPCVersion, Id: id, Error: jsonError{Code: err.Code(), Message: err.Error()}} + return &JSONErrResponse{Version: jsonRPCVersion, Id: id, Error: JSONError{Code: err.Code(), Message: err.Error()}} } // CreateErrorResponseWithInfo will create a JSON-RPC error response with the given id and error. // info is optional and contains additional information about the error. When an empty string is passed it is ignored. func (c *jsonCodec) CreateErrorResponseWithInfo(id *int64, err RPCError, info interface{}) interface{} { - return &jsonErrResponse{Version: jsonRPCVersion, Id: id, - Error: jsonError{Code: err.Code(), Message: err.Error(), Data: info}} + return &JSONErrResponse{Version: jsonRPCVersion, Id: id, + Error: JSONError{Code: err.Code(), Message: err.Error(), Data: info}} } // CreateNotification will create a JSON-RPC notification with the given subscription id and event as params. diff --git a/rpc/v2/json_test.go b/rpc/json_test.go index dc8a345d7..39aae1f54 100644 --- a/rpc/v2/json_test.go +++ b/rpc/json_test.go @@ -1,4 +1,4 @@ -package v2 +package rpc import ( "bufio" diff --git a/rpc/v2/server.go b/rpc/server.go index 4c04f04d2..0b93a4e64 100644 --- a/rpc/v2/server.go +++ b/rpc/server.go @@ -14,23 +14,37 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package v2 +package rpc import ( "fmt" "reflect" - "runtime" + "sync/atomic" + "time" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "golang.org/x/net/context" + "gopkg.in/fatih/set.v0" +) + +const ( + stopPendingRequestTimeout = 3 * time.Second // give pending requests stopPendingRequestTimeout the time to finish when the server is stopped + + DefaultIpcApis = "admin,eth,debug,miner,net,shh,txpool,personal,web3" + DefaultHttpRpcApis = "eth,net,web3" ) // NewServer will create a new server instance with no registered handlers. func NewServer() *Server { - server := &Server{services: make(serviceRegistry), subscriptions: make(subscriptionRegistry)} + server := &Server{ + services: make(serviceRegistry), + subscriptions: make(subscriptionRegistry), + codecs: set.New(), + run: 1, + } // register a default service which will provide meta information about the RPC service such as the services and // methods it offers. @@ -124,14 +138,37 @@ func (s *Server) ServeCodec(codec ServerCodec) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - for { + s.codecsMu.Lock() + if atomic.LoadInt32(&s.run) != 1 { // server stopped + s.codecsMu.Unlock() + return + } + s.codecs.Add(codec) + s.codecsMu.Unlock() + + for atomic.LoadInt32(&s.run) == 1 { reqs, batch, err := s.readRequest(codec) + if err != nil { glog.V(logger.Debug).Infof("%v\n", err) codec.Write(codec.CreateErrorResponse(nil, err)) break } + if atomic.LoadInt32(&s.run) != 1 { + err = &shutdownError{} + if batch { + resps := make([]interface{}, len(reqs)) + for i, r := range reqs { + resps[i] = codec.CreateErrorResponse(&r.id, err) + } + codec.Write(resps) + } else { + codec.Write(codec.CreateErrorResponse(&reqs[0].id, err)) + } + break + } + if batch { go s.execBatch(ctx, codec, reqs) } else { @@ -140,6 +177,22 @@ func (s *Server) ServeCodec(codec ServerCodec) { } } +// Stop will stop reading new requests, wait for stopPendingRequestTimeout to allow pending requests to finish, +// close all codecs which will cancels pending requests/subscriptions. +func (s *Server) Stop() { + if atomic.CompareAndSwapInt32(&s.run, 1, 0) { + glog.V(logger.Debug).Infoln("RPC Server shutdown initiatied") + time.AfterFunc(stopPendingRequestTimeout, func() { + s.codecsMu.Lock() + defer s.codecsMu.Unlock() + s.codecs.Each(func(c interface{}) bool { + c.(ServerCodec).Close() + return true + }) + }) + } +} + // sendNotification will create a notification from the given event by serializing member fields of the event. // It will then send the notification to the client, when it fails the codec is closed. When the event has multiple // fields an array of values is returned. diff --git a/rpc/v2/server_test.go b/rpc/server_test.go index f250c184f..5b91fe42a 100644 --- a/rpc/v2/server_test.go +++ b/rpc/server_test.go @@ -1,4 +1,20 @@ -package v2 +// 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 <http://www.gnu.org/licenses/>. + +package rpc import ( "encoding/json" @@ -91,7 +107,7 @@ func (c *ServerTestCodec) ReadRequestHeaders() ([]rpcRequest, bool, RPCError) { c.counter += 1 if c.counter == 1 { - var req jsonRequest + var req JSONRequest json.Unmarshal(c.input, &req) return []rpcRequest{rpcRequest{id: *req.Id, isPubSub: false, service: "test", method: req.Method, params: req.Payload}}, false, nil } @@ -157,16 +173,16 @@ func (c *ServerTestCodec) ParseRequestArguments(argTypes []reflect.Type, payload } func (c *ServerTestCodec) CreateResponse(id int64, reply interface{}) interface{} { - return &jsonSuccessResponse{Version: jsonRPCVersion, Id: id, Result: reply} + return &JSONSuccessResponse{Version: jsonRPCVersion, Id: id, Result: reply} } func (c *ServerTestCodec) CreateErrorResponse(id *int64, err RPCError) interface{} { - return &jsonErrResponse{Version: jsonRPCVersion, Id: id, Error: jsonError{Code: err.Code(), Message: err.Error()}} + return &JSONErrResponse{Version: jsonRPCVersion, Id: id, Error: JSONError{Code: err.Code(), Message: err.Error()}} } func (c *ServerTestCodec) CreateErrorResponseWithInfo(id *int64, err RPCError, info interface{}) interface{} { - return &jsonErrResponse{Version: jsonRPCVersion, Id: id, - Error: jsonError{Code: err.Code(), Message: err.Error(), Data: info}} + return &JSONErrResponse{Version: jsonRPCVersion, Id: id, + Error: JSONError{Code: err.Code(), Message: err.Error(), Data: info}} } func (c *ServerTestCodec) CreateNotification(subid string, event interface{}) interface{} { @@ -203,7 +219,7 @@ func TestServerMethodExecution(t *testing.T) { } id := int64(12345) - req := jsonRequest{ + req := JSONRequest{ Method: "echo", Version: "2.0", Id: &id, @@ -233,7 +249,7 @@ func TestServerMethodWithCtx(t *testing.T) { } id := int64(12345) - req := jsonRequest{ + req := JSONRequest{ Method: "echoWithCtx", Version: "2.0", Id: &id, diff --git a/rpc/shared/errors.go b/rpc/shared/errors.go deleted file mode 100644 index d5a7011f9..000000000 --- a/rpc/shared/errors.go +++ /dev/null @@ -1,126 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -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 NotReadyError struct { - Resource string -} - -func (e *NotReadyError) Error() string { - return fmt.Sprintf("%s not ready", e.Resource) -} - -func NewNotReadyError(resource string) *NotReadyError { - return &NotReadyError{ - Resource: resource, - } -} - -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, - } -} diff --git a/rpc/shared/types.go b/rpc/shared/types.go deleted file mode 100644 index db328234d..000000000 --- a/rpc/shared/types.go +++ /dev/null @@ -1,108 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package shared - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" -) - -// Ethereum RPC API interface -type EthereumApi interface { - // API identifier - Name() string - - // API version - ApiVersion() string - - // Execute the given request and returns the response or an error - Execute(*Request) (interface{}, error) - - // List of supported RCP methods this API provides - Methods() []string -} - -// RPC request -type Request struct { - Id interface{} `json:"id"` - Jsonrpc string `json:"jsonrpc"` - Method string `json:"method"` - Params json.RawMessage `json:"params"` -} - -// RPC response -type Response struct { - Id interface{} `json:"id"` - Jsonrpc string `json:"jsonrpc"` -} - -// RPC success response -type SuccessResponse struct { - Id interface{} `json:"id"` - Jsonrpc string `json:"jsonrpc"` - Result interface{} `json:"result"` -} - -// RPC error response -type ErrorResponse struct { - Id interface{} `json:"id"` - Jsonrpc string `json:"jsonrpc"` - Error *ErrorObject `json:"error"` -} - -// RPC error response details -type ErrorObject struct { - Code int `json:"code"` - Message string `json:"message"` - // Data interface{} `json:"data"` -} - -// Create RPC error response, this allows for custom error codes -func NewRpcErrorResponse(id interface{}, jsonrpcver string, errCode int, err error) *ErrorResponse { - jsonerr := &ErrorObject{errCode, err.Error()} - response := ErrorResponse{Jsonrpc: jsonrpcver, Id: id, Error: jsonerr} - - glog.V(logger.Detail).Infof("Generated error response: %s", response) - return &response -} - -// Create RPC response -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 *NotReadyError: - jsonerr := &ErrorObject{-32000, 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 -} diff --git a/rpc/shared/utils.go b/rpc/shared/utils.go deleted file mode 100644 index b13e9eb1b..000000000 --- a/rpc/shared/utils.go +++ /dev/null @@ -1,43 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package shared - -import "strings" - -const ( - AdminApiName = "admin" - EthApiName = "eth" - DbApiName = "db" - DebugApiName = "debug" - MergedApiName = "merged" - MinerApiName = "miner" - NetApiName = "net" - ShhApiName = "shh" - TxPoolApiName = "txpool" - PersonalApiName = "personal" - Web3ApiName = "web3" - - JsonRpcVersion = "2.0" -) - -var ( - // All API's - AllApis = strings.Join([]string{ - AdminApiName, DbApiName, EthApiName, DebugApiName, MinerApiName, NetApiName, - ShhApiName, TxPoolApiName, PersonalApiName, Web3ApiName, - }, ",") -) diff --git a/rpc/v2/types.go b/rpc/types.go index 8e638726f..02295a022 100644 --- a/rpc/v2/types.go +++ b/rpc/types.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package v2 +package rpc import ( "fmt" @@ -25,6 +25,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/event" + "gopkg.in/fatih/set.v0" ) // API describes the set of methods offered over the RPC interface @@ -75,6 +76,10 @@ type Server struct { services serviceRegistry muSubcriptions sync.Mutex // protects subscriptions subscriptions subscriptionRegistry + + run int32 + codecsMu sync.Mutex + codecs *set.Set } // rpcRequest represents a raw incoming RPC request @@ -350,3 +355,14 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { func (bn *BlockNumber) Int64() int64 { return (int64)(*bn) } + +// Client defines the interface for go client that wants to connect to a geth RPC endpoint +type Client interface { + // SupportedModules returns the collection of API's the server offers + SupportedModules() (map[string]string, error) + + Send(req interface{}) error + Recv(msg interface{}) error + + Close() +} diff --git a/rpc/v2/types_test.go b/rpc/types_test.go index f73a2369e..c2c5c6db6 100644 --- a/rpc/v2/types_test.go +++ b/rpc/types_test.go @@ -1,4 +1,20 @@ -package v2 +// 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 <http://www.gnu.org/licenses/>. + +package rpc import ( "bytes" diff --git a/rpc/useragent/agent.go b/rpc/useragent/agent.go deleted file mode 100644 index df0739e65..000000000 --- a/rpc/useragent/agent.go +++ /dev/null @@ -1,24 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -// package user agent provides frontends and agents which can interact with the user -package useragent - -var ( - AskPasswordMethod = "agent_askPassword" - ConfirmTransactionMethod = "agent_confirmTransaction" - EnableUserAgentMethod = "admin_enableUserAgent" -) diff --git a/rpc/useragent/remote_frontend.go b/rpc/useragent/remote_frontend.go deleted file mode 100644 index 944ab287a..000000000 --- a/rpc/useragent/remote_frontend.go +++ /dev/null @@ -1,166 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -package useragent - -import ( - "encoding/json" - "fmt" - "net" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -// remoteFrontend implements xeth.Frontend and will communicate with an external -// user agent over a connection -type RemoteFrontend struct { - enabled bool - mgr *accounts.Manager - d *json.Decoder - e *json.Encoder - n int -} - -// NewRemoteFrontend creates a new frontend which will interact with an user agent -// over the given connection -func NewRemoteFrontend(conn net.Conn, mgr *accounts.Manager) *RemoteFrontend { - return &RemoteFrontend{false, mgr, json.NewDecoder(conn), json.NewEncoder(conn), 0} -} - -// Enable will enable user interaction -func (fe *RemoteFrontend) Enable() { - fe.enabled = true -} - -func (fe *RemoteFrontend) AskPassword() (string, bool) { - if !fe.enabled { - return "", false - } - - err := fe.send(AskPasswordMethod) - if err != nil { - glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err) - return "", false - } - - passwdRes, err := fe.recv() - if err != nil { - glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err) - return "", false - } - - if passwd, ok := passwdRes.Result.(string); ok { - return passwd, true - } - - return "", false - -} - -// UnlockAccount asks the user agent for the user password and tries to unlock the account. -// It will try 3 attempts before giving up. -func (fe *RemoteFrontend) UnlockAccount(address []byte) bool { - if !fe.enabled { - return false - } - - err := fe.send(AskPasswordMethod, common.Bytes2Hex(address)) - if err != nil { - glog.V(logger.Error).Infof("Unable to send password request to agent - %v\n", err) - return false - } - - passwdRes, err := fe.recv() - if err != nil { - glog.V(logger.Error).Infof("Unable to recv password response from agent - %v\n", err) - return false - } - - if passwd, ok := passwdRes.Result.(string); ok { - err = fe.mgr.Unlock(common.BytesToAddress(address), passwd) - } - - if err == nil { - return true - } - - glog.V(logger.Debug).Infoln("3 invalid account unlock attempts") - return false -} - -// ConfirmTransaction asks the user for approval -func (fe *RemoteFrontend) ConfirmTransaction(tx string) bool { - if !fe.enabled { - return true // backwards compatibility - } - - err := fe.send(ConfirmTransactionMethod, tx) - if err != nil { - glog.V(logger.Error).Infof("Unable to send tx confirmation request to agent - %v\n", err) - return false - } - - confirmResponse, err := fe.recv() - if err != nil { - glog.V(logger.Error).Infof("Unable to recv tx confirmation response from agent - %v\n", err) - return false - } - - if confirmed, ok := confirmResponse.Result.(bool); ok { - return confirmed - } - - return false -} - -// send request to the agent -func (fe *RemoteFrontend) send(method string, params ...interface{}) error { - fe.n += 1 - - p, err := json.Marshal(params) - if err != nil { - glog.V(logger.Info).Infof("Unable to send agent request %v\n", err) - return err - } - - req := shared.Request{ - Method: method, - Jsonrpc: shared.JsonRpcVersion, - Id: fe.n, - Params: p, - } - - return fe.e.Encode(&req) -} - -// recv user response from agent -func (fe *RemoteFrontend) recv() (*shared.SuccessResponse, error) { - var res json.RawMessage - if err := fe.d.Decode(&res); err != nil { - return nil, err - } - - var response shared.SuccessResponse - if err := json.Unmarshal(res, &response); err == nil { - return &response, nil - } - - return nil, fmt.Errorf("Invalid user agent response") -} diff --git a/rpc/v2/utils.go b/rpc/utils.go index ca37924a3..25321c543 100644 --- a/rpc/v2/utils.go +++ b/rpc/utils.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package v2 +package rpc import ( "crypto/rand" @@ -25,6 +25,8 @@ import ( "unicode" "unicode/utf8" + "fmt" + "golang.org/x/net/context" ) @@ -212,3 +214,33 @@ func newSubscriptionId() (string, error) { } return "0x" + hex.EncodeToString(subid[:]), nil } + +// SupportedModules returns the collection of API's that the RPC server offers +// on which the given client connects. +func SupportedModules(client Client) (map[string]string, error) { + req := map[string]interface{}{ + "id": 1, + "method": "rpc_modules", + } + + if err := client.Send(req); err != nil { + return nil, err + } + + var response map[string]interface{} + if err := client.Recv(&response); err != nil { + return nil, err + } + + if payload, ok := response["result"]; ok { + mods := make(map[string]string) + if modules, ok := payload.(map[string]interface{}); ok { + for m, v := range modules { + mods[m] = fmt.Sprintf("%s", v) + } + return mods, nil + } + } + + return nil, fmt.Errorf("unable to retrieve modules") +} diff --git a/rpc/websocket.go b/rpc/websocket.go new file mode 100644 index 000000000..b5bcbf4f6 --- /dev/null +++ b/rpc/websocket.go @@ -0,0 +1,235 @@ +// 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 <http://www.gnu.org/licenses/>. + +package rpc + +import ( + "errors" + "fmt" + "net" + "net/http" + "sync" + + "os" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "golang.org/x/net/websocket" + "gopkg.in/fatih/set.v0" +) + +var ( + wsServerMu sync.Mutex + wsRPCServer *Server + wsListener net.Listener +) + +// wsReaderWriterCloser reads and write payloads from and to a websocket connection. +type wsReaderWriterCloser struct { + c *websocket.Conn +} + +// Read will read incoming payload data into p. +func (rw *wsReaderWriterCloser) Read(p []byte) (int, error) { + return rw.c.Read(p) +} + +// Write writes p to the websocket. +func (rw *wsReaderWriterCloser) Write(p []byte) (int, error) { + return rw.c.Write(p) +} + +// Close closes the websocket connection. +func (rw *wsReaderWriterCloser) Close() error { + return rw.c.Close() +} + +// wsHandler accepts a websocket connection and handles incoming RPC requests. +// Will return when the websocket connection is closed, either by the client or +// server. +func wsHandler(conn *websocket.Conn) { + rwc := &wsReaderWriterCloser{conn} + wsRPCServer.ServeCodec(NewJSONCodec(rwc)) +} + +// wsHandshakeValidator returns a handler that verifies the origin during the +// websocket upgrade process. When a '*' is specified as an allowed origins all +// connections are accepted. +func wsHandshakeValidator(allowedOrigins []string) func(*websocket.Config, *http.Request) error { + origins := set.New() + allowAllOrigins := false + + for _, origin := range allowedOrigins { + if origin == "*" { + allowAllOrigins = true + } + if origin != "" { + origins.Add(origin) + } + } + + // allow localhost if no allowedOrigins are specified + if len(origins.List()) == 0 { + origins.Add("http://localhost") + if hostname, err := os.Hostname(); err == nil { + origins.Add("http://" + hostname) + } + } + + glog.V(logger.Debug).Infof("Allowed origin(s) for WS RPC interface %v\n", origins.List()) + + f := func(cfg *websocket.Config, req *http.Request) error { + origin := req.Header.Get("Origin") + if allowAllOrigins || origins.Has(origin) { + return nil + } + glog.V(logger.Debug).Infof("origin '%s' not allowed on WS-RPC interface\n", origin) + return fmt.Errorf("origin %s not allowed", origin) + } + + return f +} + +// StartWS will start a websocket RPC server on the given address and port. +func StartWS(address string, port int, corsdomains []string, apis []API) error { + wsServerMu.Lock() + defer wsServerMu.Unlock() + + if wsRPCServer != nil { + return fmt.Errorf("WS RPC interface already started on %s", wsListener.Addr()) + } + + rpcServer := NewServer() + for _, api := range apis { + if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil { + return err + } + } + + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", address, port)) + if err != nil { + return err + } + + wsServer := websocket.Server{Handshake: wsHandshakeValidator(corsdomains), Handler: wsHandler} + wsHTTPServer := http.Server{Handler: wsServer} + + go wsHTTPServer.Serve(listener) + + wsListener = listener + wsRPCServer = rpcServer + + return nil +} + +// StopWS stops the running websocket RPC server. +func StopWS() error { + wsServerMu.Lock() + defer wsServerMu.Unlock() + + if wsRPCServer == nil { + return errors.New("HTTP RPC interface not started") + } + + wsListener.Close() + wsRPCServer.Stop() + + wsRPCServer = nil + wsListener = nil + + return nil +} + +// wsClient represents a RPC client that communicates over websockets with a +// RPC server. +type wsClient struct { + endpoint string + connMu sync.Mutex + conn *websocket.Conn +} + +// NewWSClientj creates a new RPC client that communicates with a RPC server +// that is listening on the given endpoint using JSON encoding. +func NewWSClient(endpoint string) (*wsClient, error) { + return &wsClient{endpoint: endpoint}, nil +} + +// connection will return a websocket connection to the RPC server. It will +// (re)connect when necessary. +func (client *wsClient) connection() (*websocket.Conn, error) { + if client.conn != nil { + return client.conn, nil + } + + origin, err := os.Hostname() + if err != nil { + return nil, err + } + + origin = "http://" + origin + client.conn, err = websocket.Dial(client.endpoint, "", origin) + + return client.conn, err +} + +// SupportedModules is the collection of modules the RPC server offers. +func (client *wsClient) SupportedModules() (map[string]string, error) { + return SupportedModules(client) +} + +// Send writes the JSON serialized msg to the websocket. It will create a new +// websocket connection to the server if the client is currently not connected. +func (client *wsClient) Send(msg interface{}) (err error) { + client.connMu.Lock() + defer client.connMu.Unlock() + + var conn *websocket.Conn + if conn, err = client.connection(); err == nil { + if err = websocket.JSON.Send(conn, msg); err != nil { + client.conn.Close() + client.conn = nil + } + } + + return err +} + +// Recv reads a JSON message from the websocket and unmarshals it into msg. +func (client *wsClient) Recv(msg interface{}) (err error) { + client.connMu.Lock() + defer client.connMu.Unlock() + + var conn *websocket.Conn + if conn, err = client.connection(); err == nil { + if err = websocket.JSON.Receive(conn, msg); err != nil { + client.conn.Close() + client.conn = nil + } + } + return +} + +// Close closes the underlaying websocket connection. +func (client *wsClient) Close() { + client.connMu.Lock() + defer client.connMu.Unlock() + + if client.conn != nil { + client.conn.Close() + client.conn = nil + } + +} diff --git a/rpc/xeth.go b/rpc/xeth.go deleted file mode 100644 index 9527a96c0..000000000 --- a/rpc/xeth.go +++ /dev/null @@ -1,77 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -// Package rpc implements the Ethereum JSON-RPC API. -package rpc - -import ( - "encoding/json" - "fmt" - "reflect" - "sync/atomic" - - "github.com/ethereum/go-ethereum/rpc/comms" - "github.com/ethereum/go-ethereum/rpc/shared" -) - -// Xeth is a native API interface to a remote node. -type Xeth struct { - client comms.EthereumClient - reqId uint32 -} - -// NewXeth constructs a new native API interface to a remote node. -func NewXeth(client comms.EthereumClient) *Xeth { - return &Xeth{ - client: client, - } -} - -// Call invokes a method with the given parameters are the remote node. -func (self *Xeth) Call(method string, params []interface{}) (map[string]interface{}, error) { - // Assemble the json RPC request - data, err := json.Marshal(params) - if err != nil { - return nil, err - } - req := &shared.Request{ - Id: atomic.AddUint32(&self.reqId, 1), - Jsonrpc: "2.0", - Method: method, - Params: data, - } - // Send the request over and retrieve the response - if err := self.client.Send(req); err != nil { - return nil, err - } - res, err := self.client.Recv() - if err != nil { - return nil, err - } - // Ensure the response is valid, and extract the results - success, isSuccessResponse := res.(*shared.SuccessResponse) - failure, isFailureResponse := res.(*shared.ErrorResponse) - switch { - case isFailureResponse: - return nil, fmt.Errorf("Method invocation failed: %v", failure.Error) - - case isSuccessResponse: - return success.Result.(map[string]interface{}), nil - - default: - return nil, fmt.Errorf("Invalid response type: %v", reflect.TypeOf(res)) - } -} |