diff options
Diffstat (limited to 'rpc')
-rw-r--r-- | rpc/api.go | 585 | ||||
-rw-r--r-- | rpc/api_test.go | 18 | ||||
-rw-r--r-- | rpc/args.go | 576 | ||||
-rw-r--r-- | rpc/args_test.go | 434 | ||||
-rw-r--r-- | rpc/messages.go | 384 | ||||
-rw-r--r-- | rpc/util.go | 7 |
6 files changed, 1186 insertions, 818 deletions
diff --git a/rpc/api.go b/rpc/api.go index 70a8cf9b4..dc0945d19 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -1,14 +1,7 @@ -/* -For each request type, define the following: - -1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder() -2. json.Decoder() calls "UnmarshalON" defined on each "Args" struct -3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to ON - -*/ package rpc import ( + "encoding/json" "math/big" "strings" "sync" @@ -50,20 +43,20 @@ type EthereumApi struct { db ethutil.Database - defaultBlockAge int64 + // defaultBlockAge int64 } func NewEthereumApi(eth *xeth.XEth) *EthereumApi { db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ - eth: eth, - mux: eth.Backend().EventMux(), - quit: make(chan struct{}), - filterManager: filter.NewFilterManager(eth.Backend().EventMux()), - logs: make(map[int]*logFilter), - messages: make(map[int]*whisperFilter), - db: db, - defaultBlockAge: -1, + eth: eth, + mux: eth.Backend().EventMux(), + quit: make(chan struct{}), + filterManager: filter.NewFilterManager(eth.Backend().EventMux()), + logs: make(map[int]*logFilter), + messages: make(map[int]*whisperFilter), + db: db, + // defaultBlockAge: -1, } go api.filterManager.Start() go api.start() @@ -71,36 +64,36 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi { return api } -func (self *EthereumApi) setStateByBlockNumber(num int64) { - chain := self.xeth().Backend().ChainManager() - var block *types.Block +// func (self *EthereumApi) setStateByBlockNumber(num int64) { +// chain := self.xeth().Backend().ChainManager() +// var block *types.Block - if self.defaultBlockAge < 0 { - num = chain.CurrentBlock().Number().Int64() + num + 1 - } - block = chain.GetBlockByNumber(uint64(num)) +// if self.defaultBlockAge < 0 { +// num = chain.CurrentBlock().Number().Int64() + num + 1 +// } +// block = chain.GetBlockByNumber(uint64(num)) - if block != nil { - self.useState(state.New(block.Root(), self.xeth().Backend().StateDb())) - } else { - self.useState(chain.State()) - } -} +// if block != nil { +// self.useState(state.New(block.Root(), self.xeth().Backend().StateDb())) +// } else { +// self.useState(chain.State()) +// } +// } func (self *EthereumApi) start() { timer := time.NewTicker(filterTickerTime) - events := self.mux.Subscribe(core.ChainEvent{}) + // events := self.mux.Subscribe(core.ChainEvent{}) done: for { select { - case ev := <-events.Chan(): - switch ev.(type) { - case core.ChainEvent: - if self.defaultBlockAge < 0 { - self.setStateByBlockNumber(self.defaultBlockAge) - } - } + // case ev := <-events.Chan(): + // switch ev.(type) { + // case core.ChainEvent: + // if self.defaultBlockAge < 0 { + // self.setStateByBlockNumber(self.defaultBlockAge) + // } + // } case <-timer.C: self.logMut.Lock() self.messagesMut.Lock() @@ -129,35 +122,35 @@ func (self *EthereumApi) stop() { close(self.quit) } -func (self *EthereumApi) Register(args string, reply *interface{}) error { - self.regmut.Lock() - defer self.regmut.Unlock() +// func (self *EthereumApi) Register(args string, reply *interface{}) error { +// self.regmut.Lock() +// defer self.regmut.Unlock() - if _, ok := self.register[args]; ok { - self.register[args] = nil // register with empty - } - return nil -} +// if _, ok := self.register[args]; ok { +// self.register[args] = nil // register with empty +// } +// return nil +// } -func (self *EthereumApi) Unregister(args string, reply *interface{}) error { - self.regmut.Lock() - defer self.regmut.Unlock() +// func (self *EthereumApi) Unregister(args string, reply *interface{}) error { +// self.regmut.Lock() +// defer self.regmut.Unlock() - delete(self.register, args) +// delete(self.register, args) - return nil -} +// return nil +// } -func (self *EthereumApi) WatchTx(args string, reply *interface{}) error { - self.regmut.Lock() - defer self.regmut.Unlock() +// func (self *EthereumApi) WatchTx(args string, reply *interface{}) error { +// self.regmut.Lock() +// defer self.regmut.Unlock() - txs := self.register[args] - self.register[args] = nil +// txs := self.register[args] +// self.register[args] = nil - *reply = txs - return nil -} +// *reply = txs +// return nil +// } func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error { var id int @@ -239,23 +232,13 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error return nil } -func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { - // This seems a bit precarious Maybe worth splitting to discrete functions - if len(args.Hash) > 0 { - *reply = p.xeth().BlockByHash(args.Hash) - } else { - *reply = p.xeth().BlockByNumber(args.BlockNumber) - } - return nil -} - func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { - if len(args.Gas) == 0 { - args.Gas = defaultGas.String() + if args.Gas == ethutil.Big0 { + args.Gas = defaultGas } - if len(args.GasPrice) == 0 { - args.GasPrice = defaultGasPrice.String() + if args.GasPrice == ethutil.Big0 { + args.GasPrice = defaultGasPrice } // TODO if no_private_key then @@ -279,7 +262,10 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { p.register[ags.From] = append(p.register[args.From], args) } */ - result, _ := p.xeth().Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) + result, err := p.xeth().Transact( /* TODO specify account */ args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data) + if err != nil { + return err + } *reply = result //} @@ -287,7 +273,7 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { } func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error { - result, err := p.xeth().Call( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) + result, err := p.xeth().Call( /* TODO specify account */ args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data) if err != nil { return err } @@ -296,22 +282,27 @@ func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error { return nil } -func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error { - err := args.requirementsPushTx() - if err != nil { +func (p *EthereumApi) GetBalance(args *GetBalanceArgs, reply *interface{}) error { + if err := args.requirements(); err != nil { return err } - result, _ := p.xeth().PushTx(args.Tx) - *reply = result + state := p.xeth().State().SafeGet(args.Address) + *reply = toHex(state.Balance().Bytes()) return nil } -func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error { - err := args.requirements() - if err != nil { +func (p *EthereumApi) GetStorage(args *GetStorageArgs, reply *interface{}) error { + if err := args.requirements(); err != nil { return err } + *reply = p.xeth().State().SafeGet(args.Address).Storage() + return nil +} +func (p *EthereumApi) GetStorageAt(args *GetStorageAtArgs, reply *interface{}) error { + if err := args.requirements(); err != nil { + return err + } state := p.xeth().State().SafeGet(args.Address) value := state.StorageString(args.Key) @@ -328,64 +319,6 @@ func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error { return nil } -func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error { - err := args.requirements() - if err != nil { - return err - } - - *reply = p.xeth().State().SafeGet(args.Address).Storage() - return nil -} - -func (p *EthereumApi) GetPeerCount(reply *interface{}) error { - *reply = p.xeth().PeerCount() - return nil -} - -func (p *EthereumApi) GetIsListening(reply *interface{}) error { - *reply = p.xeth().IsListening() - return nil -} - -func (p *EthereumApi) GetCoinbase(reply *interface{}) error { - *reply = p.xeth().Coinbase() - return nil -} - -func (p *EthereumApi) Accounts(reply *interface{}) error { - *reply = p.xeth().Accounts() - return nil -} - -func (p *EthereumApi) GetIsMining(reply *interface{}) error { - *reply = p.xeth().IsMining() - return nil -} - -func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error { - *reply = p.xeth().SetMining(shouldmine) - return nil -} - -func (p *EthereumApi) GetDefaultBlockAge(reply *interface{}) error { - *reply = p.defaultBlockAge - return nil -} - -func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int64, reply *interface{}) error { - p.defaultBlockAge = defaultBlockAge - p.setStateByBlockNumber(p.defaultBlockAge) - - *reply = true - return nil -} - -func (p *EthereumApi) BlockNumber(reply *interface{}) error { - *reply = p.xeth().Backend().ChainManager().CurrentBlock().Number() - return nil -} - func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error { err := args.requirements() if err != nil { @@ -395,19 +328,8 @@ func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) err return nil } -func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error { - err := args.requirements() - if err != nil { - return err - } - state := p.xeth().State().SafeGet(args.Address) - *reply = toHex(state.Balance().Bytes()) - return nil -} - -func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { - err := args.requirements() - if err != nil { +func (p *EthereumApi) GetData(args *GetDataArgs, reply *interface{}) error { + if err := args.requirements(); err != nil { return err } *reply = p.xeth().CodeAt(args.Address) @@ -415,28 +337,13 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { } func (p *EthereumApi) GetCompilers(reply *interface{}) error { - c := []string{"serpent"} + c := []string{""} *reply = c return nil } -func (p *EthereumApi) CompileSerpent(script string, reply *interface{}) error { - res, err := ethutil.Compile(script, false) - if err != nil { - return err - } - *reply = res - return nil -} - -func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { - *reply = toHex(crypto.Sha3(fromHex(args.Data))) - return nil -} - func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error { - err := args.requirements() - if err != nil { + if err := args.requirements(); err != nil { return err } @@ -446,8 +353,7 @@ func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error { } func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error { - err := args.requirements() - if err != nil { + if err := args.requirements(); err != nil { return err } @@ -461,14 +367,18 @@ func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error { return nil } -func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) error { +func (p *EthereumApi) NewWhisperFilter(args *WhisperFilterArgs, reply *interface{}) error { var id int - args.Fn = func(msg xeth.WhisperMessage) { + opts := new(xeth.Options) + opts.From = args.From + opts.To = args.To + opts.Topics = args.Topics + opts.Fn = func(msg xeth.WhisperMessage) { p.messagesMut.Lock() defer p.messagesMut.Unlock() p.messages[id].add(msg) // = append(p.messages[id], msg) } - id = p.xeth().Whisper().Watch(args) + id = p.xeth().Whisper().Watch(opts) p.messages[id] = &whisperFilter{timeout: time.Now()} *reply = id return nil @@ -509,195 +419,212 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) switch req.Method { - case "eth_coinbase": - return p.GetCoinbase(reply) - case "eth_listening": - return p.GetIsListening(reply) - case "eth_mining": - return p.GetIsMining(reply) - case "eth_setMining": - args, err := req.ToBoolArgs() - if err != nil { - return err - } - return p.SetMining(args, reply) - case "eth_defaultBlock": - return p.GetDefaultBlockAge(reply) - case "eth_setDefaultBlock": - args, err := req.ToIntArgs() - if err != nil { + case "web3_sha3": + args := new(Sha3Args) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.SetDefaultBlockAge(int64(args), reply) - case "eth_peerCount": - return p.GetPeerCount(reply) - case "eth_number": - return p.BlockNumber(reply) + *reply = toHex(crypto.Sha3(fromHex(args.Data))) + case "net_listening": + *reply = p.xeth().IsListening() + case "net_peerCount": + *reply = toHex(big.NewInt(int64(p.xeth().PeerCount())).Bytes()) + case "eth_coinbase": + *reply = p.xeth().Coinbase() + case "eth_mining": + *reply = p.xeth().IsMining() + case "eth_gasPrice": + *reply = toHex(defaultGasPrice.Bytes()) case "eth_accounts": - return p.Accounts(reply) - case "eth_countAt": - args, err := req.ToGetTxCountArgs() - if err != nil { + *reply = p.xeth().Accounts() + case "eth_blockNumber": + *reply = toHex(p.xeth().Backend().ChainManager().CurrentBlock().Number().Bytes()) + case "eth_getBalance": + // TODO handle BlockNumber + args := new(GetBalanceArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.GetTxCountAt(args, reply) - case "eth_codeAt": - args, err := req.ToGetCodeAtArgs() - if err != nil { + return p.GetBalance(args, reply) + case "eth_getStorage": + // TODO handle BlockNumber + args := new(GetStorageArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.GetCodeAt(args, reply) - case "eth_balanceAt": - args, err := req.ToGetBalanceArgs() - if err != nil { + return p.GetStorage(args, reply) + case "eth_getStorageAt": + // TODO handle BlockNumber + args := new(GetStorageAtArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.GetBalanceAt(args, reply) - case "eth_stateAt": - args, err := req.ToGetStateArgs() - if err != nil { - return err - } - return p.GetStateAt(args, reply) - case "eth_storageAt": - args, err := req.ToStorageAtArgs() - if err != nil { + return p.GetStorageAt(args, reply) + case "eth_getTransactionCount": + // TODO handle BlockNumber + args := new(GetTxCountArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.GetStorageAt(args, reply) - case "eth_blockByNumber", "eth_blockByHash": - args, err := req.ToGetBlockArgs() - if err != nil { + return p.GetTxCountAt(args, reply) + case "eth_getBlockTransactionCountByHash": + case "eth_getBlockTransactionCountByNumber": + case "eth_getUncleCountByBlockHash": + case "eth_getUncleCountByBlockNumber": + return errNotImplemented + case "eth_getData": + // TODO handle BlockNumber + args := new(GetDataArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.GetBlock(args, reply) - case "eth_transact": - args, err := req.ToNewTxArgs() - if err != nil { + return p.GetData(args, reply) + case "eth_sendTransaction": + args := new(NewTxArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } return p.Transact(args, reply) case "eth_call": - args, err := req.ToNewTxArgs() - if err != nil { + args := new(NewTxArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } return p.Call(args, reply) - case "eth_newFilter": - args, err := req.ToFilterArgs() - if err != nil { - return err - } - return p.NewFilter(args, reply) - case "eth_newFilterString": - args, err := req.ToFilterStringArgs() - if err != nil { - return err - } - return p.NewFilterString(args, reply) - case "eth_uninstallFilter": - args, err := req.ToUninstallFilterArgs() - if err != nil { + case "eth_flush": + return errNotImplemented + case "eth_getBlockByHash": + // TODO handle second param for "include transaction objects" + args := new(GetBlockByHashArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.UninstallFilter(args, reply) - case "eth_changed": - args, err := req.ToIdArgs() - if err != nil { + *reply = p.xeth().BlockByHash(args.BlockHash) + case "eth_getBlockByNumber": + // TODO handle second param for "include transaction objects" + args := new(GetBlockByNumberArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.FilterChanged(args, reply) - case "eth_filterLogs": - args, err := req.ToIdArgs() - if err != nil { - return err - } - return p.Logs(args, reply) - case "eth_logs": - args, err := req.ToFilterArgs() - if err != nil { + *reply = p.xeth().BlockByNumber(args.BlockNumber) + case "eth_getTransactionByHash": + case "eth_getTransactionByBlockHashAndIndex": + case "eth_getTransactionByBlockNumberAndIndex": + case "eth_getUncleByBlockHashAndIndex": + case "eth_getUncleByBlockNumberAndIndex": + return errNotImplemented + case "eth_getCompilers": + return p.GetCompilers(reply) + case "eth_compileSolidity": + case "eth_compileLLL": + case "eth_compileSerpent": + return errNotImplemented + case "eth_newFilter": + args := new(FilterOptions) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.AllLogs(args, reply) - case "eth_gasPrice": - *reply = toHex(defaultGasPrice.Bytes()) - return nil - case "eth_register": - args, err := req.ToRegisterArgs() - if err != nil { + return p.NewFilter(args, reply) + case "eth_newBlockFilter": + args := new(FilterStringArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.Register(args, reply) - case "eth_unregister": - args, err := req.ToRegisterArgs() - if err != nil { + return p.NewFilterString(args.Word, reply) + case "eth_uninstallFilter": + args := new(FilterIdArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.Unregister(args, reply) - case "eth_watchTx": - args, err := req.ToWatchTxArgs() - if err != nil { + return p.UninstallFilter(args.Id, reply) + case "eth_getFilterChanges": + args := new(FilterIdArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.WatchTx(args, reply) - case "eth_compilers": - return p.GetCompilers(reply) - case "eth_serpent": - args, err := req.ToCompileArgs() - if err != nil { + return p.FilterChanged(args.Id, reply) + case "eth_getFilterLogs": + args := new(FilterIdArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.CompileSerpent(args, reply) - case "web3_sha3": - args, err := req.ToSha3Args() - if err != nil { + return p.Logs(args.Id, reply) + case "eth_getLogs": + args := new(FilterOptions) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.Sha3(args, reply) + return p.AllLogs(args, reply) + case "eth_getWork": + case "eth_submitWork": + return errNotImplemented case "db_put": - args, err := req.ToDbPutArgs() - if err != nil { + args := new(DbArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } return p.DbPut(args, reply) case "db_get": - args, err := req.ToDbGetArgs() - if err != nil { + args := new(DbArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } return p.DbGet(args, reply) - case "shh_newIdentity": - return p.NewWhisperIdentity(reply) - case "shh_newFilter": - args, err := req.ToWhisperFilterArgs() - if err != nil { + case "shh_post": + args := new(WhisperMessageArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.NewWhisperFilter(args, reply) - case "shh_changed": - args, err := req.ToIdArgs() - if err != nil { + return p.WhisperPost(args, reply) + case "shh_newIdentity": + return p.NewWhisperIdentity(reply) + case "shh_hasIdentity": + args := new(WhisperIdentityArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.MessagesChanged(args, reply) - case "shh_post": - args, err := req.ToWhisperPostArgs() - if err != nil { + return p.HasWhisperIdentity(args.Identity, reply) + case "shh_newGroup": + case "shh_addToGroup": + return errNotImplemented + case "shh_newFilter": + args := new(WhisperFilterArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.WhisperPost(args, reply) - case "shh_haveIdentity": - args, err := req.ToWhisperHasIdentityArgs() - if err != nil { + return p.NewWhisperFilter(args, reply) + case "shh_uninstallFilter": + return errNotImplemented + case "shh_getFilterChanges": + args := new(FilterIdArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.HasWhisperIdentity(args, reply) + return p.MessagesChanged(args.Id, reply) case "shh_getMessages": - args, err := req.ToIdArgs() - if err != nil { + args := new(FilterIdArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { return err } - return p.WhisperMessages(args, reply) + return p.WhisperMessages(args.Id, reply) + // case "eth_register": + // args, err := req.ToRegisterArgs() + // if err != nil { + // return err + // } + // return p.Register(args, reply) + // case "eth_unregister": + // args, err := req.ToRegisterArgs() + // if err != nil { + // return err + // } + // return p.Unregister(args, reply) + // case "eth_watchTx": + // args, err := req.ToWatchTxArgs() + // if err != nil { + // return err + // } + // return p.WatchTx(args, reply) default: return NewErrorWithMessage(errNotImplemented, req.Method) } @@ -719,3 +646,39 @@ func (self *EthereumApi) useState(statedb *state.StateDB) { self.eth = self.eth.UseState(statedb) } + +func toFilterOptions(options *FilterOptions) core.FilterOptions { + var opts core.FilterOptions + + // Convert optional address slice/string to byte slice + if str, ok := options.Address.(string); ok { + opts.Address = [][]byte{fromHex(str)} + } else if slice, ok := options.Address.([]interface{}); ok { + bslice := make([][]byte, len(slice)) + for i, addr := range slice { + if saddr, ok := addr.(string); ok { + bslice[i] = fromHex(saddr) + } + } + opts.Address = bslice + } + + opts.Earliest = options.Earliest + opts.Latest = options.Latest + + topics := make([][][]byte, len(options.Topics)) + for i, topicDat := range options.Topics { + if slice, ok := topicDat.([]interface{}); ok { + topics[i] = make([][]byte, len(slice)) + for j, topic := range slice { + topics[i][j] = fromHex(topic.(string)) + } + } else if str, ok := topicDat.(string); ok { + topics[i] = make([][]byte, 1) + topics[i][0] = fromHex(str) + } + } + opts.Topics = topics + + return opts +} diff --git a/rpc/api_test.go b/rpc/api_test.go index a9fc16cd3..ec03822c5 100644 --- a/rpc/api_test.go +++ b/rpc/api_test.go @@ -1,11 +1,29 @@ package rpc import ( + "encoding/json" "sync" "testing" "time" ) +func TestWeb3Sha3(t *testing.T) { + jsonstr := `{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}` + expected := "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad" + + api := &EthereumApi{} + + var req RpcRequest + json.Unmarshal([]byte(jsonstr), &req) + + var response interface{} + _ = api.GetRequestReply(&req, &response) + + if response.(string) != expected { + t.Errorf("Expected %s got %s", expected, response) + } +} + func TestFilterClose(t *testing.T) { t.Skip() api := &EthereumApi{ diff --git a/rpc/args.go b/rpc/args.go index ea8489585..63969e598 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -1,183 +1,275 @@ package rpc -import "encoding/json" +import ( + "bytes" + "encoding/json" + "math/big" -import "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/ethutil" +) -type GetBlockArgs struct { - BlockNumber int32 - Hash string +type GetBlockByHashArgs struct { + BlockHash string + Transactions bool } -func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { - argint, argstr := int32(0), "" - if err = json.Unmarshal(b, &argint); err == nil { - obj.BlockNumber = argint - return +func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs } - if err = json.Unmarshal(b, &argstr); err == nil { - obj.Hash = argstr - return + + if len(obj) < 1 { + return errArguments } - return errDecodeArgs + args.BlockHash = obj[0].(string) + + if len(obj) > 1 { + args.Transactions = obj[1].(bool) + } + + return nil } -type NewTxArgs struct { - From string `json:"from"` - To string `json:"to"` - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - Data string `json:"data"` +type GetBlockByNumberArgs struct { + BlockNumber int64 + Transactions bool } -func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { - // Data can be either specified as "data" or "code" :-/ - var ext struct { - From string - To string - Value string - Gas string - GasPrice string - Data string - Code string +func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs } - if err = json.Unmarshal(b, &ext); err == nil { - if len(ext.Data) == 0 { - ext.Data = ext.Code - } - obj.From = ext.From - obj.To = ext.To - obj.Value = ext.Value - obj.Gas = ext.Gas - obj.GasPrice = ext.GasPrice - obj.Data = ext.Data + if len(obj) < 1 { + return errArguments + } + args.BlockNumber = ethutil.Big(obj[0].(string)).Int64() - return + if len(obj) > 1 { + args.Transactions = obj[1].(bool) } - return errDecodeArgs + return nil } -type PushTxArgs struct { - Tx string `json:"tx"` +type NewTxArgs struct { + From string + To string + Value *big.Int + Gas *big.Int + GasPrice *big.Int + Data string } -func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, &arg0); err == nil { - obj.Tx = arg0 - return +func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) { + var obj []struct { + From string `json:"from"` + To string `json:"to"` + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Data string `json:"data"` + } + + if err = json.Unmarshal(b, &obj); err != nil { + return errDecodeArgs } - return errDecodeArgs -} -func (a *PushTxArgs) requirementsPushTx() error { - if a.Tx == "" { - return NewErrorWithMessage(errArguments, "PushTx requires a 'tx' as argument") + if len(obj) < 1 { + return errArguments } + args.From = obj[0].From + args.To = obj[0].To + args.Value = ethutil.Big(obj[0].Value) + args.Gas = ethutil.Big(obj[0].Gas) + args.GasPrice = ethutil.Big(obj[0].GasPrice) + args.Data = obj[0].Data + return nil } type GetStorageArgs struct { - Address string + Address string + BlockNumber int64 } -func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { - if err = json.Unmarshal(b, &obj.Address); err != nil { +func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { return errDecodeArgs } - return + + if len(obj) < 1 { + return errArguments + } + args.Address = obj[0].(string) + + if len(obj) > 1 { + if obj[1].(string) == "latest" { + args.BlockNumber = -1 + } else { + args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() + } + } + + return nil } -func (a *GetStorageArgs) requirements() error { - if len(a.Address) == 0 { - return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument") +func (args *GetStorageArgs) requirements() error { + if len(args.Address) == 0 { + return NewErrorWithMessage(errArguments, "Address cannot be blank") } return nil } -type GetStateArgs struct { - Address string - Key string +type GetStorageAtArgs struct { + Address string + Key string + BlockNumber int64 } -func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, &arg0); err == nil { - obj.Address = arg0 - return +func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs } - return errDecodeArgs + + if len(obj) < 2 { + return errArguments + } + args.Address = obj[0].(string) + args.Key = obj[1].(string) + + if len(obj) > 2 { + if obj[2].(string) == "latest" { + args.BlockNumber = -1 + } else { + args.BlockNumber = ethutil.Big(obj[2].(string)).Int64() + } + } + + return nil } -func (a *GetStateArgs) requirements() error { - if a.Address == "" { - return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument") +func (args *GetStorageAtArgs) requirements() error { + if len(args.Address) == 0 { + return NewErrorWithMessage(errArguments, "Address cannot be blank") } - if a.Key == "" { - return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'key' value as argument") + + if len(args.Key) == 0 { + return NewErrorWithMessage(errArguments, "Key cannot be blank") } return nil } type GetTxCountArgs struct { - Address string `json:"address"` + Address string + BlockNumber int64 } -func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, &arg0); err == nil { - obj.Address = arg0 - return +func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errArguments + } - return errDecodeArgs + args.Address = obj[0].(string) + + if len(obj) > 1 { + if obj[1].(string) == "latest" { + args.BlockNumber = -1 + } else { + args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() + } + } + + return nil } -func (a *GetTxCountArgs) requirements() error { - if a.Address == "" { - return NewErrorWithMessage(errArguments, "GetTxCountAt requires an 'address' value as argument") +func (args *GetTxCountArgs) requirements() error { + if len(args.Address) == 0 { + return NewErrorWithMessage(errArguments, "Address cannot be blank") } return nil } type GetBalanceArgs struct { - Address string + Address string + BlockNumber int64 } -func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, &arg0); err == nil { - obj.Address = arg0 - return +func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errArguments + } + args.Address = obj[0].(string) + + if len(obj) > 1 { + if obj[1].(string) == "latest" { + args.BlockNumber = -1 + } else { + args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() + } } - return errDecodeArgs + + return nil } -func (a *GetBalanceArgs) requirements() error { - if a.Address == "" { - return NewErrorWithMessage(errArguments, "GetBalanceAt requires an 'address' value as argument") +func (args *GetBalanceArgs) requirements() error { + if len(args.Address) == 0 { + return NewErrorWithMessage(errArguments, "Address cannot be blank") } return nil } -type GetCodeAtArgs struct { - Address string +type GetDataArgs struct { + Address string + BlockNumber int64 } -func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, &arg0); err == nil { - obj.Address = arg0 - return +func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errArguments + } + args.Address = obj[0].(string) + + if len(obj) > 1 { + if obj[1].(string) == "latest" { + args.BlockNumber = -1 + } else { + args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() + } } - return errDecodeArgs + + return nil } -func (a *GetCodeAtArgs) requirements() error { - if a.Address == "" { - return NewErrorWithMessage(errArguments, "GetCodeAt requires an 'address' value as argument") +func (args *GetDataArgs) requirements() error { + if len(args.Address) == 0 { + return NewErrorWithMessage(errArguments, "Address cannot be blank") } return nil } @@ -186,74 +278,129 @@ type Sha3Args struct { Data string } -func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { - if err = json.Unmarshal(b, &obj.Data); err != nil { - return errDecodeArgs +func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return NewErrorWithMessage(errDecodeArgs, err.Error()) + } + + if len(obj) < 1 { + return errArguments } - return + args.Data = obj[0].(string) + + return nil } +// type FilterArgs struct { +// FromBlock uint64 +// ToBlock uint64 +// Limit uint64 +// Offset uint64 +// Address string +// Topics []string +// } + +// func (args *FilterArgs) UnmarshalJSON(b []byte) (err error) { +// var obj []struct { +// FromBlock string `json:"fromBlock"` +// ToBlock string `json:"toBlock"` +// Limit string `json:"limit"` +// Offset string `json:"offset"` +// Address string `json:"address"` +// Topics []string `json:"topics"` +// } + +// if err = json.Unmarshal(b, &obj); err != nil { +// return errDecodeArgs +// } + +// if len(obj) < 1 { +// return errArguments +// } +// args.FromBlock = uint64(ethutil.Big(obj[0].FromBlock).Int64()) +// args.ToBlock = uint64(ethutil.Big(obj[0].ToBlock).Int64()) +// args.Limit = uint64(ethutil.Big(obj[0].Limit).Int64()) +// args.Offset = uint64(ethutil.Big(obj[0].Offset).Int64()) +// args.Address = obj[0].Address +// args.Topics = obj[0].Topics + +// return nil +// } + type FilterOptions struct { Earliest int64 Latest int64 Address interface{} - Topic []interface{} + Topics []interface{} Skip int Max int } -func toFilterOptions(options *FilterOptions) core.FilterOptions { - var opts core.FilterOptions +func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) { + var obj []struct { + FromBlock string `json:"fromBlock"` + ToBlock string `json:"toBlock"` + Limit string `json:"limit"` + Offset string `json:"offset"` + Address string `json:"address"` + Topics []interface{} `json:"topics"` + } - // Convert optional address slice/string to byte slice - if str, ok := options.Address.(string); ok { - opts.Address = [][]byte{fromHex(str)} - } else if slice, ok := options.Address.([]interface{}); ok { - bslice := make([][]byte, len(slice)) - for i, addr := range slice { - if saddr, ok := addr.(string); ok { - bslice[i] = fromHex(saddr) - } - } - opts.Address = bslice - } - - opts.Earliest = options.Earliest - opts.Latest = options.Latest - - topics := make([][][]byte, len(options.Topic)) - for i, topicDat := range options.Topic { - if slice, ok := topicDat.([]interface{}); ok { - topics[i] = make([][]byte, len(slice)) - for j, topic := range slice { - topics[i][j] = fromHex(topic.(string)) - } - } else if str, ok := topicDat.(string); ok { - topics[i] = make([][]byte, 1) - topics[i][0] = fromHex(str) - } + if err = json.Unmarshal(b, &obj); err != nil { + return errDecodeArgs } - opts.Topics = topics - return opts -} + if len(obj) < 1 { + return errArguments + } + args.Earliest = int64(ethutil.Big(obj[0].FromBlock).Int64()) + args.Latest = int64(ethutil.Big(obj[0].ToBlock).Int64()) + args.Max = int(ethutil.Big(obj[0].Limit).Int64()) + args.Skip = int(ethutil.Big(obj[0].Offset).Int64()) + args.Address = obj[0].Address + args.Topics = obj[0].Topics -type FilterChangedArgs struct { - n int + return nil } +// type FilterChangedArgs struct { +// n int +// } + type DbArgs struct { Database string Key string Value string } +func (args *DbArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 2 { + return errArguments + } + args.Database = obj[0].(string) + args.Key = obj[1].(string) + + if len(obj) > 2 { + args.Value = obj[2].(string) + } + + return nil +} + func (a *DbArgs) requirements() error { if len(a.Database) == 0 { - return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Database' value as argument") + return NewErrorWithMessage(errArguments, "Database cannot be blank") } if len(a.Key) == 0 { - return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Key' value as argument") + return NewErrorWithMessage(errArguments, "Key cannot be blank") } return nil } @@ -266,3 +413,136 @@ type WhisperMessageArgs struct { Priority uint32 Ttl uint32 } + +func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) { + var obj []struct { + Payload string + To string + From string + Topic []string + Priority string + Ttl string + } + + if err = json.Unmarshal(b, &obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errArguments + } + args.Payload = obj[0].Payload + args.To = obj[0].To + args.From = obj[0].From + args.Topic = obj[0].Topic + args.Priority = uint32(ethutil.Big(obj[0].Priority).Int64()) + args.Ttl = uint32(ethutil.Big(obj[0].Ttl).Int64()) + + return nil +} + +type CompileArgs struct { + Source string +} + +func (args *CompileArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) > 0 { + args.Source = obj[0].(string) + } + + return nil +} + +type FilterStringArgs struct { + Word string +} + +func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) { + var obj []string + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errDecodeArgs + } + + args.Word = obj[0] + + return nil +} + +type FilterIdArgs struct { + Id int +} + +func (args *FilterIdArgs) UnmarshalJSON(b []byte) (err error) { + var obj []string + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errDecodeArgs + } + + args.Id = int(ethutil.Big(obj[0]).Int64()) + + return nil +} + +type WhisperIdentityArgs struct { + Identity string +} + +func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) { + var obj []string + r := bytes.NewReader(b) + if err := json.NewDecoder(r).Decode(&obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errDecodeArgs + } + + args.Identity = obj[0] + + return nil +} + +type WhisperFilterArgs struct { + To string `json:"to"` + From string + Topics []string +} + +func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) { + var obj []struct { + To string + From string + Topics []string + } + + if err = json.Unmarshal(b, &obj); err != nil { + return errDecodeArgs + } + + if len(obj) < 1 { + return errArguments + } + + args.To = obj[0].To + args.From = obj[0].From + args.Topics = obj[0].Topics + + return nil +} diff --git a/rpc/args_test.go b/rpc/args_test.go new file mode 100644 index 000000000..1e6609b79 --- /dev/null +++ b/rpc/args_test.go @@ -0,0 +1,434 @@ +package rpc + +import ( + "bytes" + "encoding/json" + "math/big" + "testing" +) + +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 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 err := args.requirements(); 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 TestGetBlockByHashArgs(t *testing.T) { + input := `["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true]` + expected := new(GetBlockByHashArgs) + expected.BlockHash = "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" + expected.Transactions = 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.Transactions != expected.Transactions { + t.Errorf("Transactions should be %v but is %v", expected.Transactions, args.Transactions) + } +} + +func TestGetBlockByNumberArgs(t *testing.T) { + input := `["0x1b4", false]` + expected := new(GetBlockByNumberArgs) + expected.BlockNumber = 436 + expected.Transactions = false + + args := new(GetBlockByNumberArgs) + if err := json.Unmarshal([]byte(input), &args); err != nil { + t.Error(err) + } + + if args.BlockNumber != expected.BlockNumber { + t.Errorf("BlockHash should be %v but is %v", expected.BlockNumber, args.BlockNumber) + } + + if args.Transactions != expected.Transactions { + t.Errorf("Transactions should be %v but is %v", expected.Transactions, args.Transactions) + } +} + +func TestNewTxArgs(t *testing.T) { + input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a000", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}]` + 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" + + 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) + } +} + +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 err := args.requirements(); 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 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 err := args.requirements(); 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 TestGetTxCountArgs(t *testing.T) { + input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]` + 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 err := args.requirements(); 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 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 err := args.requirements(); 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 TestFilterOptions(t *testing.T) { + input := `[{ + "fromBlock": "0x1", + "toBlock": "0x2", + "limit": "0x3", + "offset": "0x0", + "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", + "topics": ["0x12341234"]}]` + expected := new(FilterOptions) + expected.Earliest = 1 + expected.Latest = 2 + expected.Max = 3 + expected.Skip = 0 + expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8" + expected.Topic = []string{"0x12341234"} + + args := new(FilterOptions) + 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 != args.Address { + t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address) + } + + // if expected.Topic != args.Topic { + // t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic) + // } +} + +func TestDbArgs(t *testing.T) { + input := `["0x74657374","0x6b6579","0x6d79537472696e67"]` + expected := new(DbArgs) + expected.Database = "0x74657374" + expected.Key = "0x6b6579" + expected.Value = "0x6d79537472696e67" + + 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 expected.Value != args.Value { + t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value) + } +} + +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.Topic = []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.Topic != args.Topic { + // t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic) + // } +} + +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 TestWhsiperFilterArgs(t *testing.T) { + input := `[{"topics": ["0x68656c6c6f20776f726c64"], "to": "0x34ag445g3455b34"}]` + expected := new(WhisperFilterArgs) + expected.From = "" + expected.To = "0x34ag445g3455b34" + expected.Topics = []string{"0x68656c6c6f20776f726c64"} + + args := new(WhisperFilterArgs) + 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.Topics != args.Topics { + // t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics) + // } +} + +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 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 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) + } +} diff --git a/rpc/messages.go b/rpc/messages.go index b37d8229d..a3ebbf330 100644 --- a/rpc/messages.go +++ b/rpc/messages.go @@ -17,12 +17,9 @@ package rpc import ( - "bytes" "encoding/json" "errors" "fmt" - - "github.com/ethereum/go-ethereum/xeth" ) var ( @@ -33,10 +30,10 @@ var ( ) type RpcRequest struct { - ID interface{} `json:"id"` - JsonRpc string `json:"jsonrpc"` - Method string `json:"method"` - Params []json.RawMessage `json:"params"` + ID interface{} `json:"id"` + JsonRpc string `json:"jsonrpc"` + Method string `json:"method"` + Params json.RawMessage `json:"params"` } type RpcSuccessResponse struct { @@ -61,359 +58,30 @@ func NewErrorWithMessage(err error, msg string) error { return fmt.Errorf("%s: %s", err.Error(), msg) } -func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(Sha3Args) - r := bytes.NewReader(req.Params[0]) - if err := json.NewDecoder(r).Decode(args); err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(GetBlockArgs) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(NewTxArgs) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, NewErrorWithMessage(errDecodeArgs, err.Error()) - } - - return args, nil -} - -func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(PushTxArgs) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToGetStateArgs() (*GetStateArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(GetStateArgs) - // TODO need to pass both arguments - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToStorageAtArgs() (*GetStorageArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(GetStorageArgs) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(GetTxCountArgs) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(GetBalanceArgs) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(GetCodeAtArgs) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToBoolArgs() (bool, error) { - if len(req.Params) < 1 { - return false, errArguments - } - - var args bool - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return false, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToIntArgs() (int, error) { - if len(req.Params) < 1 { - return 0, errArguments - } - - var args int - if err := json.Unmarshal(req.Params[0], &args); err != nil { - return 0, errArguments - } - - return args, nil -} - -func (req *RpcRequest) ToCompileArgs() (string, error) { - if len(req.Params) < 1 { - return "", errArguments - } - - var args string - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return "", errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - args := new(FilterOptions) - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(args) - if err != nil { - return nil, errDecodeArgs - } - return args, nil -} - -func (req *RpcRequest) ToFilterStringArgs() (string, error) { - if len(req.Params) < 1 { - return "", errArguments - } - - var args string - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return "", errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToUninstallFilterArgs() (int, error) { - if len(req.Params) < 1 { - return 0, errArguments - } - - var args int - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return 0, errDecodeArgs - } - - return args, nil -} - -func (req *RpcRequest) ToFilterChangedArgs() (int, error) { - if len(req.Params) < 1 { - return 0, errArguments - } - - var id int - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(&id) - if err != nil { - return 0, errDecodeArgs - } - return id, nil -} - -func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) { - if len(req.Params) < 3 { - return nil, errArguments - } - - var args DbArgs - err := json.Unmarshal(req.Params[0], &args.Database) - if err != nil { - return nil, NewErrorWithMessage(errDecodeArgs, err.Error()) - } - err = json.Unmarshal(req.Params[1], &args.Key) - if err != nil { - return nil, NewErrorWithMessage(errDecodeArgs, err.Error()) - } - err = json.Unmarshal(req.Params[2], &args.Value) - if err != nil { - return nil, NewErrorWithMessage(errDecodeArgs, err.Error()) - } - - return &args, nil -} - -func (req *RpcRequest) ToDbGetArgs() (*DbArgs, error) { - if len(req.Params) < 2 { - return nil, errArguments - } +// func (req *RpcRequest) ToRegisterArgs() (string, error) { +// if len(req.Params) < 1 { +// return "", errArguments +// } - var args DbArgs - err := json.Unmarshal(req.Params[0], &args.Database) - if err != nil { - return nil, NewErrorWithMessage(errDecodeArgs, err.Error()) - } +// var args string +// err := json.Unmarshal(req.Params, &args) +// if err != nil { +// return "", err +// } - err = json.Unmarshal(req.Params[1], &args.Key) - if err != nil { - return nil, NewErrorWithMessage(errDecodeArgs, err.Error()) - } +// return args, nil +// } - return &args, nil -} - -func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - var args xeth.Options - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return nil, NewErrorWithMessage(errDecodeArgs, err.Error()) - } - - return &args, nil -} - -func (req *RpcRequest) ToIdArgs() (int, error) { - if len(req.Params) < 1 { - return 0, errArguments - } +// func (req *RpcRequest) ToWatchTxArgs() (string, error) { +// if len(req.Params) < 1 { +// return "", errArguments +// } - var id int - err := json.Unmarshal(req.Params[0], &id) - if err != nil { - return 0, errDecodeArgs - } - - return id, nil -} - -func (req *RpcRequest) ToWhisperPostArgs() (*WhisperMessageArgs, error) { - if len(req.Params) < 1 { - return nil, errArguments - } - - var args WhisperMessageArgs - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return nil, err - } - - return &args, nil -} +// var args string +// err := json.Unmarshal(req.Params, &args) +// if err != nil { +// return "", err +// } -func (req *RpcRequest) ToWhisperHasIdentityArgs() (string, error) { - if len(req.Params) < 1 { - return "", errArguments - } - - var args string - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return "", err - } - - return args, nil -} - -func (req *RpcRequest) ToRegisterArgs() (string, error) { - if len(req.Params) < 1 { - return "", errArguments - } - - var args string - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return "", err - } - - return args, nil -} - -func (req *RpcRequest) ToWatchTxArgs() (string, error) { - if len(req.Params) < 1 { - return "", errArguments - } - - var args string - err := json.Unmarshal(req.Params[0], &args) - if err != nil { - return "", err - } - - return args, nil -} +// return args, nil +// } diff --git a/rpc/util.go b/rpc/util.go index 3e8ca3fef..69c7b629f 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -63,7 +63,12 @@ func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) } func toHex(b []byte) string { - return "0x" + ethutil.Bytes2Hex(b) + hex := ethutil.Bytes2Hex(b) + // Prefer output of "0x0" instead of "0x" + if len(hex) == 0 { + hex = "0" + } + return "0x" + hex } func fromHex(s string) []byte { if len(s) > 1 { |