├── .gitignore ├── EthereumAPI.go ├── EthereumAPI_test.go ├── LICENSE ├── README.md ├── admin.go ├── contants.go ├── db.go ├── debug.go ├── eth.go ├── external.go ├── external_test.go ├── json.go ├── json_test.go ├── miner.go ├── net.go ├── personal.go ├── ssh.go ├── structures.go ├── structures_test.go ├── support.go ├── support_test.go ├── txpool.go └── web3.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | *.db 6 | 7 | # Temp files 8 | *~ 9 | *.kate-swp 10 | *.orig 11 | debug 12 | 13 | # Folders 14 | _obj 15 | _test 16 | bin 17 | pkg 18 | 19 | # Architecture specific extensions/prefixes 20 | *.[568vq] 21 | [568vq].out 22 | 23 | *.cgo1.go 24 | *.cgo2.c 25 | _cgo_defun.c 26 | _cgo_gotypes.go 27 | _cgo_export.* 28 | 29 | _testmain.go 30 | 31 | *.exe 32 | *.test 33 | *.block 34 | *.entry 35 | 36 | .DS_Store 37 | 38 | *.out -------------------------------------------------------------------------------- /EthereumAPI.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | ) 10 | 11 | var ( 12 | /* 13 | C++: http://localhost:8545 14 | Go: http://localhost:8545 15 | Py: http://localhost:4000 16 | */ 17 | 18 | server = "localhost:8545" 19 | ) 20 | 21 | //https://github.com/ethereum/wiki/wiki/JSON-RPC 22 | 23 | func SetServer(newServer string) { 24 | server = newServer 25 | } 26 | 27 | func Call(method string, params interface{}) (*JSON2Response, error) { 28 | j := NewJSON2RequestBlank() 29 | j.Method = method 30 | j.Params = params 31 | j.ID = 1 32 | 33 | postGet := "POST" 34 | 35 | address := fmt.Sprintf("http://%s/", server) 36 | 37 | data, err := j.JSONString() 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | req, err := http.NewRequest(postGet, address, strings.NewReader(data)) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | req.Header.Set("Content-Type", "application/json") 48 | 49 | client := &http.Client{} 50 | resp, err := client.Do(req) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | defer resp.Body.Close() 56 | 57 | body, err := ioutil.ReadAll(resp.Body) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | jResp := new(JSON2Response) 63 | 64 | err = json.Unmarshal(body, jResp) 65 | if err != nil { 66 | return nil, err 67 | } 68 | 69 | return jResp, nil 70 | } 71 | -------------------------------------------------------------------------------- /EthereumAPI_test.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI_test 2 | 3 | import ( 4 | . "github.com/FactomProject/EthereumAPI" 5 | "testing" 6 | ) 7 | 8 | func TestTest(t *testing.T) { 9 | resp, err := Call("bla", nil) 10 | if err != nil { 11 | t.Errorf("Error - %v", err) 12 | } 13 | t.Logf("Resp - %v", resp) 14 | //t.Fail() 15 | } 16 | 17 | func TestEthProtocolVersion(t *testing.T) { 18 | ver, err := EthProtocolVersion() 19 | if err != nil { 20 | t.Errorf("Error - %v", err) 21 | } 22 | t.Logf("ver - %v", ver) 23 | //t.Fail() 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Factom Foundation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ethereum API 2 | =========== 3 | -------------------------------------------------------------------------------- /admin.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/go-ethereum/wiki/Management-APIs#admin 8 | 9 | //TODO: finish 10 | func AdminAddPeer(url string) (interface{}, error) { 11 | resp, err := Call("admin_addPeer", []interface{}{url}) 12 | if err != nil { 13 | return nil, err 14 | } 15 | if resp.Error != nil { 16 | return nil, fmt.Errorf(resp.Error.Message) 17 | } 18 | return resp.Result, nil 19 | } 20 | 21 | //TODO: finish 22 | func AdminDatadir() (interface{}, error) { 23 | resp, err := Call("admin_datadir", nil) 24 | if err != nil { 25 | return nil, err 26 | } 27 | if resp.Error != nil { 28 | return nil, fmt.Errorf(resp.Error.Message) 29 | } 30 | return resp.Result, nil 31 | } 32 | 33 | //TODO: finish 34 | func AdminNodeInfo() (interface{}, error) { 35 | resp, err := Call("admin_nodeInfo", nil) 36 | if err != nil { 37 | return nil, err 38 | } 39 | if resp.Error != nil { 40 | return nil, fmt.Errorf(resp.Error.Message) 41 | } 42 | return resp.Result, nil 43 | } 44 | 45 | //TODO: finish 46 | func AdminPeers() (interface{}, error) { 47 | resp, err := Call("admin_peers", nil) 48 | if err != nil { 49 | return nil, err 50 | } 51 | if resp.Error != nil { 52 | return nil, fmt.Errorf(resp.Error.Message) 53 | } 54 | return resp.Result, nil 55 | } 56 | 57 | //TODO: finish 58 | func AdminSetSolc(path string) (interface{}, error) { 59 | resp, err := Call("admin_setSolc", []interface{}{path}) 60 | if err != nil { 61 | return nil, err 62 | } 63 | if resp.Error != nil { 64 | return nil, fmt.Errorf(resp.Error.Message) 65 | } 66 | return resp.Result, nil 67 | } 68 | 69 | //TODO: finish 70 | func AdminStartRPC(host string, port int64, cors string, apis string) (interface{}, error) { 71 | resp, err := Call("admin_startRPC", []interface{}{host, port, cors, apis}) 72 | if err != nil { 73 | return nil, err 74 | } 75 | if resp.Error != nil { 76 | return nil, fmt.Errorf(resp.Error.Message) 77 | } 78 | return resp.Result, nil 79 | } 80 | 81 | //TODO: finish 82 | func AdminStartWS(host string, port int64, cors string, apis string) (interface{}, error) { 83 | resp, err := Call("admin_startWS", []interface{}{host, port, cors, apis}) 84 | if err != nil { 85 | return nil, err 86 | } 87 | if resp.Error != nil { 88 | return nil, fmt.Errorf(resp.Error.Message) 89 | } 90 | return resp.Result, nil 91 | } 92 | 93 | //TODO: finish 94 | func AdminStopRPC() (interface{}, error) { 95 | resp, err := Call("admin_stopRPC", nil) 96 | if err != nil { 97 | return nil, err 98 | } 99 | if resp.Error != nil { 100 | return nil, fmt.Errorf(resp.Error.Message) 101 | } 102 | return resp.Result, nil 103 | } 104 | 105 | //TODO: finish 106 | func AdminStopWS() (interface{}, error) { 107 | resp, err := Call("admin_stopWS", nil) 108 | if err != nil { 109 | return nil, err 110 | } 111 | if resp.Error != nil { 112 | return nil, fmt.Errorf(resp.Error.Message) 113 | } 114 | return resp.Result, nil 115 | } 116 | -------------------------------------------------------------------------------- /contants.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import () 4 | 5 | //Blog tags 6 | const Earliest string = "earliest" 7 | const Latest string = "latest" 8 | const Pending string = "pending" 9 | -------------------------------------------------------------------------------- /db.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/wiki/wiki/JSON-RPC 8 | 9 | //TODO: finish 10 | func DBPutString(data []string) (bool, error) { 11 | resp, err := Call("db_putString", data) 12 | if err != nil { 13 | return false, err 14 | } 15 | if resp.Error != nil { 16 | return false, fmt.Errorf(resp.Error.Message) 17 | } 18 | return resp.Result.(bool), nil 19 | } 20 | 21 | //TODO: finish 22 | func DBGetString(data []string) (string, error) { 23 | resp, err := Call("db_getString", data) 24 | if err != nil { 25 | return "", err 26 | } 27 | if resp.Error != nil { 28 | return "", fmt.Errorf(resp.Error.Message) 29 | } 30 | return resp.Result.(string), nil 31 | } 32 | 33 | //TODO: finish 34 | func DBPutHex(data []string) (bool, error) { 35 | resp, err := Call("db_putHex", data) 36 | if err != nil { 37 | return false, err 38 | } 39 | if resp.Error != nil { 40 | return false, fmt.Errorf(resp.Error.Message) 41 | } 42 | return resp.Result.(bool), nil 43 | } 44 | 45 | //TODO: finish 46 | func DBGetHex(data []string) (string, error) { 47 | resp, err := Call("db_getHex", data) 48 | if err != nil { 49 | return "", err 50 | } 51 | if resp.Error != nil { 52 | return "", fmt.Errorf(resp.Error.Message) 53 | } 54 | return resp.Result.(string), nil 55 | } 56 | -------------------------------------------------------------------------------- /debug.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/go-ethereum/wiki/Management-APIs#debug 8 | 9 | //TODO: finish 10 | func DebugBacktraceAt(location string) (interface{}, error) { 11 | resp, err := Call("debug_backtraceAt", []interface{}{location}) 12 | if err != nil { 13 | return nil, err 14 | } 15 | if resp.Error != nil { 16 | return nil, fmt.Errorf(resp.Error.Message) 17 | } 18 | return resp.Result, nil 19 | } 20 | 21 | //TODO: finish 22 | func DebugBlockProfile(file string, seconds int64) (interface{}, error) { 23 | resp, err := Call("debug_blockProfile", []interface{}{file, seconds}) 24 | if err != nil { 25 | return nil, err 26 | } 27 | if resp.Error != nil { 28 | return nil, fmt.Errorf(resp.Error.Message) 29 | } 30 | return resp.Result, nil 31 | } 32 | 33 | //TODO: finish 34 | func DebugCPUProfile(file string, seconds int64) (interface{}, error) { 35 | resp, err := Call("debug_cpuProfile", []interface{}{file, seconds}) 36 | if err != nil { 37 | return nil, err 38 | } 39 | if resp.Error != nil { 40 | return nil, fmt.Errorf(resp.Error.Message) 41 | } 42 | return resp.Result, nil 43 | } 44 | 45 | //TODO: finish 46 | func DebugDumpBlock(number uint64) (interface{}, error) { 47 | resp, err := Call("debug_dumpBlock", []interface{}{number}) 48 | if err != nil { 49 | return nil, err 50 | } 51 | if resp.Error != nil { 52 | return nil, fmt.Errorf(resp.Error.Message) 53 | } 54 | return resp.Result, nil 55 | } 56 | 57 | //TODO: finish 58 | func DebugGCStats() (interface{}, error) { 59 | resp, err := Call("debug_gcStats", nil) 60 | if err != nil { 61 | return nil, err 62 | } 63 | if resp.Error != nil { 64 | return nil, fmt.Errorf(resp.Error.Message) 65 | } 66 | return resp.Result, nil 67 | } 68 | 69 | //TODO: finish 70 | func DebugGetBlockRLP(number uint64) (interface{}, error) { 71 | resp, err := Call("debug_getBlockRlp", []interface{}{number}) 72 | if err != nil { 73 | return nil, err 74 | } 75 | if resp.Error != nil { 76 | return nil, fmt.Errorf(resp.Error.Message) 77 | } 78 | return resp.Result, nil 79 | } 80 | 81 | //TODO: finish 82 | func DebugGoTrace(file string, seconds int64) (interface{}, error) { 83 | resp, err := Call("debug_goTrace", []interface{}{file, seconds}) 84 | if err != nil { 85 | return nil, err 86 | } 87 | if resp.Error != nil { 88 | return nil, fmt.Errorf(resp.Error.Message) 89 | } 90 | return resp.Result, nil 91 | } 92 | 93 | //TODO: finish 94 | func DebugMemStats() (interface{}, error) { 95 | resp, err := Call("debug_memStats", nil) 96 | if err != nil { 97 | return nil, err 98 | } 99 | if resp.Error != nil { 100 | return nil, fmt.Errorf(resp.Error.Message) 101 | } 102 | return resp.Result, nil 103 | } 104 | 105 | //TODO: finish 106 | func DebugSeedHash(number uint64) (interface{}, error) { 107 | resp, err := Call("debug_seedHash", []interface{}{number}) 108 | if err != nil { 109 | return nil, err 110 | } 111 | if resp.Error != nil { 112 | return nil, fmt.Errorf(resp.Error.Message) 113 | } 114 | return resp.Result, nil 115 | } 116 | 117 | //TODO: finish 118 | func DebugSetHead(number uint64) (interface{}, error) { 119 | resp, err := Call("debug_setHead", []interface{}{number}) 120 | if err != nil { 121 | return nil, err 122 | } 123 | if resp.Error != nil { 124 | return nil, fmt.Errorf(resp.Error.Message) 125 | } 126 | return resp.Result, nil 127 | } 128 | 129 | //TODO: finish 130 | func DebugSetBlockProfileRate(rate int64) (interface{}, error) { 131 | resp, err := Call("debug_setBlockProfileRate", []interface{}{rate}) 132 | if err != nil { 133 | return nil, err 134 | } 135 | if resp.Error != nil { 136 | return nil, fmt.Errorf(resp.Error.Message) 137 | } 138 | return resp.Result, nil 139 | } 140 | 141 | //TODO: finish 142 | func DebugStacks() (interface{}, error) { 143 | resp, err := Call("debug_stacks", nil) 144 | if err != nil { 145 | return nil, err 146 | } 147 | if resp.Error != nil { 148 | return nil, fmt.Errorf(resp.Error.Message) 149 | } 150 | return resp.Result, nil 151 | } 152 | 153 | //TODO: finish 154 | func DebugStartCPUProfile(file string) (interface{}, error) { 155 | resp, err := Call("debug_startCPUProfile", []interface{}{file}) 156 | if err != nil { 157 | return nil, err 158 | } 159 | if resp.Error != nil { 160 | return nil, fmt.Errorf(resp.Error.Message) 161 | } 162 | return resp.Result, nil 163 | } 164 | 165 | //TODO: finish 166 | func DebugStartGoTrace(file string) (interface{}, error) { 167 | resp, err := Call("debug_startGoTrace", []interface{}{file}) 168 | if err != nil { 169 | return nil, err 170 | } 171 | if resp.Error != nil { 172 | return nil, fmt.Errorf(resp.Error.Message) 173 | } 174 | return resp.Result, nil 175 | } 176 | 177 | //TODO: finish 178 | func DebugStopCPUProfile() (interface{}, error) { 179 | resp, err := Call("debug_stopCPUProfile", nil) 180 | if err != nil { 181 | return nil, err 182 | } 183 | if resp.Error != nil { 184 | return nil, fmt.Errorf(resp.Error.Message) 185 | } 186 | return resp.Result, nil 187 | } 188 | 189 | //TODO: finish 190 | func DebugStopGoTrace() (interface{}, error) { 191 | resp, err := Call("debug_stopGoTrace", nil) 192 | if err != nil { 193 | return nil, err 194 | } 195 | if resp.Error != nil { 196 | return nil, fmt.Errorf(resp.Error.Message) 197 | } 198 | return resp.Result, nil 199 | } 200 | 201 | //TODO: finish 202 | //TODO: add config? 203 | func DebugTraceBlock(blockRlp string) (interface{}, error) { 204 | resp, err := Call("debug_traceBlock", []interface{}{blockRlp}) 205 | if err != nil { 206 | return nil, err 207 | } 208 | if resp.Error != nil { 209 | return nil, fmt.Errorf(resp.Error.Message) 210 | } 211 | return resp.Result, nil 212 | } 213 | 214 | //TODO: finish 215 | //TODO: add config? 216 | func DebugTraceBlockByNumber(number uint64) (interface{}, error) { 217 | resp, err := Call("debug_traceBlockByNumber", []interface{}{number}) 218 | if err != nil { 219 | return nil, err 220 | } 221 | if resp.Error != nil { 222 | return nil, fmt.Errorf(resp.Error.Message) 223 | } 224 | return resp.Result, nil 225 | } 226 | 227 | //TODO: finish 228 | //TODO: add config? 229 | func DebugTraceBlockByHash(hash string) (interface{}, error) { 230 | resp, err := Call("debug_traceBlockByHash", []interface{}{hash}) 231 | if err != nil { 232 | return nil, err 233 | } 234 | if resp.Error != nil { 235 | return nil, fmt.Errorf(resp.Error.Message) 236 | } 237 | return resp.Result, nil 238 | } 239 | 240 | //TODO: finish 241 | //TODO: add config? 242 | func DebugTraceBlockFromFile(file string) (interface{}, error) { 243 | resp, err := Call("debug_traceBlockFromFile", []interface{}{file}) 244 | if err != nil { 245 | return nil, err 246 | } 247 | if resp.Error != nil { 248 | return nil, fmt.Errorf(resp.Error.Message) 249 | } 250 | return resp.Result, nil 251 | } 252 | 253 | //TODO: finish 254 | //TODO: add options? 255 | func DebugTraceTransaction(txHash string) (interface{}, error) { 256 | resp, err := Call("debug_traceTransaction", []interface{}{txHash}) 257 | if err != nil { 258 | return nil, err 259 | } 260 | if resp.Error != nil { 261 | return nil, fmt.Errorf(resp.Error.Message) 262 | } 263 | return resp.Result, nil 264 | } 265 | 266 | //TODO: finish 267 | func DebugVerbosity(number int64) (interface{}, error) { 268 | resp, err := Call("debug_verbosity", []interface{}{number}) 269 | if err != nil { 270 | return nil, err 271 | } 272 | if resp.Error != nil { 273 | return nil, fmt.Errorf(resp.Error.Message) 274 | } 275 | return resp.Result, nil 276 | } 277 | 278 | //TODO: finish 279 | func DebugVModule(pattern string) (interface{}, error) { 280 | resp, err := Call("debug_vmodule", []interface{}{pattern}) 281 | if err != nil { 282 | return nil, err 283 | } 284 | if resp.Error != nil { 285 | return nil, fmt.Errorf(resp.Error.Message) 286 | } 287 | return resp.Result, nil 288 | } 289 | 290 | //TODO: finish 291 | func DebugWriteBlockProfile(file string) (interface{}, error) { 292 | resp, err := Call("debug_writeBlockProfile", []interface{}{file}) 293 | if err != nil { 294 | return nil, err 295 | } 296 | if resp.Error != nil { 297 | return nil, fmt.Errorf(resp.Error.Message) 298 | } 299 | return resp.Result, nil 300 | } 301 | 302 | //TODO: finish 303 | func DebugWriteMemProfile(file string) (interface{}, error) { 304 | resp, err := Call("debug_writeMemProfile", []interface{}{file}) 305 | if err != nil { 306 | return nil, err 307 | } 308 | if resp.Error != nil { 309 | return nil, fmt.Errorf(resp.Error.Message) 310 | } 311 | return resp.Result, nil 312 | } 313 | -------------------------------------------------------------------------------- /eth.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/wiki/wiki/JSON-RPC 8 | 9 | func EthProtocolVersion() (string, error) { 10 | resp, err := Call("eth_protocolVersion", nil) 11 | if err != nil { 12 | return "", err 13 | } 14 | if resp.Error != nil { 15 | return "", fmt.Errorf(resp.Error.Message) 16 | } 17 | return resp.Result.(string), nil 18 | } 19 | 20 | func EthSyncing() (*EthSyncingResponse, error) { 21 | resp, err := Call("eth_syncing", nil) 22 | if err != nil { 23 | return nil, err 24 | } 25 | if resp.Error != nil { 26 | return nil, fmt.Errorf(resp.Error.Message) 27 | } 28 | answer := new(EthSyncingResponse) 29 | syncing, ok := resp.Result.(bool) 30 | if ok == true { 31 | answer.Syncing = syncing 32 | return answer, nil 33 | } 34 | err = MapToObject(resp.Result, answer) 35 | if err != nil { 36 | return nil, err 37 | } 38 | return answer, nil 39 | } 40 | 41 | func EthCoinbase() (string, error) { 42 | resp, err := Call("eth_coinbase", nil) 43 | if err != nil { 44 | return "", err 45 | } 46 | if resp.Error != nil { 47 | return "", fmt.Errorf(resp.Error.Message) 48 | } 49 | return resp.Result.(string), nil 50 | } 51 | 52 | func EthMining() (bool, error) { 53 | resp, err := Call("eth_mining", nil) 54 | if err != nil { 55 | return false, err 56 | } 57 | if resp.Error != nil { 58 | return false, fmt.Errorf(resp.Error.Message) 59 | } 60 | return resp.Result.(bool), nil 61 | } 62 | 63 | func EthHashrate() (int64, error) { 64 | resp, err := Call("eth_hashrate", nil) 65 | if err != nil { 66 | return 0, err 67 | } 68 | if resp.Error != nil { 69 | return 0, fmt.Errorf(resp.Error.Message) 70 | } 71 | return ParseQuantity(resp.Result.(string)) 72 | } 73 | 74 | func EthGasPrice() (int64, error) { 75 | resp, err := Call("eth_gasPrice", nil) 76 | if err != nil { 77 | return 0, err 78 | } 79 | if resp.Error != nil { 80 | return 0, fmt.Errorf(resp.Error.Message) 81 | } 82 | return ParseQuantity(resp.Result.(string)) 83 | } 84 | 85 | func EthAccounts() ([]string, error) { 86 | resp, err := Call("eth_accounts", nil) 87 | if err != nil { 88 | return nil, err 89 | } 90 | if resp.Error != nil { 91 | return nil, fmt.Errorf(resp.Error.Message) 92 | } 93 | answer := []string{} 94 | err = MapToObject(resp.Result, &answer) 95 | if err != nil { 96 | return nil, err 97 | } 98 | return answer, nil 99 | } 100 | 101 | func EthBlockNumber() (int64, error) { 102 | resp, err := Call("eth_blockNumber", nil) 103 | if err != nil { 104 | return 0, err 105 | } 106 | if resp.Error != nil { 107 | return 0, fmt.Errorf(resp.Error.Message) 108 | } 109 | return ParseQuantity(resp.Result.(string)) 110 | } 111 | 112 | //TODO: test 113 | func EthGetBalance(address string, blockNumberOrTag string) (int64, error) { 114 | resp, err := Call("eth_getBalance", []string{address, blockNumberOrTag}) 115 | if err != nil { 116 | return 0, err 117 | } 118 | if resp.Error != nil { 119 | return 0, fmt.Errorf(resp.Error.Message) 120 | } 121 | return ParseQuantity(resp.Result.(string)) 122 | } 123 | 124 | //TODO: test 125 | func EthGetStorageAt(address, positionInTheStorage, blockNumberOrTag string) (string, error) { 126 | resp, err := Call("eth_getStorageAt", []string{address, positionInTheStorage, blockNumberOrTag}) 127 | if err != nil { 128 | return "", err 129 | } 130 | if resp.Error != nil { 131 | return "", fmt.Errorf(resp.Error.Message) 132 | } 133 | return resp.Result.(string), nil 134 | } 135 | 136 | //TODO: test 137 | func EthGetTransactionCount(address, blockNumberOrTag string) (int64, error) { 138 | resp, err := Call("eth_getTransactionCount", []string{address, blockNumberOrTag}) 139 | if err != nil { 140 | return 0, err 141 | } 142 | if resp.Error != nil { 143 | return 0, fmt.Errorf(resp.Error.Message) 144 | } 145 | return ParseQuantity(resp.Result.(string)) 146 | } 147 | 148 | //TODO: test 149 | func EthGetBlockTransactionCountByHash(blockHash string) (int64, error) { 150 | resp, err := Call("eth_getBlockTransactionCountByHash", []string{blockHash}) 151 | if err != nil { 152 | return 0, err 153 | } 154 | if resp.Error != nil { 155 | return 0, fmt.Errorf(resp.Error.Message) 156 | } 157 | return ParseQuantity(resp.Result.(string)) 158 | } 159 | 160 | //TODO: test 161 | func EthGetBlockTransactionCountByNumber(blockNumberOrTag string) (int64, error) { 162 | resp, err := Call("eth_getBlockTransactionCountByNumber", []string{blockNumberOrTag}) 163 | if err != nil { 164 | return 0, err 165 | } 166 | if resp.Error != nil { 167 | return 0, fmt.Errorf(resp.Error.Message) 168 | } 169 | return ParseQuantity(resp.Result.(string)) 170 | } 171 | 172 | //TODO: test 173 | func EthGetUncleCountByBlockHash(blockHash string) (int64, error) { 174 | resp, err := Call("eth_getUncleCountByBlockHash", []string{blockHash}) 175 | if err != nil { 176 | return 0, err 177 | } 178 | if resp.Error != nil { 179 | return 0, fmt.Errorf(resp.Error.Message) 180 | } 181 | return ParseQuantity(resp.Result.(string)) 182 | } 183 | 184 | //TODO: test 185 | func EthGetUncleCountByBlockNumber(blockNumberOrTag string) (int64, error) { 186 | resp, err := Call("eth_getUncleCountByBlockNumber", []string{blockNumberOrTag}) 187 | if err != nil { 188 | return 0, err 189 | } 190 | if resp.Error != nil { 191 | return 0, fmt.Errorf(resp.Error.Message) 192 | } 193 | return ParseQuantity(resp.Result.(string)) 194 | } 195 | 196 | //TODO: test 197 | func EthGetCode(address, blockNumberOrTag string) (string, error) { 198 | resp, err := Call("eth_getCode", []string{address, blockNumberOrTag}) 199 | if err != nil { 200 | return "", err 201 | } 202 | if resp.Error != nil { 203 | return "", fmt.Errorf(resp.Error.Message) 204 | } 205 | return resp.Result.(string), nil 206 | } 207 | 208 | //TODO: test 209 | func EthSign(address, hashOfDataToSign string) (string, error) { 210 | resp, err := Call("eth_sign", []string{address, hashOfDataToSign}) 211 | if err != nil { 212 | return "", err 213 | } 214 | if resp.Error != nil { 215 | return "", fmt.Errorf(resp.Error.Message) 216 | } 217 | return resp.Result.(string), nil 218 | } 219 | 220 | //TODO: test 221 | func EthSendTransaction(tx *TransactionObject) (string, error) { 222 | resp, err := Call("eth_sendTransaction", []interface{}{tx}) 223 | if err != nil { 224 | return "", err 225 | } 226 | if resp.Error != nil { 227 | return "", fmt.Errorf(resp.Error.Message) 228 | } 229 | return resp.Result.(string), nil 230 | } 231 | 232 | //TODO: test 233 | func EthSendRawTransaction(txData string) (string, error) { 234 | resp, err := Call("eth_sendRawTransaction", []string{txData}) 235 | if err != nil { 236 | return "", err 237 | } 238 | if resp.Error != nil { 239 | return "", fmt.Errorf(resp.Error.Message) 240 | } 241 | return resp.Result.(string), nil 242 | } 243 | 244 | //TODO: test 245 | func EthCall(tx *TransactionObject, blockNumberOrTag string) (string, error) { 246 | resp, err := Call("eth_call", []interface{}{tx, blockNumberOrTag}) 247 | if err != nil { 248 | return "", err 249 | } 250 | if resp.Error != nil { 251 | return "", fmt.Errorf(resp.Error.Message) 252 | } 253 | return resp.Result.(string), nil 254 | } 255 | 256 | //TODO: test 257 | func EthEstimateGas(tx *TransactionObject, blockNumberOrTag string) (int64, error) { 258 | resp, err := Call("eth_estimateGas", []interface{}{tx, blockNumberOrTag}) 259 | if err != nil { 260 | return 0, err 261 | } 262 | if resp.Error != nil { 263 | return 0, fmt.Errorf(resp.Error.Message) 264 | } 265 | return ParseQuantity(resp.Result.(string)) 266 | } 267 | 268 | //TODO: test 269 | func EthGetBlockByHash(blockHash string, fullTransaction bool) (*BlockObject, error) { 270 | resp, err := Call("eth_getBlockByHash", []interface{}{blockHash, fullTransaction}) 271 | if err != nil { 272 | return nil, err 273 | } 274 | if resp.Error != nil { 275 | return nil, fmt.Errorf(resp.Error.Message) 276 | } 277 | answer := new(BlockObject) 278 | err = MapToObject(resp.Result, answer) 279 | if err != nil { 280 | return nil, err 281 | } 282 | return answer, nil 283 | } 284 | 285 | //TODO: test 286 | func EthGetBlockByNumber(blockNumberOrTag string, fullTransaction bool) (*BlockObject, error) { 287 | resp, err := Call("eth_getBlockByNumber", []interface{}{blockNumberOrTag, fullTransaction}) 288 | if err != nil { 289 | return nil, err 290 | } 291 | if resp.Error != nil { 292 | return nil, fmt.Errorf(resp.Error.Message) 293 | } 294 | answer := new(BlockObject) 295 | err = MapToObject(resp.Result, answer) 296 | if err != nil { 297 | return nil, err 298 | } 299 | return answer, nil 300 | } 301 | 302 | //TODO: test 303 | func EthGetTransactionByHash(txHash string) (*TransactionObject, error) { 304 | resp, err := Call("eth_getTransactionByHash", []interface{}{txHash}) 305 | if err != nil { 306 | return nil, err 307 | } 308 | if resp.Error != nil { 309 | return nil, fmt.Errorf(resp.Error.Message) 310 | } 311 | answer := new(TransactionObject) 312 | err = MapToObject(resp.Result, answer) 313 | if err != nil { 314 | return nil, err 315 | } 316 | return answer, nil 317 | } 318 | 319 | //TODO: test 320 | func EthGetTransactionByBlockHashAndIndex(blockHash, txIndex string) (*TransactionObject, error) { 321 | resp, err := Call("eth_getTransactionByBlockHashAndIndex", []interface{}{blockHash, txIndex}) 322 | if err != nil { 323 | return nil, err 324 | } 325 | if resp.Error != nil { 326 | return nil, fmt.Errorf(resp.Error.Message) 327 | } 328 | answer := new(TransactionObject) 329 | err = MapToObject(resp.Result, answer) 330 | if err != nil { 331 | return nil, err 332 | } 333 | return answer, nil 334 | } 335 | 336 | //TODO: test 337 | func EthGetTransactionByBlockNumberAndIndex(blockNumberOrTag string, txIndex string) (*TransactionObject, error) { 338 | resp, err := Call("eth_getTransactionByBlockNumberAndIndex", []interface{}{blockNumberOrTag, txIndex}) 339 | if err != nil { 340 | return nil, err 341 | } 342 | if resp.Error != nil { 343 | return nil, fmt.Errorf(resp.Error.Message) 344 | } 345 | answer := new(TransactionObject) 346 | err = MapToObject(resp.Result, answer) 347 | if err != nil { 348 | return nil, err 349 | } 350 | return answer, nil 351 | } 352 | 353 | //TODO: test 354 | func EthGetTransactionReceipt(txHash string) (*TransactionReceipt, error) { 355 | resp, err := Call("eth_getTransactionReceipt", []interface{}{txHash}) 356 | if err != nil { 357 | return nil, err 358 | } 359 | if resp.Error != nil { 360 | return nil, fmt.Errorf(resp.Error.Message) 361 | } 362 | answer := new(TransactionReceipt) 363 | err = MapToObject(resp.Result, answer) 364 | if err != nil { 365 | return nil, err 366 | } 367 | return answer, nil 368 | } 369 | 370 | //TODO: test 371 | func EthGetUncleByBlockHashAndIndex(blockHash, uncleIndex string) (*BlockObject, error) { 372 | resp, err := Call("eth_getUncleByBlockHashAndIndex", []interface{}{blockHash, uncleIndex}) 373 | if err != nil { 374 | return nil, err 375 | } 376 | if resp.Error != nil { 377 | return nil, fmt.Errorf(resp.Error.Message) 378 | } 379 | answer := new(BlockObject) 380 | err = MapToObject(resp.Result, answer) 381 | if err != nil { 382 | return nil, err 383 | } 384 | return answer, nil 385 | } 386 | 387 | //TODO: test 388 | func EthGetUncleByBlockNumberAndIndex(blockNumberOrTag string, uncleIndex string) (*BlockObject, error) { 389 | resp, err := Call("eth_getUncleByBlockNumberAndIndex", []interface{}{blockNumberOrTag, uncleIndex}) 390 | if err != nil { 391 | return nil, err 392 | } 393 | if resp.Error != nil { 394 | return nil, fmt.Errorf(resp.Error.Message) 395 | } 396 | answer := new(BlockObject) 397 | err = MapToObject(resp.Result, answer) 398 | if err != nil { 399 | return nil, err 400 | } 401 | return answer, nil 402 | } 403 | 404 | func EthGetCompilers() ([]string, error) { 405 | resp, err := Call("eth_getCompilers", nil) 406 | if err != nil { 407 | return nil, err 408 | } 409 | if resp.Error != nil { 410 | return nil, fmt.Errorf(resp.Error.Message) 411 | } 412 | return resp.Result.([]string), nil 413 | } 414 | 415 | //TODO: test 416 | func EthCompileLLL(sourceCode string) (string, error) { 417 | resp, err := Call("eth_compileLLL", []interface{}{sourceCode}) 418 | if err != nil { 419 | return "", err 420 | } 421 | if resp.Error != nil { 422 | return "", fmt.Errorf(resp.Error.Message) 423 | } 424 | return resp.Result.(string), nil 425 | } 426 | 427 | //TODO: test 428 | func EthCompileSolidity(sourceCode string) (string, error) { 429 | resp, err := Call("eth_compileSolidity", []interface{}{sourceCode}) 430 | if err != nil { 431 | return "", err 432 | } 433 | if resp.Error != nil { 434 | return "", fmt.Errorf(resp.Error.Message) 435 | } 436 | return resp.Result.(string), nil 437 | } 438 | 439 | //TODO: test 440 | func EthCompileSerpent(sourceCode string) (string, error) { 441 | resp, err := Call("eth_compileSerpent", []interface{}{sourceCode}) 442 | if err != nil { 443 | return "", err 444 | } 445 | if resp.Error != nil { 446 | return "", fmt.Errorf(resp.Error.Message) 447 | } 448 | return resp.Result.(string), nil 449 | } 450 | 451 | //TODO: test 452 | func EthNewFilter(filterOptions *FilterOptions) (int64, error) { 453 | resp, err := Call("eth_newFilter", []interface{}{filterOptions}) 454 | if err != nil { 455 | return 0, err 456 | } 457 | if resp.Error != nil { 458 | return 0, fmt.Errorf(resp.Error.Message) 459 | } 460 | return ParseQuantity(resp.Result.(string)) 461 | } 462 | 463 | //TODO: test 464 | func EthNewBlockFilter() (int64, error) { 465 | resp, err := Call("eth_newBlockFilter", nil) 466 | if err != nil { 467 | return 0, err 468 | } 469 | if resp.Error != nil { 470 | return 0, fmt.Errorf(resp.Error.Message) 471 | } 472 | return ParseQuantity(resp.Result.(string)) 473 | } 474 | 475 | //TODO: test 476 | func EthNewPendingTransactionFilter() (int64, error) { 477 | resp, err := Call("eth_newPendingTransactionFilter", nil) 478 | if err != nil { 479 | return 0, err 480 | } 481 | if resp.Error != nil { 482 | return 0, fmt.Errorf(resp.Error.Message) 483 | } 484 | return ParseQuantity(resp.Result.(string)) 485 | } 486 | 487 | //TODO: test 488 | func EthUninstallFilter(filterID string) (bool, error) { 489 | resp, err := Call("eth_uninstallFilter", []interface{}{filterID}) 490 | if err != nil { 491 | return false, err 492 | } 493 | if resp.Error != nil { 494 | return false, fmt.Errorf(resp.Error.Message) 495 | } 496 | return resp.Result.(bool), nil 497 | } 498 | 499 | //TODO: test 500 | func EthGetFilterChanges(filterID string) (*LogObject, error) { 501 | resp, err := Call("eth_getFilterChanges", []interface{}{filterID}) 502 | if err != nil { 503 | return nil, err 504 | } 505 | if resp.Error != nil { 506 | return nil, fmt.Errorf(resp.Error.Message) 507 | } 508 | answer := new(LogObject) 509 | err = MapToObject(resp.Result, answer) 510 | if err != nil { 511 | return nil, err 512 | } 513 | return answer, nil 514 | } 515 | 516 | //TODO: test 517 | func EthGetFilterLogs(filterID string) (*LogObject, error) { 518 | resp, err := Call("eth_getFilterLogs", nil) 519 | if err != nil { 520 | return nil, err 521 | } 522 | if resp.Error != nil { 523 | return nil, fmt.Errorf(resp.Error.Message) 524 | } 525 | answer := new(LogObject) 526 | err = MapToObject(resp.Result, answer) 527 | if err != nil { 528 | return nil, err 529 | } 530 | return answer, nil 531 | } 532 | 533 | //TODO: test 534 | func EthGetLogs(filter []*FilterOptions) (*LogObject, error) { 535 | resp, err := Call("eth_getLogs", filter) 536 | if err != nil { 537 | return nil, err 538 | } 539 | if resp.Error != nil { 540 | return nil, fmt.Errorf(resp.Error.Message) 541 | } 542 | answer := new(LogObject) 543 | err = MapToObject(resp.Result, answer) 544 | if err != nil { 545 | return nil, err 546 | } 547 | return answer, nil 548 | } 549 | 550 | //TODO: test 551 | func EthGetWork() ([]string, error) { 552 | resp, err := Call("eth_getWork", nil) 553 | if err != nil { 554 | return nil, err 555 | } 556 | if resp.Error != nil { 557 | return nil, fmt.Errorf(resp.Error.Message) 558 | } 559 | answer := []string{} 560 | err = MapToObject(resp.Result, &answer) 561 | if err != nil { 562 | return nil, err 563 | } 564 | return answer, nil 565 | } 566 | 567 | //TODO: test 568 | func EthSubmitWork(work []string) (bool, error) { 569 | resp, err := Call("eth_submitWork", work) 570 | if err != nil { 571 | return false, err 572 | } 573 | if resp.Error != nil { 574 | return false, fmt.Errorf(resp.Error.Message) 575 | } 576 | return resp.Result.(bool), nil 577 | } 578 | 579 | //TODO: test 580 | func EthSubmitHashrate(hashrate []string) (bool, error) { 581 | resp, err := Call("eth_submitHashrate", hashrate) 582 | if err != nil { 583 | return false, err 584 | } 585 | if resp.Error != nil { 586 | return false, fmt.Errorf(resp.Error.Message) 587 | } 588 | return resp.Result.(bool), nil 589 | } 590 | -------------------------------------------------------------------------------- /external.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | ) 10 | 11 | //https://etherscan.io/apis 12 | //https://testnet.etherscan.io/apis 13 | 14 | //https://api.etherscan.io/api?module=account&action=txlist&address=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae&startblock=0&endblock=99999999&sort=asc&apikey=YourApiKeyToken 15 | //https://testnet.etherscan.io/api?module=account&action=txlist&address=0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae&startblock=0&endblock=99999999&sort=asc&apikey=YourApiKeyToken 16 | 17 | var EtherscanTestNet bool = true 18 | var EtherscanTestNetName string = "ropsten" 19 | var EtherscanAPIKeyToken string = "UninitializedApiKey" 20 | 21 | func CallRest(url string, dst interface{}) error { 22 | postGet := "GET" 23 | 24 | req, err := http.NewRequest(postGet, url, nil) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | client := &http.Client{} 30 | resp, err := client.Do(req) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | defer resp.Body.Close() 36 | 37 | body, err := ioutil.ReadAll(resp.Body) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | err = json.Unmarshal(body, dst) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | return nil 48 | } 49 | 50 | type EtherscanResponse struct { 51 | Status string `json:"status"` 52 | Message string `json:"message"` 53 | Result interface{} `json:"result"` 54 | } 55 | 56 | type EtherscanTransaction struct { 57 | BlockNumber string `json:"blockNumber"` 58 | TimeStamp string `json:"timeStamp"` 59 | Hash string `json:"hash"` 60 | Nonce string `json:"nonce"` 61 | BlockHash string `json:"blockHash"` 62 | TransactionIndex string `json:"transactionIndex"` 63 | From string `json:"from"` 64 | To string `json:"to"` 65 | Value string `json:"value"` 66 | Gas string `json:"gas"` 67 | GasPrice string `json:"gasPrice"` 68 | IsError string `json:"isError"` 69 | Input string `json:"input"` 70 | ContractAddress string `json:"contractAddress"` 71 | CumulativeGasUsed string `json:"cumulativeGasUsed"` 72 | GasUsed string `json:"gasUsed"` 73 | Confirmations string `json:"confirmations"` 74 | } 75 | 76 | func (e *EtherscanTransaction) JSONByte() ([]byte, error) { 77 | return EncodeJSON(e) 78 | } 79 | 80 | func (e *EtherscanTransaction) JSONString() (string, error) { 81 | return EncodeJSONString(e) 82 | } 83 | 84 | func (e *EtherscanTransaction) JSONBuffer(b *bytes.Buffer) error { 85 | return EncodeJSONToBuffer(e, b) 86 | } 87 | 88 | func (e *EtherscanTransaction) String() string { 89 | str, _ := e.JSONString() 90 | return str 91 | } 92 | 93 | func EtherscanTxList(address string) ([]*EtherscanTransaction, error) { 94 | prefix := "api" 95 | if EtherscanTestNet == true { 96 | prefix = EtherscanTestNetName 97 | } 98 | 99 | url := fmt.Sprintf("https://%v.etherscan.io/api?module=account&action=txlist&address=%v&startblock=0&endblock=99999999&sort=asc&apikey=%v", prefix, address, EtherscanAPIKeyToken) 100 | dst := new(EtherscanResponse) 101 | dst.Result = []*EtherscanTransaction{} 102 | err := CallRest(url, dst) 103 | if err != nil { 104 | return nil, err 105 | } 106 | list := []*EtherscanTransaction{} 107 | err = MapToObject(dst.Result, &list) 108 | if err != nil { 109 | return nil, err 110 | } 111 | return list, nil 112 | } 113 | 114 | func EtherscanTxListWithStartBlock(address string, startBlock int64) ([]*EtherscanTransaction, error) { 115 | prefix := "api" 116 | if EtherscanTestNet == true { 117 | prefix = EtherscanTestNetName 118 | } 119 | url := fmt.Sprintf("https://%v.etherscan.io/api?module=account&action=txlist&address=%v&startblock=%v&endblock=99999999&sort=asc&apikey=%v", prefix, address, startBlock, EtherscanAPIKeyToken) 120 | dst := new(EtherscanResponse) 121 | dst.Result = []*EtherscanTransaction{} 122 | err := CallRest(url, dst) 123 | if err != nil { 124 | return nil, err 125 | } 126 | list := []*EtherscanTransaction{} 127 | err = MapToObject(dst.Result, &list) 128 | if err != nil { 129 | return nil, err 130 | } 131 | return list, nil 132 | } 133 | -------------------------------------------------------------------------------- /external_test.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/FactomProject/EthereumAPI" 7 | ) 8 | 9 | func TestEtherscanTxList(t *testing.T) { 10 | resp, err := EtherscanTxList("0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae") 11 | t.Errorf("%v, %v", resp, err) 12 | } 13 | -------------------------------------------------------------------------------- /json.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Factom Foundation 2 | // Use of this source code is governed by the MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | package EthereumAPI 6 | 7 | import ( 8 | "bytes" 9 | "encoding/json" 10 | "fmt" 11 | "strconv" 12 | ) 13 | 14 | func MapToObject(source interface{}, dst interface{}) error { 15 | b, err := json.Marshal(source) 16 | if err != nil { 17 | return err 18 | } 19 | return json.Unmarshal(b, dst) 20 | } 21 | 22 | func ParseQuantity(q string) (int64, error) { 23 | return strconv.ParseInt(q, 0, 64) 24 | } 25 | 26 | func EncodeJSON(data interface{}) ([]byte, error) { 27 | encoded, err := json.Marshal(data) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return encoded, nil 32 | } 33 | 34 | func EncodeJSONString(data interface{}) (string, error) { 35 | encoded, err := EncodeJSON(data) 36 | if err != nil { 37 | return "", err 38 | } 39 | return string(encoded), err 40 | } 41 | 42 | func EncodeJSONToBuffer(data interface{}, b *bytes.Buffer) error { 43 | encoded, err := EncodeJSON(data) 44 | if err != nil { 45 | return err 46 | } 47 | _, err = b.Write(encoded) 48 | return err 49 | } 50 | 51 | type JSON2Request struct { 52 | JSONRPC string `json:"jsonrpc"` 53 | ID interface{} `json:"id"` 54 | Params interface{} `json:"params,omitempty"` 55 | Method string `json:"method,omitempty"` 56 | } 57 | 58 | func (e *JSON2Request) JSONByte() ([]byte, error) { 59 | return EncodeJSON(e) 60 | } 61 | 62 | func (e *JSON2Request) JSONString() (string, error) { 63 | return EncodeJSONString(e) 64 | } 65 | 66 | func (e *JSON2Request) JSONBuffer(b *bytes.Buffer) error { 67 | return EncodeJSONToBuffer(e, b) 68 | } 69 | 70 | func (e *JSON2Request) String() string { 71 | str, _ := e.JSONString() 72 | return str 73 | } 74 | 75 | func NewJSON2RequestBlank() *JSON2Request { 76 | j := new(JSON2Request) 77 | j.JSONRPC = "2.0" 78 | return j 79 | } 80 | 81 | func NewJSON2Request(id, params interface{}, method string) *JSON2Request { 82 | j := new(JSON2Request) 83 | j.JSONRPC = "2.0" 84 | j.ID = id 85 | j.Params = params 86 | j.Method = method 87 | return j 88 | } 89 | 90 | func ParseJSON2Request(request string) (*JSON2Request, error) { 91 | j := new(JSON2Request) 92 | err := json.Unmarshal([]byte(request), j) 93 | if err != nil { 94 | return nil, err 95 | } 96 | if j.JSONRPC != "2.0" { 97 | return nil, fmt.Errorf("Invalid JSON RPC version - `%v`, should be `2.0`", j.JSONRPC) 98 | } 99 | return j, nil 100 | } 101 | 102 | type JSON2Response struct { 103 | JSONRPC string `json:"jsonrpc"` 104 | ID interface{} `json:"id"` 105 | Error *JSONError `json:"error,omitempty"` 106 | Result interface{} `json:"result,omitempty"` 107 | } 108 | 109 | func (e *JSON2Response) JSONByte() ([]byte, error) { 110 | return EncodeJSON(e) 111 | } 112 | 113 | func (e *JSON2Response) JSONString() (string, error) { 114 | return EncodeJSONString(e) 115 | } 116 | 117 | func (e *JSON2Response) JSONBuffer(b *bytes.Buffer) error { 118 | return EncodeJSONToBuffer(e, b) 119 | } 120 | 121 | func (e *JSON2Response) String() string { 122 | str, _ := e.JSONString() 123 | return str 124 | } 125 | 126 | func NewJSON2Response() *JSON2Response { 127 | j := new(JSON2Response) 128 | j.JSONRPC = "2.0" 129 | return j 130 | } 131 | 132 | func (j *JSON2Response) AddError(code int, message string, data interface{}) { 133 | e := NewJSONError(code, message, data) 134 | j.Error = e 135 | } 136 | 137 | type JSONError struct { 138 | Code int `json:"code"` 139 | Message string `json:"message"` 140 | Data interface{} `json:"data,omitempty"` 141 | } 142 | 143 | func NewJSONError(code int, message string, data interface{}) *JSONError { 144 | j := new(JSONError) 145 | j.Code = code 146 | j.Message = message 147 | j.Data = data 148 | return j 149 | } 150 | -------------------------------------------------------------------------------- /json_test.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI_test 2 | 3 | import ( 4 | . "github.com/FactomProject/EthereumAPI" 5 | "testing" 6 | ) 7 | 8 | func TestParseQuantity(t *testing.T) { 9 | i, err := ParseQuantity("0x41") 10 | if err != nil { 11 | t.Errorf("%v", err) 12 | } 13 | if i != 65 { 14 | t.Errorf("Returned wrong int value") 15 | } 16 | 17 | i, err = ParseQuantity("0x400") 18 | if err != nil { 19 | t.Errorf("%v", err) 20 | } 21 | if i != 1024 { 22 | t.Errorf("Returned wrong int value") 23 | } 24 | 25 | i, err = ParseQuantity("0x0") 26 | if err != nil { 27 | t.Errorf("%v", err) 28 | } 29 | if i != 0 { 30 | t.Errorf("Returned wrong int value") 31 | } 32 | } 33 | 34 | func TestMapToObject(t *testing.T) { 35 | list := []string{"Hello", "bye"} 36 | l2 := []string{} 37 | 38 | err := MapToObject(list, &l2) 39 | if err != nil { 40 | t.Errorf("%v", err) 41 | } 42 | 43 | if list[0] != l2[0] || list[1] != l2[1] { 44 | t.Errorf("Invalid list returned") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /miner.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/go-ethereum/wiki/Management-APIs#miner 8 | 9 | //TODO: finish 10 | func MinerHashrate() (interface{}, error) { 11 | resp, err := Call("miner_hashrate", nil) 12 | if err != nil { 13 | return nil, err 14 | } 15 | if resp.Error != nil { 16 | return nil, fmt.Errorf(resp.Error.Message) 17 | } 18 | return resp.Result, nil 19 | } 20 | 21 | //TODO: finish 22 | func MinerMakeDAG(number int64) (interface{}, error) { 23 | resp, err := Call("miner_makeDAG", []interface{}{number}) 24 | if err != nil { 25 | return nil, err 26 | } 27 | if resp.Error != nil { 28 | return nil, fmt.Errorf(resp.Error.Message) 29 | } 30 | return resp.Result, nil 31 | } 32 | 33 | //TODO: finish 34 | func MinerSetExtra(extra string) (interface{}, error) { 35 | resp, err := Call("miner_setExtra", []interface{}{extra}) 36 | if err != nil { 37 | return nil, err 38 | } 39 | if resp.Error != nil { 40 | return nil, fmt.Errorf(resp.Error.Message) 41 | } 42 | return resp.Result, nil 43 | } 44 | 45 | //TODO: finish 46 | func MinerSetGasPrice(number int64) (interface{}, error) { 47 | resp, err := Call("miner_setGasPrice", []interface{}{number}) 48 | if err != nil { 49 | return nil, err 50 | } 51 | if resp.Error != nil { 52 | return nil, fmt.Errorf(resp.Error.Message) 53 | } 54 | return resp.Result, nil 55 | } 56 | 57 | //TODO: finish 58 | func MinerStart(threads int64) (interface{}, error) { 59 | resp, err := Call("miner_start", []interface{}{threads}) 60 | if err != nil { 61 | return nil, err 62 | } 63 | if resp.Error != nil { 64 | return nil, fmt.Errorf(resp.Error.Message) 65 | } 66 | return resp.Result, nil 67 | } 68 | 69 | //TODO: finish 70 | func MinerStartAutoDAG() (interface{}, error) { 71 | resp, err := Call("miner_startAutoDAG", nil) 72 | if err != nil { 73 | return nil, err 74 | } 75 | if resp.Error != nil { 76 | return nil, fmt.Errorf(resp.Error.Message) 77 | } 78 | return resp.Result, nil 79 | } 80 | 81 | //TODO: finish 82 | func MinerStop() (interface{}, error) { 83 | resp, err := Call("miner_stop", nil) 84 | if err != nil { 85 | return nil, err 86 | } 87 | if resp.Error != nil { 88 | return nil, fmt.Errorf(resp.Error.Message) 89 | } 90 | return resp.Result, nil 91 | } 92 | 93 | //TODO: finish 94 | func MinerStopAutoDAG() (interface{}, error) { 95 | resp, err := Call("miner_stopAutoDAG", nil) 96 | if err != nil { 97 | return nil, err 98 | } 99 | if resp.Error != nil { 100 | return nil, fmt.Errorf(resp.Error.Message) 101 | } 102 | return resp.Result, nil 103 | } 104 | -------------------------------------------------------------------------------- /net.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/wiki/wiki/JSON-RPC 8 | 9 | func NetVersion() (string, error) { 10 | resp, err := Call("net_version", nil) 11 | if err != nil { 12 | return "", err 13 | } 14 | if resp.Error != nil { 15 | return "", fmt.Errorf(resp.Error.Message) 16 | } 17 | return resp.Result.(string), nil 18 | } 19 | 20 | func NetListening() (bool, error) { 21 | resp, err := Call("net_listening", nil) 22 | if err != nil { 23 | return false, err 24 | } 25 | if resp.Error != nil { 26 | return false, fmt.Errorf(resp.Error.Message) 27 | } 28 | return resp.Result.(bool), nil 29 | } 30 | 31 | func NetPeerCount() (*Quantity, error) { 32 | resp, err := Call("net_peerCount", nil) 33 | if err != nil { 34 | return nil, err 35 | } 36 | if resp.Error != nil { 37 | return nil, fmt.Errorf(resp.Error.Message) 38 | } 39 | answer := new(Quantity) 40 | err = MapToObject(resp.Result, answer) 41 | if err != nil { 42 | return nil, err 43 | } 44 | return answer, nil 45 | } 46 | -------------------------------------------------------------------------------- /personal.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal 8 | 9 | //TODO: finish 10 | func PersonalImportRawKey(keyData, passphrase string) (interface{}, error) { 11 | resp, err := Call("personal_importRawKey", []interface{}{keyData, passphrase}) 12 | if err != nil { 13 | return nil, err 14 | } 15 | if resp.Error != nil { 16 | return nil, fmt.Errorf(resp.Error.Message) 17 | } 18 | return resp.Result, nil 19 | } 20 | 21 | //TODO: finish 22 | func PersonalListAccounts() (interface{}, error) { 23 | resp, err := Call("personal_listAccounts", nil) 24 | if err != nil { 25 | return nil, err 26 | } 27 | if resp.Error != nil { 28 | return nil, fmt.Errorf(resp.Error.Message) 29 | } 30 | return resp.Result, nil 31 | } 32 | 33 | //TODO: finish 34 | func PersonalLockAccount(address string) (interface{}, error) { 35 | resp, err := Call("personal_lockAccount", []interface{}{address}) 36 | if err != nil { 37 | return nil, err 38 | } 39 | if resp.Error != nil { 40 | return nil, fmt.Errorf(resp.Error.Message) 41 | } 42 | return resp.Result, nil 43 | } 44 | 45 | //TODO: finish 46 | func PersonalNewAccount(passphrase string) (interface{}, error) { 47 | resp, err := Call("personal_newAccount", []interface{}{passphrase}) 48 | if err != nil { 49 | return nil, err 50 | } 51 | if resp.Error != nil { 52 | return nil, fmt.Errorf(resp.Error.Message) 53 | } 54 | return resp.Result, nil 55 | } 56 | 57 | //TODO: finish 58 | func PersonalUnlockAccount(address, passphrase string, duration int64) (interface{}, error) { 59 | resp, err := Call("personal_unlockAccount", []interface{}{address, passphrase, duration}) 60 | if err != nil { 61 | return nil, err 62 | } 63 | if resp.Error != nil { 64 | return nil, fmt.Errorf(resp.Error.Message) 65 | } 66 | return resp.Result, nil 67 | } 68 | 69 | //TODO: finish 70 | func PersonalSendTransaction(tx *TransactionObject, passphrase string) (string, error) { 71 | resp, err := Call("personal_sendTransaction", []interface{}{tx, passphrase}) 72 | if err != nil { 73 | return "", err 74 | } 75 | if resp.Error != nil { 76 | return "", fmt.Errorf(resp.Error.Message) 77 | } 78 | return resp.Result.(string), nil 79 | } 80 | -------------------------------------------------------------------------------- /ssh.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/wiki/wiki/JSON-RPC 8 | 9 | //TODO: test 10 | func SSHPost(whisper *WhisperMessage) (bool, error) { 11 | resp, err := Call("shh_post", []interface{}{whisper}) 12 | if err != nil { 13 | return false, err 14 | } 15 | if resp.Error != nil { 16 | return false, fmt.Errorf(resp.Error.Message) 17 | } 18 | return resp.Result.(bool), nil 19 | } 20 | 21 | //TODO: test 22 | func SSHVersion() (string, error) { 23 | resp, err := Call("shh_version", nil) 24 | if err != nil { 25 | return "", err 26 | } 27 | if resp.Error != nil { 28 | return "", fmt.Errorf(resp.Error.Message) 29 | } 30 | return resp.Result.(string), nil 31 | } 32 | 33 | //TODO: test 34 | func SSHNewIdentity() (string, error) { 35 | resp, err := Call("shh_newIdentity", nil) 36 | if err != nil { 37 | return "", err 38 | } 39 | if resp.Error != nil { 40 | return "", fmt.Errorf(resp.Error.Message) 41 | } 42 | return resp.Result.(string), nil 43 | } 44 | 45 | //TODO: test 46 | func SSHHasIdentity(identityAddress string) (bool, error) { 47 | resp, err := Call("shh_hasIdentity", []interface{}{identityAddress}) 48 | if err != nil { 49 | return false, err 50 | } 51 | if resp.Error != nil { 52 | return false, fmt.Errorf(resp.Error.Message) 53 | } 54 | return resp.Result.(bool), nil 55 | } 56 | 57 | //TODO: test 58 | func SSHNewGroup() (string, error) { 59 | resp, err := Call("shh_newGroup", nil) 60 | if err != nil { 61 | return "", err 62 | } 63 | if resp.Error != nil { 64 | return "", fmt.Errorf(resp.Error.Message) 65 | } 66 | return resp.Result.(string), nil 67 | } 68 | 69 | //TODO: test 70 | func SSHAddToGroup(identityAddress string) (interface{}, error) { 71 | resp, err := Call("shh_addToGroup", []interface{}{identityAddress}) 72 | if err != nil { 73 | return "", err 74 | } 75 | if resp.Error != nil { 76 | return "", fmt.Errorf(resp.Error.Message) 77 | } 78 | return resp.Result.(string), nil 79 | } 80 | 81 | //TODO: test 82 | func SSHNewFilter(filter *FilterOptions) (int64, error) { 83 | resp, err := Call("shh_newFilter", []interface{}{filter}) 84 | if err != nil { 85 | return 0, err 86 | } 87 | if resp.Error != nil { 88 | return 0, fmt.Errorf(resp.Error.Message) 89 | } 90 | return ParseQuantity(resp.Result.(string)) 91 | } 92 | 93 | //TODO: test 94 | func SSHUninstallFilter(filterID string) (bool, error) { 95 | resp, err := Call("shh_uninstallFilter", []interface{}{filterID}) 96 | if err != nil { 97 | return false, err 98 | } 99 | if resp.Error != nil { 100 | return false, fmt.Errorf(resp.Error.Message) 101 | } 102 | return resp.Result.(bool), nil 103 | } 104 | 105 | //TODO: test 106 | func SSHGetFilterChanges(filterID string) ([]*Message, error) { 107 | resp, err := Call("shh_getFilterChanges", []interface{}{filterID}) 108 | if err != nil { 109 | return nil, err 110 | } 111 | answer := []*Message{} 112 | err = MapToObject(resp.Result, &answer) 113 | if err != nil { 114 | return nil, err 115 | } 116 | return answer, nil 117 | } 118 | 119 | //TODO: test 120 | func SSHGetMessages(filterID string) ([]*Message, error) { 121 | resp, err := Call("shh_getMessages", []interface{}{filterID}) 122 | if err != nil { 123 | return nil, err 124 | } 125 | answer := []*Message{} 126 | err = MapToObject(resp.Result, &answer) 127 | if err != nil { 128 | return nil, err 129 | } 130 | return answer, nil 131 | } 132 | -------------------------------------------------------------------------------- /structures.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "bytes" 5 | "encoding" 6 | ) 7 | 8 | type EthSyncingResponse struct { 9 | Syncing bool `json:"syncing,omitempty"` 10 | StartingBlock string `json:"startingBlock,omitempty"` 11 | CurrentBlock string `json:"currentBlock,omitempty"` 12 | HighestBlock string `json:"highestBlock,omitempty"` 13 | } 14 | 15 | func (e *EthSyncingResponse) JSONByte() ([]byte, error) { 16 | return EncodeJSON(e) 17 | } 18 | 19 | func (e *EthSyncingResponse) JSONString() (string, error) { 20 | return EncodeJSONString(e) 21 | } 22 | 23 | func (e *EthSyncingResponse) JSONBuffer(b *bytes.Buffer) error { 24 | return EncodeJSONToBuffer(e, b) 25 | } 26 | 27 | func (e *EthSyncingResponse) String() string { 28 | str, _ := e.JSONString() 29 | return str 30 | } 31 | 32 | type TransactionObject struct { 33 | Hash string `json:"hash,omitempty"` 34 | Nonce string `json:"nonce,omitempty"` 35 | BlockHash string `json:"blockHash,omitempty"` 36 | BlockNumber string `json:"blockNumber,omitempty"` 37 | TransactionIndex string `json:"transactionIndex,omitempty"` 38 | 39 | From string `json:"from"` 40 | To string `json:"to,omitempty"` 41 | Gas string `json:"gas,omitempty"` 42 | GasPrice string `json:"gasPrice,omitempty"` 43 | Value string `json:"value,omitempty"` 44 | Data string `json:"data,omitempty"` 45 | Input string `json:"input,omitempty"` 46 | } 47 | 48 | func (e *TransactionObject) JSONByte() ([]byte, error) { 49 | return EncodeJSON(e) 50 | } 51 | 52 | func (e *TransactionObject) JSONString() (string, error) { 53 | return EncodeJSONString(e) 54 | } 55 | 56 | func (e *TransactionObject) JSONBuffer(b *bytes.Buffer) error { 57 | return EncodeJSONToBuffer(e, b) 58 | } 59 | 60 | func (e *TransactionObject) String() string { 61 | str, _ := e.JSONString() 62 | return str 63 | } 64 | 65 | type BlockObject struct { 66 | Number string `json:"number"` 67 | Hash string `json:"hash"` 68 | ParentHash string `json:"parentHash"` 69 | Nonce string `json:"nonce"` 70 | Sha3Uncles string `json:"sha3Uncles"` 71 | LogsBloom string `json:"logsBloom"` 72 | TransactionsRoot string `json:"transactionsRoot"` 73 | StateRoot string `json:"stateRoot"` 74 | Miner string `json:"miner"` 75 | Difficulty string `json:"difficulty"` 76 | TotalDifficulty string `json:"totalDifficulty"` 77 | ExtraData string `json:"extraData"` 78 | Size string `json:"size"` 79 | GasLimit string `json:"gasLimit"` 80 | GasUsed string `json:"gasUsed"` 81 | Timestamp string `json:"timestamp"` 82 | //TODO: handle both full transactions and the hashes 83 | Transactions []interface{} `json:"transactions"` 84 | Uncles []string `json:"uncles"` 85 | } 86 | 87 | func (e *BlockObject) JSONByte() ([]byte, error) { 88 | return EncodeJSON(e) 89 | } 90 | 91 | func (e *BlockObject) JSONString() (string, error) { 92 | return EncodeJSONString(e) 93 | } 94 | 95 | func (e *BlockObject) JSONBuffer(b *bytes.Buffer) error { 96 | return EncodeJSONToBuffer(e, b) 97 | } 98 | 99 | func (e *BlockObject) String() string { 100 | str, _ := e.JSONString() 101 | return str 102 | } 103 | 104 | type TransactionReceipt struct { 105 | TransactionHash string `json:"transactionHash"` 106 | TransactionIndex string `json:"transactionIndex"` 107 | BlockHash string `json:"blockHash"` 108 | BlockNumber string `json:"blockNumber"` 109 | CumulativeGasUsed string `json:"cumulativeGasUsed"` 110 | GasUsed string `json:"gasUsed"` 111 | ContractAddress string `json:"contractAddress"` 112 | Logs []interface{} `json:"logs"` 113 | } 114 | 115 | func (e *TransactionReceipt) JSONByte() ([]byte, error) { 116 | return EncodeJSON(e) 117 | } 118 | 119 | func (e *TransactionReceipt) JSONString() (string, error) { 120 | return EncodeJSONString(e) 121 | } 122 | 123 | func (e *TransactionReceipt) JSONBuffer(b *bytes.Buffer) error { 124 | return EncodeJSONToBuffer(e, b) 125 | } 126 | 127 | func (e *TransactionReceipt) String() string { 128 | str, _ := e.JSONString() 129 | return str 130 | } 131 | 132 | type FilterOptions struct { 133 | FromBlock string `json:"fromBlock,omitempty"` 134 | ToBlock string `json:"toBlock,omitempty"` 135 | Address string `json:"address,omitempty"` 136 | Topics []string `json:"topics,omitempty"` 137 | } 138 | 139 | func (e *FilterOptions) JSONByte() ([]byte, error) { 140 | return EncodeJSON(e) 141 | } 142 | 143 | func (e *FilterOptions) JSONString() (string, error) { 144 | return EncodeJSONString(e) 145 | } 146 | 147 | func (e *FilterOptions) JSONBuffer(b *bytes.Buffer) error { 148 | return EncodeJSONToBuffer(e, b) 149 | } 150 | 151 | func (e *FilterOptions) String() string { 152 | str, _ := e.JSONString() 153 | return str 154 | } 155 | 156 | type LogObject struct { 157 | Type string `json:"type"` 158 | logIndex string `json:"logIndex"` 159 | TransactionIndex string `json:"transactionIndex"` 160 | TransactionHash string `json:"transactionHash"` 161 | BlockHash string `json:"blockHash"` 162 | BlockNumber string `json:"blockNumber"` 163 | Address string `json:"address"` 164 | Data string `json:"data"` 165 | Topics []string `json:"topics"` 166 | } 167 | 168 | func (e *LogObject) JSONByte() ([]byte, error) { 169 | return EncodeJSON(e) 170 | } 171 | 172 | func (e *LogObject) JSONString() (string, error) { 173 | return EncodeJSONString(e) 174 | } 175 | 176 | func (e *LogObject) JSONBuffer(b *bytes.Buffer) error { 177 | return EncodeJSONToBuffer(e, b) 178 | } 179 | 180 | func (e *LogObject) String() string { 181 | str, _ := e.JSONString() 182 | return str 183 | } 184 | 185 | type WhisperMessage struct { 186 | From string `json:"from,omitempty"` 187 | To string `json:"to,omitempty"` 188 | Topics string `json:"topics"` 189 | Payload string `json:"payload"` 190 | Priority string `json:"priority"` 191 | TTL string `json:"ttl"` 192 | } 193 | 194 | func (e *WhisperMessage) JSONByte() ([]byte, error) { 195 | return EncodeJSON(e) 196 | } 197 | 198 | func (e *WhisperMessage) JSONString() (string, error) { 199 | return EncodeJSONString(e) 200 | } 201 | 202 | func (e *WhisperMessage) JSONBuffer(b *bytes.Buffer) error { 203 | return EncodeJSONToBuffer(e, b) 204 | } 205 | 206 | func (e *WhisperMessage) String() string { 207 | str, _ := e.JSONString() 208 | return str 209 | } 210 | 211 | type Message struct { 212 | Hash string `json:"hash"` 213 | From string `json:"from"` 214 | To string `json:"to"` 215 | Expiry string `json:"expiry"` 216 | TTL string `json:"ttl"` 217 | Sent string `json:"sent"` 218 | Topics []string `json:"topics"` 219 | Payload string `json:"payload"` 220 | WorkProved string `json:"workProved"` 221 | } 222 | 223 | func (e *Message) JSONByte() ([]byte, error) { 224 | return EncodeJSON(e) 225 | } 226 | 227 | func (e *Message) JSONString() (string, error) { 228 | return EncodeJSONString(e) 229 | } 230 | 231 | func (e *Message) JSONBuffer(b *bytes.Buffer) error { 232 | return EncodeJSONToBuffer(e, b) 233 | } 234 | 235 | func (e *Message) String() string { 236 | str, _ := e.JSONString() 237 | return str 238 | } 239 | 240 | type Quantity int64 241 | 242 | var _ encoding.TextMarshaler = (*Quantity)(nil) 243 | var _ encoding.TextUnmarshaler = (*Quantity)(nil) 244 | 245 | func (q *Quantity) MarshalText() (text []byte, err error) { 246 | return ([]byte)(IntToQuantity(int64(*q))), nil 247 | } 248 | 249 | func (q *Quantity) UnmarshalText(text []byte) error { 250 | i, err := QuantityToInt(string(text)) 251 | if err != nil { 252 | return err 253 | } 254 | *q = Quantity(i) 255 | return nil 256 | } 257 | 258 | func (e *Quantity) JSONByte() ([]byte, error) { 259 | return EncodeJSON(e) 260 | } 261 | 262 | func (e *Quantity) JSONString() (string, error) { 263 | return EncodeJSONString(e) 264 | } 265 | 266 | func (e *Quantity) JSONBuffer(b *bytes.Buffer) error { 267 | return EncodeJSONToBuffer(e, b) 268 | } 269 | 270 | func (e *Quantity) String() string { 271 | return IntToQuantity(e.Int64()) 272 | } 273 | 274 | func (q *Quantity) Int64() int64 { 275 | return int64(*q) 276 | } 277 | 278 | func NewQuantityFromInt(i int64) *Quantity { 279 | q := new(Quantity) 280 | *q = Quantity(i) 281 | return q 282 | } 283 | 284 | func NewQuantityFromString(s string) *Quantity { 285 | i, _ := QuantityToInt(s) 286 | return NewQuantityFromInt(i) 287 | } 288 | -------------------------------------------------------------------------------- /structures_test.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI_test 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | . "github.com/FactomProject/EthereumAPI" 8 | ) 9 | 10 | func TestQuantityJSON(t *testing.T) { 11 | for i := 0; i < 100; i++ { 12 | q1 := NewQuantityFromInt(int64(i)) 13 | j, err := json.Marshal(q1) 14 | if err != nil { 15 | t.Errorf("%v", err) 16 | } 17 | q2 := new(Quantity) 18 | err = json.Unmarshal(j, q2) 19 | if err != nil { 20 | t.Errorf("%v", err) 21 | } 22 | if int64(*q1) != int64(*q2) { 23 | t.Errorf("q1!=q2 - %v vs %v", q1, q2) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /support.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Factom Foundation 2 | // Use of this source code is governed by the MIT 3 | // license that can be found in the LICENSE file. 4 | 5 | package EthereumAPI 6 | 7 | import ( 8 | "encoding/hex" 9 | "fmt" 10 | "github.com/tonnerre/golang-go.crypto/sha3" 11 | "strconv" 12 | ) 13 | 14 | //https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI 15 | 16 | func IntToQuantity(i int64) string { 17 | return "0x" + IntToQuantityWithoutPrefix(i) 18 | } 19 | 20 | func IntToQuantityWithoutPrefix(i int64) string { 21 | hex := fmt.Sprintf("%x", i) 22 | index := -1 23 | for i := range hex { 24 | if hex[i] == byte('0') { 25 | index = i 26 | } else { 27 | break 28 | } 29 | } 30 | if index > -1 { 31 | hex = hex[index:] 32 | } 33 | if len(hex) == 0 { 34 | hex = "0" 35 | } 36 | return hex 37 | } 38 | 39 | func QuantityToInt(q string) (int64, error) { 40 | //Remove "0x" if it exists 41 | if len(q) > 1 { 42 | if q[0] == '0' && q[1] == 'x' { 43 | q = q[2:] 44 | } 45 | } 46 | 47 | //Making sure the bytes are of even length 48 | if len(q)%2 == 1 { 49 | q = "0" + q 50 | } 51 | 52 | return strconv.ParseInt(q, 16, 64) 53 | } 54 | 55 | func HexToData(b []byte) string { 56 | return "0x" + HexToDataWithoutPrefix(b) 57 | } 58 | 59 | func HexToDataWithoutPrefix(b []byte) string { 60 | return fmt.Sprintf("%x", b) 61 | } 62 | 63 | func HexToPaddedData(b []byte) string { 64 | return "0x" + HexToDataWithoutPrefix(b) 65 | } 66 | 67 | func HexToPaddedDataWithoutPrefix(b []byte) string { 68 | l := len(b) 69 | data := IntToData(int64(l)) 70 | data += fmt.Sprintf("%x", b) 71 | if l%32 != 0 { 72 | rest := make([]byte, 32-l%32) 73 | data += fmt.Sprintf("%x", rest) 74 | } 75 | return data 76 | } 77 | 78 | func DataToHex(data string) ([]byte, error) { 79 | //Remove "0x" if it exists 80 | if len(data) > 1 { 81 | if data[0] == '0' && data[1] == 'x' { 82 | data = data[2:] 83 | } 84 | } 85 | return hex.DecodeString(data) 86 | } 87 | 88 | func StringToMethodID(method string) string { 89 | h := sha3.NewKeccak256() 90 | h.Write([]byte(method)) 91 | var digest [32]byte 92 | h.Sum(digest[:0]) 93 | return fmt.Sprintf("%x", digest[:4]) 94 | } 95 | 96 | func IntToData(i int64) string { 97 | return fmt.Sprintf("%064x", i) 98 | } 99 | 100 | func StringToData(str string) string { 101 | return HexToPaddedData([]byte(str)) 102 | } 103 | 104 | func StringToDataWithoutPrefix(str string) string { 105 | return HexToPaddedDataWithoutPrefix([]byte(str)) 106 | } 107 | -------------------------------------------------------------------------------- /support_test.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI_test 2 | 3 | import ( 4 | "bytes" 5 | . "github.com/FactomProject/EthereumAPI" 6 | "testing" 7 | ) 8 | 9 | func TestIntToQuantity(t *testing.T) { 10 | var i int64 = 0 11 | hex := IntToQuantity(i) 12 | if hex != "0x0" { 13 | t.Errorf("Wrong Quantity for %v - %v", i, hex) 14 | } 15 | 16 | i = 1 17 | hex = IntToQuantity(i) 18 | if hex != "0x1" { 19 | t.Errorf("Wrong Quantity for %v - %v", i, hex) 20 | } 21 | 22 | i = 65 23 | hex = IntToQuantity(i) 24 | if hex != "0x41" { 25 | t.Errorf("Wrong Quantity for %v - %v", i, hex) 26 | } 27 | 28 | i = 1024 29 | hex = IntToQuantity(i) 30 | if hex != "0x400" { 31 | t.Errorf("Wrong Quantity for %v - %v", i, hex) 32 | } 33 | } 34 | 35 | func TestQuantityToInt(t *testing.T) { 36 | var i int64 = 0 37 | i2, err := QuantityToInt(IntToQuantity(i)) 38 | if i != i2 { 39 | t.Errorf("Wrong Quantity for %v - %v", i, i2) 40 | } 41 | 42 | i = 1 43 | i2, err = QuantityToInt(IntToQuantity(i)) 44 | if err != nil { 45 | t.Errorf("Err - %v", err) 46 | } 47 | if i != i2 { 48 | t.Errorf("Wrong Quantity for %v - %v", i, i2) 49 | } 50 | 51 | i = 65 52 | i2, err = QuantityToInt(IntToQuantity(i)) 53 | if err != nil { 54 | t.Errorf("Err - %v", err) 55 | } 56 | if i != i2 { 57 | t.Errorf("Wrong Quantity for %v - %v", i, i2) 58 | } 59 | 60 | i = 1024 61 | i2, err = QuantityToInt(IntToQuantity(i)) 62 | if err != nil { 63 | t.Errorf("Err - %v", err) 64 | } 65 | if i != i2 { 66 | t.Errorf("Wrong Quantity for %v - %v", i, i2) 67 | } 68 | } 69 | 70 | func TestHexToData(t *testing.T) { 71 | var i []byte = []byte("A") 72 | hex := HexToData(i) 73 | if hex != "0x41" { 74 | t.Errorf("Wrong Data for %x - %v", i, hex) 75 | } 76 | 77 | i = []byte{0x00, 0x42, 0x00} 78 | hex = HexToData(i) 79 | if hex != "0x004200" { 80 | t.Errorf("Wrong Data for %x - %v", i, hex) 81 | } 82 | 83 | i = []byte("") 84 | hex = HexToData(i) 85 | if hex != "0x" { 86 | t.Errorf("Wrong Data for %x - %v", i, hex) 87 | } 88 | } 89 | 90 | func TestDataToHex(t *testing.T) { 91 | var i []byte = []byte("ABBA") 92 | hex, err := DataToHex(HexToData(i)) 93 | if err != nil { 94 | t.Errorf("Err - %v", err) 95 | } 96 | if bytes.Compare(i, hex) != 0 { 97 | t.Errorf("%x != %x", i, hex) 98 | } 99 | 100 | i = []byte("") 101 | hex, err = DataToHex(HexToData(i)) 102 | if err != nil { 103 | t.Errorf("Err - %v", err) 104 | } 105 | if bytes.Compare(i, hex) != 0 { 106 | t.Errorf("%x != %x", i, hex) 107 | } 108 | 109 | i = []byte("A") 110 | hex, err = DataToHex(HexToData(i)) 111 | if err != nil { 112 | t.Errorf("Err - %v", err) 113 | } 114 | if bytes.Compare(i, hex) != 0 { 115 | t.Errorf("%x != %x", i, hex) 116 | } 117 | 118 | i = []byte{0x00, 0x42, 0x00} 119 | hex, err = DataToHex(HexToData(i)) 120 | if err != nil { 121 | t.Errorf("Err - %v", err) 122 | } 123 | if bytes.Compare(i, hex) != 0 { 124 | t.Errorf("%x != %x", i, hex) 125 | } 126 | } 127 | 128 | func TestStringToMethodID(t *testing.T) { 129 | id := StringToMethodID("baz(uint32,bool)") 130 | if id != "cdcd77c0" { 131 | t.Errorf("Invalid MethodID - %v", id) 132 | } 133 | id = StringToMethodID("bar(fixed128x128[2])") 134 | if id != "ab55044d" { 135 | t.Errorf("Invalid MethodID - %v", id) 136 | } 137 | } 138 | 139 | func TestIntToData(t *testing.T) { 140 | d := IntToData(69) 141 | if d != "0000000000000000000000000000000000000000000000000000000000000045" { 142 | t.Errorf("Invalid data - %v", d) 143 | } 144 | } 145 | 146 | func TestStringToDataWithoutPrefix(t *testing.T) { 147 | str := StringToDataWithoutPrefix("Hello, world!") 148 | if str != "000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000" { 149 | t.Errorf("Invalid data - %v", str) 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /txpool.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/go-ethereum/wiki/Management-APIs#txpool 8 | 9 | //TODO: finish 10 | func TxPoolContent() (interface{}, error) { 11 | resp, err := Call("txpool_content", nil) 12 | if err != nil { 13 | return nil, err 14 | } 15 | if resp.Error != nil { 16 | return nil, fmt.Errorf(resp.Error.Message) 17 | } 18 | return resp.Result, nil 19 | } 20 | 21 | //TODO: finish 22 | func TxPoolInspect() (interface{}, error) { 23 | resp, err := Call("txpool_inspect", nil) 24 | if err != nil { 25 | return nil, err 26 | } 27 | if resp.Error != nil { 28 | return nil, fmt.Errorf(resp.Error.Message) 29 | } 30 | return resp.Result, nil 31 | } 32 | 33 | //TODO: finish 34 | func TxPoolStatus() (interface{}, error) { 35 | resp, err := Call("txpool_status", nil) 36 | if err != nil { 37 | return nil, err 38 | } 39 | if resp.Error != nil { 40 | return nil, fmt.Errorf(resp.Error.Message) 41 | } 42 | return resp.Result, nil 43 | } 44 | -------------------------------------------------------------------------------- /web3.go: -------------------------------------------------------------------------------- 1 | package EthereumAPI 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | //https://github.com/ethereum/wiki/wiki/JSON-RPC 8 | 9 | func Web3ClientVersion() (string, error) { 10 | resp, err := Call("web3_clientVersion", nil) 11 | if err != nil { 12 | return "", err 13 | } 14 | if resp.Error != nil { 15 | return "", fmt.Errorf(resp.Error.Message) 16 | } 17 | return resp.Result.(string), nil 18 | } 19 | 20 | func Web3Sha3(data string) (string, error) { 21 | resp, err := Call("web3_sha3", []interface{}{data}) 22 | if err != nil { 23 | return "", err 24 | } 25 | if resp.Error != nil { 26 | return "", fmt.Errorf(resp.Error.Message) 27 | } 28 | return resp.Result.(string), nil 29 | } 30 | --------------------------------------------------------------------------------