web3 in jail
This commit is contained in:
parent
92737d0395
commit
47b01ec3c2
156
src/jail.go
156
src/jail.go
|
@ -4,6 +4,9 @@ import (
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
"fmt"
|
"fmt"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var statusJs string
|
var statusJs string
|
||||||
|
@ -37,11 +40,25 @@ func printResult(res string, err error) string {
|
||||||
|
|
||||||
func Parse(chatId string, js string) string {
|
func Parse(chatId string, js string) string {
|
||||||
vm := otto.New()
|
vm := otto.New()
|
||||||
jjs := statusJs + js + `
|
initJjs := statusJs + ";"
|
||||||
var catalog = JSON.stringify(_status_catalog);
|
|
||||||
`
|
|
||||||
vms[chatId] = vm
|
vms[chatId] = vm
|
||||||
_, err := vm.Run(jjs)
|
_, err := vm.Run(initJjs)
|
||||||
|
vm.Set("jeth", struct{}{})
|
||||||
|
|
||||||
|
jethObj, _ := vm.Get("jeth")
|
||||||
|
jethObj.Object().Set("send", Send)
|
||||||
|
jethObj.Object().Set("sendAsync", Send)
|
||||||
|
|
||||||
|
jjs := Web3_JS + `
|
||||||
|
var Web3 = require('web3');
|
||||||
|
var web3 = new Web3(jeth);
|
||||||
|
var Bignumber = require("bignumber.js");
|
||||||
|
function bn(val){
|
||||||
|
return new Bignumber(val);
|
||||||
|
}
|
||||||
|
` + js + "; var catalog = JSON.stringify(_status_catalog);"
|
||||||
|
vm.Run(jjs)
|
||||||
|
|
||||||
res, _ := vm.Get("catalog")
|
res, _ := vm.Get("catalog")
|
||||||
|
|
||||||
return printResult(res.String(), err)
|
return printResult(res.String(), err)
|
||||||
|
@ -57,3 +74,134 @@ func Call(chatId string, path string, args string) string {
|
||||||
|
|
||||||
return printResult(res.String(), err);
|
return printResult(res.String(), err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send will serialize the first argument, send it to the node and returns the response.
|
||||||
|
func Send(call otto.FunctionCall) (response otto.Value) {
|
||||||
|
// Ensure that we've got a batch request (array) or a single request (object)
|
||||||
|
arg := call.Argument(0).Object()
|
||||||
|
if arg == nil || (arg.Class() != "Array" && arg.Class() != "Object") {
|
||||||
|
throwJSException("request must be an object or array")
|
||||||
|
}
|
||||||
|
// Convert the otto VM arguments to Go values
|
||||||
|
data, err := call.Otto.Call("JSON.stringify", nil, arg)
|
||||||
|
if err != nil {
|
||||||
|
throwJSException(err.Error())
|
||||||
|
}
|
||||||
|
reqjson, err := data.ToString()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
throwJSException(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
reqs []rpc.JSONRequest
|
||||||
|
batch = true
|
||||||
|
)
|
||||||
|
if err = json.Unmarshal([]byte(reqjson), &reqs); err != nil {
|
||||||
|
// single request?
|
||||||
|
reqs = make([]rpc.JSONRequest, 1)
|
||||||
|
if err = json.Unmarshal([]byte(reqjson), &reqs[0]); err != nil {
|
||||||
|
throwJSException("invalid request")
|
||||||
|
}
|
||||||
|
batch = false
|
||||||
|
}
|
||||||
|
// Iteratively execute the requests
|
||||||
|
call.Otto.Set("response_len", len(reqs))
|
||||||
|
call.Otto.Run("var ret_response = new Array(response_len);")
|
||||||
|
|
||||||
|
for i, req := range reqs {
|
||||||
|
// Execute the RPC request and parse the reply
|
||||||
|
if err = client.Send(&req); err != nil {
|
||||||
|
return newErrorResponse(call, -32603, err.Error(), req.Id)
|
||||||
|
}
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
if err = client.Recv(&result); err != nil {
|
||||||
|
return newErrorResponse(call, -32603, err.Error(), req.Id)
|
||||||
|
}
|
||||||
|
// Feed the reply back into the JavaScript runtime environment
|
||||||
|
id, _ := result["id"]
|
||||||
|
jsonver, _ := result["jsonrpc"]
|
||||||
|
|
||||||
|
call.Otto.Set("ret_id", id)
|
||||||
|
call.Otto.Set("ret_jsonrpc", jsonver)
|
||||||
|
call.Otto.Set("response_idx", i)
|
||||||
|
|
||||||
|
if res, ok := result["result"]; ok {
|
||||||
|
payload, _ := json.Marshal(res)
|
||||||
|
call.Otto.Set("ret_result", string(payload))
|
||||||
|
response, err = call.Otto.Run(`
|
||||||
|
ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) };
|
||||||
|
`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if res, ok := result["error"]; ok {
|
||||||
|
payload, _ := json.Marshal(res)
|
||||||
|
call.Otto.Set("ret_result", string(payload))
|
||||||
|
response, err = call.Otto.Run(`
|
||||||
|
ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, error: JSON.parse(ret_result) };
|
||||||
|
`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return newErrorResponse(call, -32603, fmt.Sprintf("Invalid response"), new(int64))
|
||||||
|
}
|
||||||
|
// Convert single requests back from batch ones
|
||||||
|
if !batch {
|
||||||
|
call.Otto.Run("ret_response = ret_response[0];")
|
||||||
|
}
|
||||||
|
// Execute any registered callbacks
|
||||||
|
if call.Argument(1).IsObject() {
|
||||||
|
call.Otto.Set("callback", call.Argument(1))
|
||||||
|
call.Otto.Run(`
|
||||||
|
if (Object.prototype.toString.call(callback) == '[object Function]') {
|
||||||
|
callback(null, ret_response);
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// newErrorResponse creates a JSON RPC error response for a specific request id,
|
||||||
|
// containing the specified error code and error message. Beside returning the
|
||||||
|
// error to the caller, it also sets the ret_error and ret_response JavaScript
|
||||||
|
// variables.
|
||||||
|
func newErrorResponse(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) {
|
||||||
|
// Bundle the error into a JSON RPC call response
|
||||||
|
res := rpc.JSONErrResponse{
|
||||||
|
Version: "2.0",
|
||||||
|
Id: id,
|
||||||
|
Error: rpc.JSONError{
|
||||||
|
Code: code,
|
||||||
|
Message: msg,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Serialize the error response into JavaScript variables
|
||||||
|
errObj, err := json.Marshal(res.Error)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Failed to serialize JSON RPC error: %v", err)
|
||||||
|
}
|
||||||
|
resObj, err := json.Marshal(res)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Failed to serialize JSON RPC error response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = call.Otto.Run("ret_error = " + string(errObj)); err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Failed to set `ret_error` to the occurred error: %v", err)
|
||||||
|
}
|
||||||
|
resVal, err := call.Otto.Run("ret_response = " + string(resObj))
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Failed to set `ret_response` to the JSON RPC response: %v", err)
|
||||||
|
}
|
||||||
|
return resVal
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// throwJSException panics on an otto.Value. The Otto VM will recover from the
|
||||||
|
// Go panic and throw msg as a JavaScript error.
|
||||||
|
func throwJSException(msg interface{}) otto.Value {
|
||||||
|
val, err := otto.ToValue(msg)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Failed to serialize JavaScript exception %v: %v", msg, err)
|
||||||
|
}
|
||||||
|
panic(val)
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/whisper"
|
"github.com/ethereum/go-ethereum/whisper"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -39,6 +40,7 @@ var (
|
||||||
accountManager *accounts.Manager // the account manager attached to the currentNode
|
accountManager *accounts.Manager // the account manager attached to the currentNode
|
||||||
whisperService *whisper.Whisper // whisper service
|
whisperService *whisper.Whisper // whisper service
|
||||||
datadir string // data directory for geth
|
datadir string // data directory for geth
|
||||||
|
client rpc.Client
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -100,6 +102,7 @@ func RunNode(nodeIn *node.Node) {
|
||||||
}
|
}
|
||||||
lightEthereum.StatusBackend.SetTransactionQueueHandler(onSendTransactionRequest)
|
lightEthereum.StatusBackend.SetTransactionQueueHandler(onSendTransactionRequest)
|
||||||
|
|
||||||
|
client, _ = nodeIn.Attach()
|
||||||
nodeIn.Wait()
|
nodeIn.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue