github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/cmd/geth/apicmd.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 package main 17 18 import ( 19 "encoding/json" 20 "errors" 21 "fmt" 22 "math/rand" 23 "strconv" 24 "strings" 25 26 "gopkg.in/urfave/cli.v1" 27 28 "os" 29 30 "github.com/ethereumproject/go-ethereum/node" 31 "github.com/ethereumproject/go-ethereum/rpc" 32 ) 33 34 var ( 35 apiCommand = cli.Command{ 36 Action: execAPI, 37 Name: "api", 38 Usage: "Run any API command", 39 Description: ` 40 The api command allows you to communicate (via IPC) with a running geth instance 41 and run any RPC API method. 42 43 Each parameter should be passed as JSON representation: 44 - no quotations for numbers or booleans, 45 - strings must be correctly quoted, like '"some value"' (quotes must be 46 included in string passed to application), 47 - complex objects could be passed as JSON string. 48 49 Examples: 50 51 $ geth api eth getBlockByNumber 123 true 52 $ geth eth getBlockByNumber '"latest"' true 53 $ geth --chain morden api eth sendTransaction '{"from": "0x396599f365093186742c17aab158bf515e978bc7", "gas": "0x5208", "gasPrice": "0x02540be400", "to": "0xa02cee0fc1d3fb4dde86b79fe93e4140671fd949"}' 54 55 Output will be written to stderr in JSON format. 56 `, 57 } 58 ) 59 60 func execAPI(ctx *cli.Context) error { 61 client, err := getClient(ctx) 62 if err != nil { 63 return err 64 } 65 66 if err := validateArguments(ctx, client); err != nil { 67 return err 68 } 69 70 result, err := callRPC(ctx, client) 71 if err != nil { 72 return err 73 } 74 return prettyPrint(result) 75 } 76 77 func getClient(ctx *cli.Context) (rpc.Client, error) { 78 chainDir := MustMakeChainDataDir(ctx) 79 var uri = "ipc:" + node.DefaultIPCEndpoint(chainDir) 80 return rpc.NewClient(uri) 81 } 82 83 func validateArguments(ctx *cli.Context, client rpc.Client) error { 84 if len(ctx.Args()) < 2 { 85 return fmt.Errorf("api command requires at least 2 arguments (module and method), %d provided", 86 len(ctx.Args())) 87 } 88 modules, err := client.SupportedModules() 89 if err != nil { 90 return err 91 } 92 93 module := ctx.Args()[0] 94 if _, ok := modules[module]; !ok { 95 return fmt.Errorf("unknown API module: %s", module) 96 } 97 98 return nil 99 } 100 101 func callRPC(ctx *cli.Context, client rpc.Client) (interface{}, error) { 102 var ( 103 module = ctx.Args()[0] 104 method = ctx.Args()[1] 105 args = ctx.Args()[2:] 106 ) 107 req := rpc.JSONRequest{ 108 Id: json.RawMessage(strconv.Itoa(rand.Int())), 109 Method: module + "_" + method, 110 Version: "2.0", 111 Payload: json.RawMessage("[" + strings.Join(args, ",") + "]"), 112 } 113 114 if err := client.Send(req); err != nil { 115 return nil, err 116 } 117 118 var res rpc.JSONResponse 119 if err := client.Recv(&res); err != nil { 120 return nil, err 121 } 122 if res.Error != nil { 123 return nil, fmt.Errorf("error in %s_%s: %s (code: %d)", 124 module, method, res.Error.Message, res.Error.Code) 125 } 126 if res.Result != nil { 127 return res.Result, nil 128 } 129 130 return nil, errors.New("no API response") 131 } 132 133 func prettyPrint(result interface{}) error { 134 jsonBytes, err := json.MarshalIndent(result, "", " ") 135 if err != nil { 136 return err 137 } 138 os.Stderr.Write(jsonBytes) 139 return nil 140 }