aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2015-01-28 17:29:29 +0800
committerobscuren <geffobscura@gmail.com>2015-01-28 17:29:29 +0800
commit4c5968097d2a9fef8af904bfee93cd76cdafd314 (patch)
treef896c42c37eddfd2f912115eab3dd9f59eaa484d
parentf3e78c8f3cd2196ef70a41f298b6df556543d581 (diff)
parent159c4d56cd82d6fe721058557977f4efda31661c (diff)
downloadgo-tangerine-4c5968097d2a9fef8af904bfee93cd76cdafd314.tar.gz
go-tangerine-4c5968097d2a9fef8af904bfee93cd76cdafd314.tar.zst
go-tangerine-4c5968097d2a9fef8af904bfee93cd76cdafd314.zip
Merge branch 'jsonrpc' into qt5.4
-rw-r--r--.gitignore2
-rw-r--r--cmd/utils/cmd.go8
-rw-r--r--rpc/args.go218
-rw-r--r--rpc/json.go37
-rw-r--r--rpc/message.go169
-rw-r--r--rpc/packages.go319
-rw-r--r--rpc/server.go61
-rw-r--r--rpc/writer.go75
-rw-r--r--tests/vm/gh_test.go18
-rw-r--r--vm/vm_jit.go358
-rw-r--r--vm/vm_jit_fake.go10
-rw-r--r--websocket/util.go (renamed from cmd/utils/websockets.go)43
12 files changed, 965 insertions, 353 deletions
diff --git a/.gitignore b/.gitignore
index f84fe6040..71ce90db3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@
.#*
*#
*~
+.project
+.settings
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index a57d3266f..95a7f89c8 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -40,6 +40,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/websocket"
"github.com/ethereum/go-ethereum/xeth"
)
@@ -200,6 +201,13 @@ func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
}
}
+func StartWebSockets(eth *eth.Ethereum) {
+ clilogger.Infoln("Starting WebSockets")
+
+ sock := websocket.NewWebSocketServer(eth)
+ go sock.Serv()
+}
+
var gminer *miner.Miner
func GetMiner() *miner.Miner {
diff --git a/rpc/args.go b/rpc/args.go
new file mode 100644
index 000000000..8b01cc191
--- /dev/null
+++ b/rpc/args.go
@@ -0,0 +1,218 @@
+package rpc
+
+import (
+ "encoding/json"
+)
+
+type GetBlockArgs struct {
+ BlockNumber int32
+ Hash string
+}
+
+func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) {
+ argint, argstr := int32(0), ""
+ if err = json.Unmarshal(b, &argint); err == nil {
+ obj.BlockNumber = argint
+ return
+ }
+ if err = json.Unmarshal(b, &argstr); err == nil {
+ obj.Hash = argstr
+ return
+ }
+ return NewErrorResponse(ErrorDecodeArgs)
+}
+
+func (obj *GetBlockArgs) requirements() error {
+ if obj.BlockNumber == 0 && obj.Hash == "" {
+ return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument")
+ }
+ return nil
+}
+
+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"`
+}
+
+// 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")
+ }
+ if a.GasPrice == "" {
+ return NewErrorResponse("Transact requires a 'gasprice' value as argument")
+ }
+ 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"`
+}
+
+func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) {
+ arg0 := ""
+ if err = json.Unmarshal(b, arg0); err == nil {
+ obj.Tx = arg0
+ return
+ }
+ return NewErrorResponse(ErrorDecodeArgs)
+}
+
+func (a *PushTxArgs) requirementsPushTx() error {
+ if a.Tx == "" {
+ return NewErrorResponse("PushTx requires a 'tx' as argument")
+ }
+ return nil
+}
+
+type GetStorageArgs struct {
+ Address string
+ Key string
+}
+
+func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
+ arg0 := ""
+ if err = json.Unmarshal(b, arg0); err == nil {
+ obj.Address = arg0
+ return
+ }
+ return NewErrorResponse(ErrorDecodeArgs)
+}
+
+func (a *GetStorageArgs) requirements() error {
+ if a.Address == "" {
+ return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
+ }
+ if a.Key == "" {
+ return NewErrorResponse("GetStorageAt requires an 'key' value as argument")
+ }
+ return nil
+}
+
+type GetStorageAtRes struct {
+ Key string `json:"key"`
+ Value string `json:"value"`
+ Address string `json:"address"`
+}
+
+type GetTxCountArgs struct {
+ Address string `json:"address"`
+}
+
+// type GetTxCountRes struct {
+// Nonce int `json:"nonce"`
+// }
+
+func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
+ arg0 := ""
+ if err = json.Unmarshal(b, arg0); err == nil {
+ obj.Address = arg0
+ return
+ }
+ return NewErrorResponse("Could not determine JSON parameters")
+}
+
+func (a *GetTxCountArgs) requirements() error {
+ if a.Address == "" {
+ return NewErrorResponse("GetTxCountAt requires an 'address' value as argument")
+ }
+ return nil
+}
+
+// type GetPeerCountRes struct {
+// PeerCount int `json:"peerCount"`
+// }
+
+// type GetListeningRes struct {
+// IsListening bool `json:"isListening"`
+// }
+
+// type GetCoinbaseRes struct {
+// Coinbase string `json:"coinbase"`
+// }
+
+// type GetMiningRes struct {
+// IsMining bool `json:"isMining"`
+// }
+
+type GetBalanceArgs struct {
+ Address string
+}
+
+func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
+ arg0 := ""
+ if err = json.Unmarshal(b, &arg0); err == nil {
+ obj.Address = arg0
+ return
+ }
+ return NewErrorResponse("Could not determine JSON parameters")
+}
+
+func (a *GetBalanceArgs) requirements() error {
+ if a.Address == "" {
+ return NewErrorResponse("GetBalanceAt requires an 'address' value as argument")
+ }
+ return nil
+}
+
+type BalanceRes struct {
+ Balance string `json:"balance"`
+ Address string `json:"address"`
+}
+
+type GetCodeAtArgs struct {
+ Address string
+}
+
+func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) {
+ arg0 := ""
+ if err = json.Unmarshal(b, &arg0); err == nil {
+ obj.Address = arg0
+ return
+ }
+ return NewErrorResponse(ErrorDecodeArgs)
+}
+
+func (a *GetCodeAtArgs) requirements() error {
+ if a.Address == "" {
+ return NewErrorResponse("GetCodeAt requires an 'address' value as argument")
+ }
+ return nil
+}
diff --git a/rpc/json.go b/rpc/json.go
index e467f9a34..5446cb3c1 100644
--- a/rpc/json.go
+++ b/rpc/json.go
@@ -1,8 +1,25 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ go-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
package rpc
import (
"encoding/json"
"io"
+ "net/http"
)
type jsonWrapper struct{}
@@ -11,10 +28,30 @@ func (self jsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error)
var payload []byte
payload, err = json.Marshal(v)
if err != nil {
+ jsonlogger.Fatalln("Error marshalling JSON", err)
return 0, err
}
+ jsonlogger.Infof("Sending payload: %s", payload)
return writer.Write(payload)
}
+func (self jsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) {
+ var reqParsed RpcRequest
+
+ // Convert JSON to native types
+ d := json.NewDecoder(req.Body)
+ // d.UseNumber()
+ defer req.Body.Close()
+ err := d.Decode(&reqParsed)
+
+ if err != nil {
+ jsonlogger.Errorln("Error decoding JSON: ", err)
+ return reqParsed, err
+ }
+ jsonlogger.DebugDetailf("Parsed request: %s", reqParsed)
+
+ return reqParsed, nil
+}
+
var JSON jsonWrapper
diff --git a/rpc/message.go b/rpc/message.go
index c8103eded..63de734b8 100644
--- a/rpc/message.go
+++ b/rpc/message.go
@@ -1,14 +1,167 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ go-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
package rpc
-import "github.com/ethereum/go-ethereum/ethutil"
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+)
+
+const (
+ ErrorArguments = "Error: Insufficient arguments"
+ ErrorNotImplemented = "Error: Method not implemented"
+ ErrorUnknown = "Error: Unknown error"
+ ErrorParseRequest = "Error: Could not parse request"
+ ErrorDecodeArgs = "Error: Could not decode arguments"
+)
+
+type ErrorResponse struct {
+ Error bool `json:"error"`
+ ErrorText string `json:"errorText"`
+}
+
+type RpcSuccessResponse struct {
+ ID int `json:"id"`
+ JsonRpc string `json:"jsonrpc"`
+ Error bool `json:"error"`
+ Result interface{} `json:"result"`
+}
+
+type RpcErrorResponse struct {
+ ID int `json:"id"`
+ JsonRpc string `json:"jsonrpc"`
+ Error bool `json:"error"`
+ ErrorText string `json:"errortext"`
+}
+
+type RpcRequest struct {
+ JsonRpc string `json:"jsonrpc"`
+ ID int `json:"id"`
+ Method string `json:"method"`
+ Params []json.RawMessage `json:"params"`
+}
+
+func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) {
+ if len(req.Params) < 1 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ args := new(GetBlockArgs)
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ jsonlogger.DebugDetailf("%T %v", args, args)
+ return args, nil
+}
+
+func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) {
+ if len(req.Params) < 7 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ args := new(NewTxArgs)
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ jsonlogger.DebugDetailf("%T %v", args, args)
+ return args, nil
+}
+
+func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) {
+ if len(req.Params) < 1 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ args := new(PushTxArgs)
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ jsonlogger.DebugDetailf("%T %v", args, args)
+ return args, nil
+}
+
+func (req *RpcRequest) ToGetStorageArgs() (*GetStorageArgs, error) {
+ if len(req.Params) < 2 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ args := new(GetStorageArgs)
+ // TODO need to pass both arguments
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ jsonlogger.DebugDetailf("%T %v", args, args)
+ return args, nil
+}
+
+func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) {
+ if len(req.Params) < 1 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ args := new(GetTxCountArgs)
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ jsonlogger.DebugDetailf("%T %v", args, args)
+ return args, nil
+}
+
+func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) {
+ if len(req.Params) < 1 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
+
+ args := new(GetBalanceArgs)
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ jsonlogger.DebugDetailf("%T %v", args, args)
+ return args, nil
+}
+
+func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) {
+ if len(req.Params) < 1 {
+ return nil, NewErrorResponse(ErrorArguments)
+ }
-type Message struct {
- Call string `json:"call"`
- Args []interface{} `json:"args"`
- Id int `json:"_id"`
- Data interface{} `json:"data"`
+ args := new(GetCodeAtArgs)
+ r := bytes.NewReader(req.Params[0])
+ err := json.NewDecoder(r).Decode(args)
+ if err != nil {
+ return nil, NewErrorResponse(ErrorDecodeArgs)
+ }
+ jsonlogger.DebugDetailf("%T %v", args, args)
+ return args, nil
}
-func (self *Message) Arguments() *ethutil.Value {
- return ethutil.NewValue(self.Args)
+func NewErrorResponse(msg string) error {
+ return errors.New(msg)
}
diff --git a/rpc/packages.go b/rpc/packages.go
index 5535e6e79..e87e0db7c 100644
--- a/rpc/packages.go
+++ b/rpc/packages.go
@@ -1,8 +1,31 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ go-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+
+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 "UnmarshalJSON" defined on each "Args" struct
+3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to JSON
+
+*/
package rpc
import (
- "encoding/json"
- "errors"
"math/big"
"strings"
@@ -14,185 +37,57 @@ type EthereumApi struct {
pipe *xeth.JSXEth
}
-type JsonArgs interface {
- requirements() error
-}
-
-type BlockResponse struct {
- JsonResponse
-}
-type GetBlockArgs struct {
- BlockNumber int
- Hash string
-}
-
-type ErrorResponse struct {
- Error bool `json:"error"`
- ErrorText string `json:"errorText"`
-}
-
-type JsonResponse interface {
-}
-
-type SuccessRes struct {
- Error bool `json:"error"`
- Result JsonResponse `json:"result"`
-}
-
-func NewSuccessRes(object JsonResponse) string {
- e := SuccessRes{Error: false, Result: object}
- res, err := json.Marshal(e)
- if err != nil {
- // This should never happen
- panic("Creating json error response failed, help")
- }
- success := string(res)
- return success
-}
-
-func NewErrorResponse(msg string) error {
- e := ErrorResponse{Error: true, ErrorText: msg}
- res, err := json.Marshal(e)
- if err != nil {
- // This should never happen
- panic("Creating json error response failed, help")
- }
- newErr := errors.New(string(res))
- return newErr
-}
-
-func (b *GetBlockArgs) requirements() error {
- if b.BlockNumber == 0 && b.Hash == "" {
- return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument")
- }
- return nil
-}
-
-func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error {
+func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
- block := p.pipe.BlockByHash(args.Hash)
- *reply = NewSuccessRes(block)
- return nil
-}
-
-type NewTxArgs struct {
- Sec string
- Recipient string
- Value string
- Gas string
- GasPrice string
- Init string
- Body string
-}
-type TxResponse struct {
- Hash string
-}
-
-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")
- }
- if a.GasPrice == "" {
- return NewErrorResponse("Transact requires a 'gasprice' value as argument")
- }
- 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")
+ if args.BlockNumber > 0 {
+ *reply = p.pipe.BlockByNumber(args.BlockNumber)
+ } else {
+ *reply = p.pipe.BlockByHash(args.Hash)
}
return nil
}
-func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error {
+func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body)
- *reply = NewSuccessRes(result)
+ *reply = result
return nil
}
-func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error {
+func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error {
err := args.requirementsContract()
if err != nil {
return err
}
result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body)
- *reply = NewSuccessRes(result)
- return nil
-}
-
-type PushTxArgs struct {
- Tx string
-}
-
-func (a *PushTxArgs) requirementsPushTx() error {
- if a.Tx == "" {
- return NewErrorResponse("PushTx requires a 'tx' as argument")
- }
+ *reply = result
return nil
}
-func (p *EthereumApi) PushTx(args *PushTxArgs, reply *string) error {
+func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
err := args.requirementsPushTx()
if err != nil {
return err
}
result, _ := p.pipe.PushTx(args.Tx)
- *reply = NewSuccessRes(result)
+ *reply = result
return nil
}
-func (p *EthereumApi) GetKey(args interface{}, reply *string) error {
- *reply = NewSuccessRes(p.pipe.Key())
+func (p *EthereumApi) GetKey(args interface{}, reply *interface{}) error {
+ *reply = p.pipe.Key()
return nil
}
-type GetStorageArgs struct {
- Address string
- Key string
-}
-
-func (a *GetStorageArgs) requirements() error {
- if a.Address == "" {
- return NewErrorResponse("GetStorageAt requires an 'address' value as argument")
- }
- if a.Key == "" {
- return NewErrorResponse("GetStorageAt requires an 'key' value as argument")
- }
- return nil
-}
-
-type GetStorageAtRes struct {
- Key string `json:"key"`
- Value string `json:"value"`
- Address string `json:"address"`
-}
-
-func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error {
+func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
@@ -210,102 +105,104 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error {
}
jsonlogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx)
value := state.Storage(ethutil.Hex2Bytes(hx))
- *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()})
+ *reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}
return nil
}
-type GetTxCountArgs struct {
- Address string `json:"address"`
-}
-type GetTxCountRes struct {
- Nonce int `json:"nonce"`
-}
-
-func (a *GetTxCountArgs) requirements() error {
- if a.Address == "" {
- return NewErrorResponse("GetTxCountAt requires an 'address' value as argument")
- }
+func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
+ *reply = p.pipe.PeerCount()
return nil
}
-type GetPeerCountRes struct {
- PeerCount int `json:"peerCount"`
-}
-
-func (p *EthereumApi) GetPeerCount(args *interface{}, reply *string) error {
- *reply = NewSuccessRes(GetPeerCountRes{PeerCount: p.pipe.PeerCount()})
+func (p *EthereumApi) GetIsListening(reply *interface{}) error {
+ *reply = p.pipe.IsListening()
return nil
}
-type GetListeningRes struct {
- IsListening bool `json:"isListening"`
-}
-
-func (p *EthereumApi) GetIsListening(args *interface{}, reply *string) error {
- *reply = NewSuccessRes(GetListeningRes{IsListening: p.pipe.IsListening()})
+func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
+ *reply = p.pipe.CoinBase()
return nil
}
-type GetCoinbaseRes struct {
- Coinbase string `json:"coinbase"`
-}
-
-func (p *EthereumApi) GetCoinbase(args *interface{}, reply *string) error {
- *reply = NewSuccessRes(GetCoinbaseRes{Coinbase: p.pipe.CoinBase()})
+func (p *EthereumApi) GetIsMining(reply *interface{}) error {
+ *reply = p.pipe.IsMining()
return nil
}
-type GetMiningRes struct {
- IsMining bool `json:"isMining"`
-}
-
-func (p *EthereumApi) GetIsMining(args *interface{}, reply *string) error {
- *reply = NewSuccessRes(GetMiningRes{IsMining: p.pipe.IsMining()})
- return nil
-}
-
-func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *string) error {
+func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
- state := p.pipe.TxCountAt(args.Address)
- *reply = NewSuccessRes(GetTxCountRes{Nonce: state})
- return nil
-}
-
-type GetBalanceArgs struct {
- Address string
-}
-
-func (a *GetBalanceArgs) requirements() error {
- if a.Address == "" {
- return NewErrorResponse("GetBalanceAt requires an 'address' value as argument")
- }
+ *reply = p.pipe.TxCountAt(args.Address)
return nil
}
-type BalanceRes struct {
- Balance string `json:"balance"`
- Address string `json:"address"`
-}
-
-func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error {
+func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address))
- *reply = NewSuccessRes(BalanceRes{Balance: state.Balance().String(), Address: args.Address})
+ *reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address}
return nil
}
-type TestRes struct {
- JsonResponse `json:"-"`
- Answer int `json:"answer"`
-}
-
-func (p *EthereumApi) Test(args *GetBlockArgs, reply *string) error {
- *reply = NewSuccessRes(TestRes{Answer: 15})
+func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
+ err := args.requirements()
+ if err != nil {
+ return err
+ }
+ *reply = p.pipe.CodeAt(args.Address)
+ return nil
+}
+
+func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
+ // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC
+ jsonlogger.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_peerCount":
+ return p.GetPeerCount(reply)
+ case "eth_countAt":
+ args, err := req.ToGetTxCountArgs()
+ if err != nil {
+ return err
+ }
+ return p.GetTxCountAt(args, reply)
+ case "eth_codeAt":
+ args, err := req.ToGetCodeAtArgs()
+ if err != nil {
+ return err
+ }
+ return p.GetCodeAt(args, reply)
+ case "eth_balanceAt":
+ args, err := req.ToGetBalanceArgs()
+ if err != nil {
+ return err
+ }
+ return p.GetBalanceAt(args, reply)
+ case "eth_stateAt":
+ args, err := req.ToGetStorageArgs()
+ if err != nil {
+ return err
+ }
+ return p.GetStorageAt(args, reply)
+ case "eth_blockByNumber", "eth_blockByHash":
+ args, err := req.ToGetBlockArgs()
+ if err != nil {
+ return err
+ }
+ return p.GetBlock(args, reply)
+ default:
+ return NewErrorResponse(ErrorNotImplemented)
+ }
+
+ jsonlogger.DebugDetailf("Reply: %T %s", reply, reply)
return nil
}
diff --git a/rpc/server.go b/rpc/server.go
index 983dc6c33..a4cf1aa7c 100644
--- a/rpc/server.go
+++ b/rpc/server.go
@@ -1,10 +1,25 @@
+/*
+ This file is part of go-ethereum
+
+ go-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ go-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
package rpc
import (
"fmt"
"net"
- "net/rpc"
- "net/rpc/jsonrpc"
+ "net/http"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/xeth"
@@ -38,17 +53,14 @@ func (s *JsonRpcServer) Stop() {
func (s *JsonRpcServer) Start() {
jsonlogger.Infoln("Starting JSON-RPC server")
go s.exitHandler()
- rpc.Register(&EthereumApi{pipe: s.pipe})
- rpc.HandleHTTP()
- for {
- conn, err := s.listener.Accept()
- if err != nil {
- jsonlogger.Infoln("Error starting JSON-RPC:", err)
- break
- }
- jsonlogger.Debugln("Incoming request.")
- go jsonrpc.ServeConn(conn)
+ h := apiHandler(&EthereumApi{pipe: s.pipe})
+ http.Handle("/", h)
+
+ err := http.Serve(s.listener, nil)
+ // FIX Complains on shutdown due to listner already being closed
+ if err != nil {
+ jsonlogger.Errorln("Error on JSON-RPC interface:", err)
}
}
@@ -65,3 +77,28 @@ func NewJsonRpcServer(pipe *xeth.JSXEth, port int) (*JsonRpcServer, error) {
pipe: pipe,
}, nil
}
+
+func apiHandler(xeth *EthereumApi) http.Handler {
+ fn := func(w http.ResponseWriter, req *http.Request) {
+ jsonlogger.Debugln("Handling request")
+
+ reqParsed, reqerr := JSON.ParseRequestBody(req)
+ if reqerr != nil {
+ JSON.Send(w, &RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: ErrorParseRequest})
+ return
+ }
+
+ var response interface{}
+ reserr := xeth.GetRequestReply(&reqParsed, &response)
+ if reserr != nil {
+ jsonlogger.Errorln(reserr)
+ JSON.Send(w, &RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()})
+ return
+ }
+
+ jsonlogger.Debugf("Generated response: %T %s", response, response)
+ JSON.Send(w, &RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response})
+ }
+
+ return http.HandlerFunc(fn)
+}
diff --git a/rpc/writer.go b/rpc/writer.go
deleted file mode 100644
index 4cc39f577..000000000
--- a/rpc/writer.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package rpc
-
-/*
-func pack(id int, v ...interface{}) Message {
- return Message{Data: v, Id: id}
-}
-
-func WriteOn(msg *Message, writer io.Writer) {
- //msg := &Message{Seed: seed, Data: data}
-
- switch msg.Call {
- case "compile":
- data := ethutil.NewValue(msg.Args)
- bcode, err := ethutil.Compile(data.Get(0).Str(), false)
- if err != nil {
- JSON.Send(writer, pack(msg.Id, err.Error()))
- }
-
- code := ethutil.Bytes2Hex(bcode)
-
- JSON.Send(writer, pack(msg.Id, code, nil))
- case "block":
- args := msg.Arguments()
-
- block := pipe.BlockByNumber(int32(args.Get(0).Uint()))
-
- JSON.Send(writer, pack(msg.Id, block))
- case "transact":
- if mp, ok := msg.Args[0].(map[string]interface{}); ok {
- object := mapToTxParams(mp)
- JSON.Send(
- writer,
- pack(msg.Id, args(pipe.Transact(object["from"], object["to"], object["value"], object["gas"], object["gasPrice"], object["data"]))),
- )
-
- }
- case "coinbase":
- JSON.Send(writer, pack(msg.Id, pipe.CoinBase(), msg.Seed))
-
- case "listening":
- JSON.Send(writer, pack(msg.Id, pipe.IsListening()))
-
- case "mining":
- JSON.Send(writer, pack(msg.Id, pipe.IsMining()))
-
- case "peerCoint":
- JSON.Send(writer, pack(msg.Id, pipe.PeerCount()))
-
- case "countAt":
- args := msg.Arguments()
-
- JSON.Send(writer, pack(msg.Id, pipe.TxCountAt(args.Get(0).Str())))
-
- case "codeAt":
- args := msg.Arguments()
-
- JSON.Send(writer, pack(msg.Id, len(pipe.CodeAt(args.Get(0).Str()))))
-
- case "stateAt":
- args := msg.Arguments()
-
- JSON.Send(writer, pack(msg.Id, pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str())))
-
- case "balanceAt":
- args := msg.Arguments()
-
- JSON.Send(writer, pack(msg.Id, pipe.BalanceAt(args.Get(0).Str())))
-
- case "newFilter":
- case "newFilterString":
- case "messages":
- // TODO
- }
-}
-*/
diff --git a/tests/vm/gh_test.go b/tests/vm/gh_test.go
index e1fdcd658..41ebba957 100644
--- a/tests/vm/gh_test.go
+++ b/tests/vm/gh_test.go
@@ -172,47 +172,47 @@ func RunVmTest(p string, t *testing.T) {
// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
func TestVMArithmetic(t *testing.T) {
- const fn = "../files/vmtests/vmArithmeticTest.json"
+ const fn = "../files/VMTests/vmArithmeticTest.json"
RunVmTest(fn, t)
}
func TestBitwiseLogicOperation(t *testing.T) {
- const fn = "../files/vmtests/vmBitwiseLogicOperationTest.json"
+ const fn = "../files/VMTests/vmBitwiseLogicOperationTest.json"
RunVmTest(fn, t)
}
func TestBlockInfo(t *testing.T) {
- const fn = "../files/vmtests/vmBlockInfoTest.json"
+ const fn = "../files/VMTests/vmBlockInfoTest.json"
RunVmTest(fn, t)
}
func TestEnvironmentalInfo(t *testing.T) {
- const fn = "../files/vmtests/vmEnvironmentalInfoTest.json"
+ const fn = "../files/VMTests/vmEnvironmentalInfoTest.json"
RunVmTest(fn, t)
}
func TestFlowOperation(t *testing.T) {
- const fn = "../files/vmtests/vmIOandFlowOperationsTest.json"
+ const fn = "../files/VMTests/vmIOandFlowOperationsTest.json"
RunVmTest(fn, t)
}
func TestPushDupSwap(t *testing.T) {
- const fn = "../files/vmtests/vmPushDupSwapTest.json"
+ const fn = "../files/VMTests/vmPushDupSwapTest.json"
RunVmTest(fn, t)
}
func TestVMSha3(t *testing.T) {
- const fn = "../files/vmtests/vmSha3Test.json"
+ const fn = "../files/VMTests/vmSha3Test.json"
RunVmTest(fn, t)
}
func TestVm(t *testing.T) {
- const fn = "../files/vmtests/vmtests.json"
+ const fn = "../files/VMTests/vmtests.json"
RunVmTest(fn, t)
}
func TestVmLog(t *testing.T) {
- const fn = "../files/vmtests/vmLogTest.json"
+ const fn = "../files/VMTests/vmLogTest.json"
RunVmTest(fn, t)
}
diff --git a/vm/vm_jit.go b/vm/vm_jit.go
index 0882bcf0c..38cab57da 100644
--- a/vm/vm_jit.go
+++ b/vm/vm_jit.go
@@ -1,31 +1,371 @@
+// +build evmjit
+
package vm
-import "math/big"
+/*
+
+void* evmjit_create();
+int evmjit_run(void* _jit, void* _data, void* _env);
+void evmjit_destroy(void* _jit);
+
+// Shared library evmjit (e.g. libevmjit.so) is expected to be installed in /usr/local/lib
+// More: https://github.com/ethereum/evmjit
+#cgo LDFLAGS: -levmjit
+*/
+import "C"
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/state"
+ "math/big"
+ "unsafe"
+)
type JitVm struct {
- env Environment
- backup *Vm
+ env Environment
+ me ContextRef
+ callerAddr []byte
+ price *big.Int
+ data RuntimeData
+}
+
+type i256 [32]byte
+
+type RuntimeData struct {
+ gas int64
+ gasPrice int64
+ callData *byte
+ callDataSize uint64
+ address i256
+ caller i256
+ origin i256
+ callValue i256
+ coinBase i256
+ difficulty i256
+ gasLimit i256
+ number uint64
+ timestamp int64
+ code *byte
+ codeSize uint64
+}
+
+func hash2llvm(h []byte) i256 {
+ var m i256
+ copy(m[len(m)-len(h):], h) // right aligned copy
+ return m
+}
+
+func llvm2hash(m *i256) []byte {
+ return C.GoBytes(unsafe.Pointer(m), C.int(len(m)))
+}
+
+func llvm2hashRef(m *i256) []byte {
+ return (*[1 << 30]byte)(unsafe.Pointer(m))[:len(m):len(m)]
+}
+
+func address2llvm(addr []byte) i256 {
+ n := hash2llvm(addr)
+ bswap(&n)
+ return n
+}
+
+// bswap swap bytes of the 256-bit integer on LLVM side
+// TODO: Do not change memory on LLVM side, that can conflict with memory access optimizations
+func bswap(m *i256) *i256 {
+ for i, l := 0, len(m); i < l/2; i++ {
+ m[i], m[l-i-1] = m[l-i-1], m[i]
+ }
+ return m
+}
+
+func trim(m []byte) []byte {
+ skip := 0
+ for i := 0; i < len(m); i++ {
+ if m[i] == 0 {
+ skip++
+ } else {
+ break
+ }
+ }
+ return m[skip:]
+}
+
+func getDataPtr(m []byte) *byte {
+ var p *byte
+ if len(m) > 0 {
+ p = &m[0]
+ }
+ return p
+}
+
+func big2llvm(n *big.Int) i256 {
+ m := hash2llvm(n.Bytes())
+ bswap(&m)
+ return m
+}
+
+func llvm2big(m *i256) *big.Int {
+ n := big.NewInt(0)
+ for i := 0; i < len(m); i++ {
+ b := big.NewInt(int64(m[i]))
+ b.Lsh(b, uint(i)*8)
+ n.Add(n, b)
+ }
+ return n
+}
+
+// llvm2bytesRef creates a []byte slice that references byte buffer on LLVM side (as of that not controller by GC)
+// User must asure that referenced memory is available to Go until the data is copied or not needed any more
+func llvm2bytesRef(data *byte, length uint64) []byte {
+ if length == 0 {
+ return nil
+ }
+ if data == nil {
+ panic("Unexpected nil data pointer")
+ }
+ return (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length]
+}
+
+func untested(condition bool, message string) {
+ if condition {
+ panic("Condition `" + message + "` tested. Remove assert.")
+ }
+}
+
+func assert(condition bool, message string) {
+ if !condition {
+ panic("Assert `" + message + "` failed!")
+ }
}
func NewJitVm(env Environment) *JitVm {
- backupVm := New(env)
- return &JitVm{env: env, backup: backupVm}
+ return &JitVm{env: env}
}
func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
- return self.backup.Run(me, caller, code, value, gas, price, callData)
+ // TODO: depth is increased but never checked by VM. VM should not know about it at all.
+ self.env.SetDepth(self.env.Depth() + 1)
+
+ // TODO: Move it to Env.Call() or sth
+ if Precompiled[string(me.Address())] != nil {
+ // if it's address of precopiled contract
+ // fallback to standard VM
+ stdVm := New(self.env)
+ return stdVm.Run(me, caller, code, value, gas, price, callData)
+ }
+
+ if self.me != nil {
+ panic("JitVm.Run() can be called only once per JitVm instance")
+ }
+
+ self.me = me
+ self.callerAddr = caller.Address()
+ self.price = price
+
+ self.data.gas = gas.Int64()
+ self.data.gasPrice = price.Int64()
+ self.data.callData = getDataPtr(callData)
+ self.data.callDataSize = uint64(len(callData))
+ self.data.address = address2llvm(self.me.Address())
+ self.data.caller = address2llvm(caller.Address())
+ self.data.origin = address2llvm(self.env.Origin())
+ self.data.callValue = big2llvm(value)
+ self.data.coinBase = address2llvm(self.env.Coinbase())
+ self.data.difficulty = big2llvm(self.env.Difficulty())
+ self.data.gasLimit = big2llvm(self.env.GasLimit())
+ self.data.number = self.env.BlockNumber().Uint64()
+ self.data.timestamp = self.env.Time()
+ self.data.code = getDataPtr(code)
+ self.data.codeSize = uint64(len(code))
+
+ jit := C.evmjit_create()
+ retCode := C.evmjit_run(jit, unsafe.Pointer(&self.data), unsafe.Pointer(self))
+
+ if retCode < 0 {
+ err = errors.New("OOG from JIT")
+ gas.SetInt64(0) // Set gas to 0, JIT does not bother
+ } else {
+ gas.SetInt64(self.data.gas)
+ if retCode == 1 { // RETURN
+ ret = C.GoBytes(unsafe.Pointer(self.data.callData), C.int(self.data.callDataSize))
+ } else if retCode == 2 { // SUICIDE
+ // TODO: Suicide support logic should be moved to Env to be shared by VM implementations
+ state := self.Env().State()
+ receiverAddr := llvm2hashRef(bswap(&self.data.address))
+ receiver := state.GetOrNewStateObject(receiverAddr)
+ balance := state.GetBalance(me.Address())
+ receiver.AddAmount(balance)
+ state.Delete(me.Address())
+ }
+ }
+
+ C.evmjit_destroy(jit);
+ return
}
func (self *JitVm) Printf(format string, v ...interface{}) VirtualMachine {
- return self.backup.Printf(format, v)
+ return self
}
func (self *JitVm) Endl() VirtualMachine {
- return self.backup.Endl()
+ return self
}
func (self *JitVm) Env() Environment {
return self.env
}
-//go is nice
+//export env_sha3
+func env_sha3(dataPtr *byte, length uint64, resultPtr unsafe.Pointer) {
+ data := llvm2bytesRef(dataPtr, length)
+ hash := crypto.Sha3(data)
+ result := (*i256)(resultPtr)
+ *result = hash2llvm(hash)
+}
+
+//export env_sstore
+func env_sstore(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, valuePtr unsafe.Pointer) {
+ vm := (*JitVm)(vmPtr)
+ index := llvm2hash(bswap((*i256)(indexPtr)))
+ value := llvm2hash(bswap((*i256)(valuePtr)))
+ value = trim(value)
+ if len(value) == 0 {
+ prevValue := vm.env.State().GetState(vm.me.Address(), index)
+ if len(prevValue) != 0 {
+ vm.Env().State().Refund(vm.callerAddr, GasSStoreRefund)
+ }
+ }
+
+ vm.env.State().SetState(vm.me.Address(), index, value)
+}
+
+//export env_sload
+func env_sload(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, resultPtr unsafe.Pointer) {
+ vm := (*JitVm)(vmPtr)
+ index := llvm2hash(bswap((*i256)(indexPtr)))
+ value := vm.env.State().GetState(vm.me.Address(), index)
+ result := (*i256)(resultPtr)
+ *result = hash2llvm(value)
+ bswap(result)
+}
+
+//export env_balance
+func env_balance(_vm unsafe.Pointer, _addr unsafe.Pointer, _result unsafe.Pointer) {
+ vm := (*JitVm)(_vm)
+ addr := llvm2hash((*i256)(_addr))
+ balance := vm.Env().State().GetBalance(addr)
+ result := (*i256)(_result)
+ *result = big2llvm(balance)
+}
+
+//export env_blockhash
+func env_blockhash(_vm unsafe.Pointer, _number unsafe.Pointer, _result unsafe.Pointer) {
+ vm := (*JitVm)(_vm)
+ number := llvm2big((*i256)(_number))
+ result := (*i256)(_result)
+
+ currNumber := vm.Env().BlockNumber()
+ limit := big.NewInt(0).Sub(currNumber, big.NewInt(256))
+ if number.Cmp(limit) >= 0 && number.Cmp(currNumber) < 0 {
+ hash := vm.Env().GetHash(uint64(number.Int64()))
+ *result = hash2llvm(hash)
+ } else {
+ *result = i256{}
+ }
+}
+
+//export env_call
+func env_call(_vm unsafe.Pointer, _gas unsafe.Pointer, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool {
+ vm := (*JitVm)(_vm)
+
+ //fmt.Printf("env_call (depth %d)\n", vm.Env().Depth())
+
+ defer func() {
+ if r := recover(); r != nil {
+ fmt.Printf("Recovered in env_call (depth %d, out %p %d): %s\n", vm.Env().Depth(), outDataPtr, outDataLen, r)
+ }
+ }()
+
+ balance := vm.Env().State().GetBalance(vm.me.Address())
+ value := llvm2big((*i256)(_value))
+
+ if balance.Cmp(value) >= 0 {
+ receiveAddr := llvm2hash((*i256)(_receiveAddr))
+ inData := C.GoBytes(inDataPtr, C.int(inDataLen))
+ outData := llvm2bytesRef(outDataPtr, outDataLen)
+ codeAddr := llvm2hash((*i256)(_codeAddr))
+ llvmGas := (*i256)(_gas)
+ gas := llvm2big(llvmGas)
+ var out []byte
+ var err error
+ if bytes.Equal(codeAddr, receiveAddr) {
+ out, err = vm.env.Call(vm.me, codeAddr, inData, gas, vm.price, value)
+ } else {
+ out, err = vm.env.CallCode(vm.me, codeAddr, inData, gas, vm.price, value)
+ }
+ *llvmGas = big2llvm(gas)
+ if err == nil {
+ copy(outData, out)
+ return true
+ }
+ }
+
+ return false
+}
+
+//export env_create
+func env_create(_vm unsafe.Pointer, _gas unsafe.Pointer, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) {
+ vm := (*JitVm)(_vm)
+
+ value := llvm2big((*i256)(_value))
+ initData := C.GoBytes(initDataPtr, C.int(initDataLen)) // TODO: Unnecessary if low balance
+ result := (*i256)(_result)
+ *result = i256{}
+
+ llvmGas := (*i256)(_gas)
+ gas := llvm2big(llvmGas)
+
+ ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value)
+ if suberr == nil {
+ dataGas := big.NewInt(int64(len(ret))) // TODO: Nto the best design. env.Create can do it, it has the reference to gas counter
+ dataGas.Mul(dataGas, GasCreateByte)
+ gas.Sub(gas, dataGas)
+ *result = hash2llvm(ref.Address())
+ }
+ *llvmGas = big2llvm(gas)
+}
+
+//export env_log
+func env_log(_vm unsafe.Pointer, dataPtr unsafe.Pointer, dataLen uint64, _topic1 unsafe.Pointer, _topic2 unsafe.Pointer, _topic3 unsafe.Pointer, _topic4 unsafe.Pointer) {
+ vm := (*JitVm)(_vm)
+
+ data := C.GoBytes(dataPtr, C.int(dataLen))
+
+ topics := make([][]byte, 0, 4)
+ if _topic1 != nil {
+ topics = append(topics, llvm2hash((*i256)(_topic1)))
+ }
+ if _topic2 != nil {
+ topics = append(topics, llvm2hash((*i256)(_topic2)))
+ }
+ if _topic3 != nil {
+ topics = append(topics, llvm2hash((*i256)(_topic3)))
+ }
+ if _topic4 != nil {
+ topics = append(topics, llvm2hash((*i256)(_topic4)))
+ }
+
+ vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data))
+}
+
+//export env_extcode
+func env_extcode(_vm unsafe.Pointer, _addr unsafe.Pointer, o_size *uint64) *byte {
+ vm := (*JitVm)(_vm)
+ addr := llvm2hash((*i256)(_addr))
+ code := vm.Env().State().GetCode(addr)
+ *o_size = uint64(len(code))
+ return getDataPtr(code)
+}
diff --git a/vm/vm_jit_fake.go b/vm/vm_jit_fake.go
new file mode 100644
index 000000000..d6b5be45b
--- /dev/null
+++ b/vm/vm_jit_fake.go
@@ -0,0 +1,10 @@
+// +build !evmjit
+
+package vm
+
+import "fmt"
+
+func NewJitVm(env Environment) VirtualMachine {
+ fmt.Printf("Warning! EVM JIT not enabled.\n")
+ return New(env)
+}
diff --git a/cmd/utils/websockets.go b/websocket/util.go
index 48ea4014b..943032b06 100644
--- a/cmd/utils/websockets.go
+++ b/websocket/util.go
@@ -1,24 +1,20 @@
/*
- This file is part of go-ethereum
+ This file is part of go-ethereum
- go-ethereum is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+ go-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- go-ethereum is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ go-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * @authors
- * Jeffrey Wilcke <i@jev.io>
- */
-package utils
+package websocket
import (
"github.com/ethereum/go-ethereum/core"
@@ -26,15 +22,11 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event/filter"
- "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/ui"
- "github.com/ethereum/go-ethereum/websocket"
"github.com/ethereum/go-ethereum/xeth"
)
-var wslogger = logger.NewLogger("WS")
-
func args(v ...interface{}) []interface{} {
return v
}
@@ -54,8 +46,8 @@ func NewWebSocketServer(eth *eth.Ethereum) *WebSocketServer {
func (self *WebSocketServer) Serv() {
pipe := xeth.NewJSXEth(self.eth)
- wsServ := websocket.NewServer("/eth", ":40404")
- wsServ.MessageFunc(func(c *websocket.Client, msg *websocket.Message) {
+ wsServ := NewServer("/eth", ":40404")
+ wsServ.MessageFunc(func(c *Client, msg *Message) {
switch msg.Call {
case "compile":
data := ethutil.NewValue(msg.Args)
@@ -162,13 +154,6 @@ func toMessages(messages state.Messages) (msgs []xeth.JSMessage) {
return
}
-func StartWebSockets(eth *eth.Ethereum) {
- wslogger.Infoln("Starting WebSockets")
-
- sock := NewWebSocketServer(eth)
- go sock.Serv()
-}
-
// TODO This is starting to become a generic method. Move to utils
func mapToTxParams(object map[string]interface{}) map[string]string {
// Default values