signer/rules: use goja and remove otto (#20599)

* signer: replace otto with goja

* go.mod: remove Otto
This commit is contained in:
Guillaume Ballet
2020-01-29 13:47:56 +01:00
committed by GitHub
parent a903912b96
commit 594e038e75
4 changed files with 26 additions and 31 deletions

View File

@ -22,12 +22,12 @@ import (
"os"
"strings"
"github.com/dop251/goja"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/signer/core"
"github.com/ethereum/go-ethereum/signer/rules/deps"
"github.com/ethereum/go-ethereum/signer/storage"
"github.com/robertkrimen/otto"
)
var (
@ -36,13 +36,13 @@ var (
// consoleOutput is an override for the console.log and console.error methods to
// stream the output into the configured output stream instead of stdout.
func consoleOutput(call otto.FunctionCall) otto.Value {
func consoleOutput(call goja.FunctionCall) goja.Value {
output := []string{"JS:> "}
for _, argument := range call.ArgumentList {
for _, argument := range call.Arguments {
output = append(output, fmt.Sprintf("%v", argument))
}
fmt.Fprintln(os.Stderr, strings.Join(output, " "))
return otto.Value{}
return goja.Undefined()
}
// rulesetUI provides an implementation of UIClientAPI that evaluates a javascript
@ -70,45 +70,47 @@ func (r *rulesetUI) Init(javascriptRules string) error {
r.jsRules = javascriptRules
return nil
}
func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error) {
func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (goja.Value, error) {
// Instantiate a fresh vm engine every time
vm := otto.New()
vm := goja.New()
// Set the native callbacks
consoleObj, _ := vm.Get("console")
consoleObj.Object().Set("log", consoleOutput)
consoleObj.Object().Set("error", consoleOutput)
consoleObj := vm.NewObject()
consoleObj.Set("log", consoleOutput)
consoleObj.Set("error", consoleOutput)
vm.Set("console", consoleObj)
vm.Set("storage", struct{}{})
storageObj, _ := vm.Get("storage")
storageObj.Object().Set("put", func(call otto.FunctionCall) otto.Value {
storageObj := vm.NewObject()
storageObj.Set("put", func(call goja.FunctionCall) goja.Value {
key, val := call.Argument(0).String(), call.Argument(1).String()
if val == "" {
r.storage.Del(key)
} else {
r.storage.Put(key, val)
}
return otto.NullValue()
return goja.Null()
})
storageObj.Object().Set("get", func(call otto.FunctionCall) otto.Value {
storageObj.Set("get", func(call goja.FunctionCall) goja.Value {
goval, _ := r.storage.Get(call.Argument(0).String())
jsval, _ := otto.ToValue(goval)
jsval := vm.ToValue(goval)
return jsval
})
vm.Set("storage", storageObj)
// Load bootstrap libraries
script, err := vm.Compile("bignumber.js", BigNumber_JS)
script, err := goja.Compile("bignumber.js", string(BigNumber_JS), true)
if err != nil {
log.Warn("Failed loading libraries", "err", err)
return otto.UndefinedValue(), err
return goja.Undefined(), err
}
vm.Run(script)
vm.RunProgram(script)
// Run the actual rule implementation
_, err = vm.Run(r.jsRules)
_, err = vm.RunString(r.jsRules)
if err != nil {
log.Warn("Execution failed", "err", err)
return otto.UndefinedValue(), err
return goja.Undefined(), err
}
// And the actual call
@ -119,7 +121,7 @@ func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error
jsonbytes, err := json.Marshal(jsarg)
if err != nil {
log.Warn("failed marshalling data", "data", jsarg)
return otto.UndefinedValue(), err
return goja.Undefined(), err
}
// Now, we call foobar(JSON.parse(<jsondata>)).
var call string
@ -128,7 +130,7 @@ func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error
} else {
call = fmt.Sprintf("%v()", jsfunc)
}
return vm.Run(call)
return vm.RunString(call)
}
func (r *rulesetUI) checkApproval(jsfunc string, jsarg []byte, err error) (bool, error) {
@ -140,11 +142,7 @@ func (r *rulesetUI) checkApproval(jsfunc string, jsarg []byte, err error) (bool,
log.Info("error occurred during execution", "error", err)
return false, err
}
result, err := v.ToString()
if err != nil {
log.Info("error occurred during response unmarshalling", "error", err)
return false, err
}
result := v.ToString().String()
if result == "Approve" {
log.Info("Op approved")
return true, nil