From ec85458612e1d5374767f87005dd0ad5934f74d5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 00:24:00 +0100 Subject: updated ethereum.js and moved to subfolder * Previous subtree caused a lot of trouble * Implemented sha3 in our shiny new http JSON RPC --- rpc/args.go | 11 +++++++++++ rpc/message.go | 14 ++++++++++++++ rpc/packages.go | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 8b01cc191..bebd79eb9 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -216,3 +216,14 @@ func (a *GetCodeAtArgs) requirements() error { } return nil } + +type Sha3Args struct { + Data string +} + +func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { + if err = json.Unmarshal(b, &obj.Data); err != nil { + return NewErrorResponse(ErrorDecodeArgs) + } + return +} diff --git a/rpc/message.go b/rpc/message.go index caf50a6c0..5785fcc87 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -56,6 +56,20 @@ type RpcRequest struct { Params []json.RawMessage `json:"params"` } +func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(Sha3Args) + r := bytes.NewReader(req.Params[0]) + if err := json.NewDecoder(r).Decode(args); err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index 5d17a0f90..2c5fbf6be 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -26,9 +26,11 @@ For each request type, define the following: package rpc import ( + "fmt" "math/big" "strings" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/xeth" ) @@ -161,6 +163,11 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { return nil } +func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { + *reply = ethutil.Bytes2Hex(crypto.Sha3(ethutil.Hex2Bytes(args.Data))) + return nil +} + func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { // Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) @@ -203,8 +210,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.GetBlock(args, reply) + case "web3_sha3": + args, err := req.ToSha3Args() + if err != nil { + return err + } + return p.Sha3(args, reply) default: - return NewErrorResponse(ErrorNotImplemented) + return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method)) } rpclogger.DebugDetailf("Reply: %T %s", reply, reply) -- cgit v1.2.3 From 6d012f628bbfc22b2587828968eff513dfeb4d8e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 12:01:51 +0100 Subject: implement transact --- rpc/args.go | 37 ++----------------------------------- rpc/message.go | 17 +++++++++++------ rpc/packages.go | 11 +++++++++-- 3 files changed, 22 insertions(+), 43 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index bebd79eb9..0c3087151 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -1,8 +1,6 @@ package rpc -import ( - "encoding/json" -) +import "encoding/json" type GetBlockArgs struct { BlockNumber int32 @@ -30,33 +28,18 @@ func (obj *GetBlockArgs) requirements() error { } type NewTxArgs struct { - Sec string `json:"sec"` Recipient string `json:"recipient"` Value string `json:"value"` Gas string `json:"gas"` GasPrice string `json:"gasprice"` - Init string `json:"init"` - Body string `json:"body"` + Data string `json:"data"` } // type TxResponse struct { // Hash string // } -func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { - if err = json.Unmarshal(b, obj); err == nil { - return - } - return NewErrorResponse(ErrorDecodeArgs) -} - func (a *NewTxArgs) requirements() error { - if a.Recipient == "" { - return NewErrorResponse("Transact requires a 'recipient' address as argument") - } - if a.Value == "" { - return NewErrorResponse("Transact requires a 'value' as argument") - } if a.Gas == "" { return NewErrorResponse("Transact requires a 'gas' value as argument") } @@ -66,22 +49,6 @@ func (a *NewTxArgs) requirements() error { return nil } -func (a *NewTxArgs) requirementsContract() error { - if a.Value == "" { - return NewErrorResponse("Create requires a 'value' as argument") - } - if a.Gas == "" { - return NewErrorResponse("Create requires a 'gas' value as argument") - } - if a.GasPrice == "" { - return NewErrorResponse("Create requires a 'gasprice' value as argument") - } - if a.Body == "" { - return NewErrorResponse("Create requires a 'body' value as argument") - } - return nil -} - type PushTxArgs struct { Tx string `json:"tx"` } diff --git a/rpc/message.go b/rpc/message.go index 5785fcc87..e9f47634f 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/json" "errors" + "fmt" ) const ( @@ -56,6 +57,14 @@ type RpcRequest struct { Params []json.RawMessage `json:"params"` } +func NewErrorResponse(msg string) error { + return errors.New(msg) +} + +func NewErrorResponseWithError(msg string, err error) error { + return fmt.Errorf("%s: %v", msg, err) +} + func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) { if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) @@ -86,7 +95,7 @@ func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { } func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) { - if len(req.Params) < 7 { + if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) } @@ -94,7 +103,7 @@ func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) { r := bytes.NewReader(req.Params[0]) err := json.NewDecoder(r).Decode(args) if err != nil { - return nil, NewErrorResponse(ErrorDecodeArgs) + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) } rpclogger.DebugDetailf("%T %v", args, args) return args, nil @@ -175,7 +184,3 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { rpclogger.DebugDetailf("%T %v", args, args) return args, nil } - -func NewErrorResponse(msg string) error { - return errors.New(msg) -} diff --git a/rpc/packages.go b/rpc/packages.go index 2c5fbf6be..11a172bd6 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -67,7 +67,8 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if err != nil { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Data) + fmt.Println("result:", result) *reply = result return nil } @@ -78,7 +79,7 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Data) *reply = result return nil } @@ -210,6 +211,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.GetBlock(args, reply) + case "eth_transact": + args, err := req.ToNewTxArgs() + if err != nil { + return err + } + return p.Transact(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3 From b5918a1faa300773aef58528e51cda4a2ad42f6f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 12:06:47 +0100 Subject: removed create --- rpc/packages.go | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 11a172bd6..3eaa71a7f 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -73,17 +73,6 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { return nil } -func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error { - err := args.requirementsContract() - if err != nil { - return err - } - - result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Data) - *reply = result - return nil -} - func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error { err := args.requirementsPushTx() if err != nil { -- cgit v1.2.3 From 84adf77bf3492351de82f0ec820a1d280e85a5cd Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 13:10:34 +0100 Subject: Added RPC "Call" for JS calls to contracts --- rpc/args.go | 11 ++++++----- rpc/packages.go | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 0c3087151..ff4974792 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -28,11 +28,12 @@ func (obj *GetBlockArgs) requirements() error { } type NewTxArgs struct { - Recipient string `json:"recipient"` - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasprice"` - Data string `json:"data"` + 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 TxResponse struct { diff --git a/rpc/packages.go b/rpc/packages.go index 3eaa71a7f..4302f6018 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -67,8 +67,17 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if err != nil { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Data) - fmt.Println("result:", result) + result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) + *reply = result + return nil +} + +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) + if err != nil { + return err + } + *reply = result return nil } @@ -206,6 +215,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.Transact(args, reply) + case "eth_call": + args, err := req.ToNewTxArgs() + if err != nil { + return err + } + return p.Call(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3 From ddf17d93acf92ef18b0134f19f22220362e06bad Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 14:46:59 +0100 Subject: Samples and disams cmd for evm code --- rpc/packages.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 4302f6018..b25660b25 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -35,6 +35,19 @@ import ( "github.com/ethereum/go-ethereum/xeth" ) +func toHex(b []byte) string { + return "0x" + ethutil.Bytes2Hex(b) +} +func fromHex(s string) []byte { + if len(s) > 1 { + if s[0:2] == "0x" { + s = s[2:] + } + return ethutil.Hex2Bytes(s) + } + return nil +} + type RpcServer interface { Start() Stop() @@ -163,7 +176,7 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { } func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { - *reply = ethutil.Bytes2Hex(crypto.Sha3(ethutil.Hex2Bytes(args.Data))) + *reply = toHex(crypto.Sha3(fromHex(args.Data))) return nil } -- cgit v1.2.3 From 6488a392a347d0d47212fdc78386e3e0e5841d7d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 16:52:00 +0100 Subject: Reimplemented message filters for rpc calls --- rpc/args.go | 31 +++++++++++++++++--- rpc/message.go | 55 ++++++++++++++++++++++++++++++++++ rpc/packages.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 169 insertions(+), 8 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index ff4974792..79519e7d2 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -1,6 +1,7 @@ package rpc import "encoding/json" +import "github.com/ethereum/go-ethereum/core" type GetBlockArgs struct { BlockNumber int32 @@ -36,10 +37,6 @@ type NewTxArgs struct { Data string `json:"data"` } -// type TxResponse struct { -// Hash string -// } - func (a *NewTxArgs) requirements() error { if a.Gas == "" { return NewErrorResponse("Transact requires a 'gas' value as argument") @@ -195,3 +192,29 @@ func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { } return } + +type FilterOptions struct { + Earliest int64 + Latest int64 + Address string + Topics []string + Skip int + Max int +} + +func toFilterOptions(options *FilterOptions) core.FilterOptions { + var opts core.FilterOptions + opts.Earliest = options.Earliest + opts.Latest = options.Latest + opts.Address = fromHex(options.Address) + opts.Topics = make([][]byte, len(options.Topics)) + for i, topic := range options.Topics { + opts.Topics[i] = fromHex(topic) + } + + return opts +} + +type FilterChangedArgs struct { + n int +} diff --git a/rpc/message.go b/rpc/message.go index e9f47634f..05f66ee95 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -21,6 +21,8 @@ import ( "encoding/json" "errors" "fmt" + + "github.com/ethereum/go-ethereum/state" ) const ( @@ -184,3 +186,56 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { rpclogger.DebugDetailf("%T %v", args, args) return args, nil } + +func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(FilterOptions) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +func (req *RpcRequest) ToFilterChangedArgs() (int, error) { + if len(req.Params) < 1 { + return 0, NewErrorResponse(ErrorArguments) + } + + var id int + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(&id) + if err != nil { + return 0, NewErrorResponse(ErrorDecodeArgs) + } + rpclogger.DebugDetailf("%T %v", id, id) + return id, nil +} + +type Log struct { + Address string `json:"address"` + Topics []string `json:"topics"` + Data string `json:"data"` +} + +func toLogs(logs state.Logs) (ls []Log) { + ls = make([]Log, len(logs)) + + for i, log := range logs { + var l Log + l.Topics = make([]string, len(log.Topics())) + l.Address = toHex(log.Address()) + l.Data = toHex(log.Data()) + for j, topic := range log.Topics() { + l.Topics[j] = toHex(topic) + } + ls[i] = l + } + + return +} diff --git a/rpc/packages.go b/rpc/packages.go index b25660b25..e8dc570fd 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -29,9 +29,13 @@ import ( "fmt" "math/big" "strings" + "sync" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/event/filter" + "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/xeth" ) @@ -53,12 +57,79 @@ type RpcServer interface { Stop() } +type EthereumApi struct { + xeth *xeth.XEth + filterManager *filter.FilterManager + + mut sync.RWMutex + logs map[int]state.Logs +} + func NewEthereumApi(xeth *xeth.XEth) *EthereumApi { - return &EthereumApi{xeth: xeth} + api := &EthereumApi{ + xeth: xeth, + filterManager: filter.NewFilterManager(xeth.Backend().EventMux()), + logs: make(map[int]state.Logs), + } + go api.filterManager.Start() + + return api } -type EthereumApi struct { - xeth *xeth.XEth +func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error { + var id int + filter := core.NewFilter(self.xeth.Backend()) + filter.LogsCallback = func(logs state.Logs) { + self.mut.Lock() + defer self.mut.Unlock() + + self.logs[id] = append(self.logs[id], logs...) + } + id = self.filterManager.InstallFilter(filter) + *reply = id + + return nil +} + +type Log struct { + Address string `json:"address"` + Topics []string `json:"topics"` + Data string `json:"data"` +} + +func toLogs(logs state.Logs) (ls []Log) { + ls = make([]Log, len(logs)) + + for i, log := range logs { + var l Log + l.Topics = make([]string, len(log.Topics())) + l.Address = toHex(log.Address()) + l.Data = toHex(log.Data()) + for j, topic := range log.Topics() { + l.Topics[j] = toHex(topic) + } + ls[i] = l + } + + return +} + +func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { + self.mut.RLock() + defer self.mut.RUnlock() + + *reply = toLogs(self.logs[id]) + + self.logs[id] = nil // empty the logs + + return nil +} + +func (self *EthereumApi) Logs(id int, reply *interface{}) error { + filter := self.filterManager.GetFilter(id) + *reply = toLogs(filter.Find()) + + return nil } func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { @@ -162,7 +233,7 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) err return err } state := p.xeth.State().SafeGet(args.Address) - *reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address} + *reply = toHex(state.Balance().Bytes()) return nil } @@ -234,6 +305,18 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error 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_changed": + args, err := req.ToFilterChangedArgs() + if err != nil { + return err + } + return p.FilterChanged(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3