Skip to content

Commit f52cae1

Browse files
committed
console: apply changes from ethereum#19761
Completion tests still seem to fail
1 parent 498eaed commit f52cae1

File tree

8 files changed

+246
-195
lines changed

8 files changed

+246
-195
lines changed

console/bridge.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"github.com/dop251/goja"
2828
"github.com/ethereum/go-ethereum/accounts/scwallet"
2929
"github.com/ethereum/go-ethereum/accounts/usbwallet"
30-
"github.com/ethereum/go-ethereum/log"
3130
"github.com/ethereum/go-ethereum/rpc"
3231
)
3332

console/console.go

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ import (
2828
"strings"
2929
"syscall"
3030

31+
"github.com/dop251/goja"
3132
"github.com/ethereum/go-ethereum/internal/jsre"
3233
"github.com/ethereum/go-ethereum/internal/web3ext"
3334
"github.com/ethereum/go-ethereum/rpc"
3435
"github.com/mattn/go-colorable"
3536
"github.com/peterh/liner"
36-
"github.com/robertkrimen/otto"
3737
)
3838

3939
var (
@@ -64,13 +64,14 @@ type Config struct {
6464
// JavaScript console attached to a running node via an external or in-process RPC
6565
// client.
6666
type Console struct {
67-
client *rpc.Client // RPC client to execute Ethereum requests through
68-
jsre *jsre.JSRE // JavaScript runtime environment running the interpreter
69-
prompt string // Input prompt prefix string
70-
prompter UserPrompter // Input prompter to allow interactive user feedback
71-
histPath string // Absolute path to the console scrollback history
72-
history []string // Scroll history maintained by the console
73-
printer io.Writer // Output writer to serialize any display strings to
67+
client *rpc.Client // RPC client to execute Ethereum requests through
68+
jsre *jsre.JSRE // JavaScript runtime environment running the interpreter
69+
prompt string // Input prompt prefix string
70+
prompter UserPrompter // Input prompter to allow interactive user feedback
71+
histPath string // Absolute path to the console scrollback history
72+
history []string // Scroll history maintained by the console
73+
printer io.Writer // Output writer to serialize any display strings to
74+
runtime *goja.Runtime // The javascript runtime
7475
}
7576

7677
// New initializes a JavaScript interpreted runtime environment and sets defaults
@@ -86,10 +87,15 @@ func New(config Config) (*Console, error) {
8687
if config.Printer == nil {
8788
config.Printer = colorable.NewColorableStdout()
8889
}
90+
91+
// Create the JS runtime
92+
runtime := goja.New()
93+
8994
// Initialize the console and return
9095
console := &Console{
96+
runtime: runtime,
9197
client: config.Client,
92-
jsre: jsre.New(config.DocRoot, config.Printer),
98+
jsre: jsre.New(config.DocRoot, config.Printer, runtime),
9399
prompt: config.Prompt,
94100
prompter: config.Prompter,
95101
printer: config.Printer,
@@ -108,22 +114,31 @@ func New(config Config) (*Console, error) {
108114
// the console's JavaScript namespaces based on the exposed modules.
109115
func (c *Console) init(preload []string) error {
110116
// Initialize the JavaScript <-> Go RPC bridge
111-
bridge := newBridge(c.client, c.prompter, c.printer)
112-
c.jsre.Set("jeth", struct{}{})
117+
bridge := newBridge(c.client, c.prompter, c.printer, c.runtime)
118+
c.jsre.Run("jeth = {};")
119+
c.jsre.Run("console = {};")
113120

114-
jethObj, _ := c.jsre.Get("jeth")
115-
jethObj.Object().Set("send", bridge.Send)
116-
jethObj.Object().Set("sendAsync", bridge.Send)
121+
jethObj := c.jsre.Get("jeth").ToObject(c.runtime)
122+
if err := jethObj.Set("send", bridge.Send); err != nil {
123+
panic(err)
124+
}
125+
if err := jethObj.Set("sendAsync", bridge.Send); err != nil {
126+
panic(err)
127+
}
117128

118-
consoleObj, _ := c.jsre.Get("console")
119-
consoleObj.Object().Set("log", c.consoleOutput)
120-
consoleObj.Object().Set("error", c.consoleOutput)
129+
consoleObj := c.runtime.Get("console").ToObject(c.runtime)
130+
if err := consoleObj.Set("log", c.consoleOutput); err != nil {
131+
panic(err)
132+
}
133+
if err := consoleObj.Set("error", c.consoleOutput); err != nil {
134+
panic(err)
135+
}
121136

122137
// Load all the internal utility JavaScript libraries
123-
if err := c.jsre.Compile("bignumber.js", jsre.BignumberJs); err != nil {
138+
if err := c.jsre.Compile("bignumber.js", string(jsre.BignumberJs)); err != nil {
124139
return fmt.Errorf("bignumber.js: %v", err)
125140
}
126-
if err := c.jsre.Compile("web3.js", jsre.Web3Js); err != nil {
141+
if err := c.jsre.Compile("web3.js", string(jsre.Web3Js)); err != nil {
127142
return fmt.Errorf("web3.js: %v", err)
128143
}
129144
if _, err := c.jsre.Run("var Web3 = require('web3');"); err != nil {
@@ -148,7 +163,7 @@ func (c *Console) init(preload []string) error {
148163
return fmt.Errorf("%s.js: %v", api, err)
149164
}
150165
flatten += fmt.Sprintf("var %s = web3.%s; ", api, api)
151-
} else if obj, err := c.jsre.Run("web3." + api); err == nil && obj.IsObject() {
166+
} else if obj, err := c.jsre.Run("web3." + api); err == nil && obj.ToObject(c.runtime) != nil {
152167
// Enable web3.js built-in extension if available.
153168
flatten += fmt.Sprintf("var %s = web3.%s; ", api, api)
154169
}
@@ -162,16 +177,16 @@ func (c *Console) init(preload []string) error {
162177
// If the console is in interactive mode, instrument password related methods to query the user
163178
if c.prompter != nil {
164179
// Retrieve the account management object to instrument
165-
personal, err := c.jsre.Get("personal")
166-
if err != nil {
167-
return err
180+
personal := c.jsre.Get("personal")
181+
if personal == nil {
182+
return fmt.Errorf("Could not find personal")
168183
}
169184
// Override the openWallet, unlockAccount, newAccount and sign methods since
170185
// these require user interaction. Assign these method in the Console the
171186
// original web3 callbacks. These will be called by the jeth.* methods after
172187
// they got the password from the user and send the original web3 request to
173188
// the backend.
174-
if obj := personal.Object(); obj != nil { // make sure the personal api is enabled over the interface
189+
if obj := personal.ToObject(c.runtime); obj != nil { // make sure the personal api is enabled over the interface
175190
if _, err = c.jsre.Run(`jeth.openWallet = personal.openWallet;`); err != nil {
176191
return fmt.Errorf("personal.openWallet: %v", err)
177192
}
@@ -191,11 +206,11 @@ func (c *Console) init(preload []string) error {
191206
}
192207
}
193208
// The admin.sleep and admin.sleepBlocks are offered by the console and not by the RPC layer.
194-
admin, err := c.jsre.Get("admin")
195-
if err != nil {
196-
return err
209+
admin := c.jsre.Get("admin")
210+
if admin == nil {
211+
return fmt.Errorf("Could not find admin")
197212
}
198-
if obj := admin.Object(); obj != nil { // make sure the admin api is enabled over the interface
213+
if obj := admin.ToObject(c.runtime); obj != nil { // make sure the admin api is enabled over the interface
199214
obj.Set("sleepBlocks", bridge.SleepBlocks)
200215
obj.Set("sleep", bridge.Sleep)
201216
obj.Set("clearHistory", c.clearHistory)
@@ -204,8 +219,8 @@ func (c *Console) init(preload []string) error {
204219
for _, path := range preload {
205220
if err := c.jsre.Exec(path); err != nil {
206221
failure := err.Error()
207-
if ottoErr, ok := err.(*otto.Error); ok {
208-
failure = ottoErr.String()
222+
if gojaErr, ok := err.(*goja.Exception); ok {
223+
failure = gojaErr.String()
209224
}
210225
return fmt.Errorf("%s: %v", path, failure)
211226
}
@@ -235,13 +250,13 @@ func (c *Console) clearHistory() {
235250

236251
// consoleOutput is an override for the console.log and console.error methods to
237252
// stream the output into the configured output stream instead of stdout.
238-
func (c *Console) consoleOutput(call otto.FunctionCall) otto.Value {
253+
func (c *Console) consoleOutput(call goja.FunctionCall) goja.Value {
239254
var output []string
240-
for _, argument := range call.ArgumentList {
255+
for _, argument := range call.Arguments {
241256
output = append(output, fmt.Sprintf("%v", argument))
242257
}
243258
fmt.Fprintln(c.printer, strings.Join(output, " "))
244-
return otto.Value{}
259+
return goja.Null()
245260
}
246261

247262
// AutoCompleteInput is a pre-assembled word completer to be used by the user

console/console_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ func TestPrettyError(t *testing.T) {
289289
defer tester.Close(t)
290290
tester.console.Evaluate("throw 'hello'")
291291

292-
want := jsre.ErrorColor("hello") + "\n"
292+
want := jsre.ErrorColor("hello") + "\n\tat <eval>:1:7(1)\n\n"
293293
if output := tester.output.String(); output != want {
294294
t.Fatalf("pretty error mismatch: have %s, want %s", output, want)
295295
}

internal/jsre/completion.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,32 @@ import (
2020
"sort"
2121
"strings"
2222

23-
"github.com/robertkrimen/otto"
23+
"github.com/dop251/goja"
2424
)
2525

2626
// CompleteKeywords returns potential continuations for the given line. Since line is
2727
// evaluated, callers need to make sure that evaluating line does not have side effects.
2828
func (jsre *JSRE) CompleteKeywords(line string) []string {
2929
var results []string
30-
jsre.Do(func(vm *otto.Otto) {
30+
jsre.Do(func(vm *goja.Runtime) {
3131
results = getCompletions(vm, line)
3232
})
3333
return results
3434
}
3535

36-
func getCompletions(vm *otto.Otto, line string) (results []string) {
36+
func getCompletions(vm *goja.Runtime, line string) (results []string) {
3737
parts := strings.Split(line, ".")
3838
objRef := "this"
3939
prefix := line
40+
var obj *goja.Object
4041
if len(parts) > 1 {
4142
objRef = strings.Join(parts[0:len(parts)-1], ".")
4243
prefix = parts[len(parts)-1]
44+
obj, _ = vm.Get(objRef).(*goja.Object)
45+
} else {
46+
obj = vm.GlobalObject()
4347
}
4448

45-
obj, _ := vm.Object(objRef)
4649
if obj == nil {
4750
return nil
4851
}
@@ -59,9 +62,11 @@ func getCompletions(vm *otto.Otto, line string) (results []string) {
5962
// Append opening parenthesis (for functions) or dot (for objects)
6063
// if the line itself is the only completion.
6164
if len(results) == 1 && results[0] == line {
62-
obj, _ := vm.Object(line)
65+
/* XXX Get will return `nil` et j'avais suppose que ca lancerait
66+
une exception donc je dois tout revoir */
67+
obj := vm.Get(line)
6368
if obj != nil {
64-
if obj.Class() == "Function" {
69+
if _, isfunc := goja.AssertFunction(obj); isfunc {
6570
results[0] += "("
6671
} else {
6772
results[0] += "."

internal/jsre/completion_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ import (
2020
"os"
2121
"reflect"
2222
"testing"
23+
24+
"github.com/dop251/goja"
2325
)
2426

2527
func TestCompleteKeywords(t *testing.T) {
26-
re := New("", os.Stdout)
28+
re := New("", os.Stdout, goja.New())
2729
re.Run(`
2830
function theClass() {
2931
this.foo = 3;

0 commit comments

Comments
 (0)