github.com/daethereum/go-dae@v2.2.3+incompatible/eth/tracers/js/goja.go (about) 1 // Copyright 2022 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package js 18 19 import ( 20 "encoding/json" 21 "errors" 22 "fmt" 23 "math/big" 24 "time" 25 26 "github.com/dop251/goja" 27 28 "github.com/daethereum/go-dae/common" 29 "github.com/daethereum/go-dae/common/hexutil" 30 "github.com/daethereum/go-dae/core/vm" 31 "github.com/daethereum/go-dae/crypto" 32 "github.com/daethereum/go-dae/eth/tracers" 33 jsassets "github.com/daethereum/go-dae/eth/tracers/js/internal/tracers" 34 ) 35 36 var assetTracers = make(map[string]string) 37 38 // init retrieves the JavaScript transaction tracers included in go-ethereum. 39 func init() { 40 var err error 41 assetTracers, err = jsassets.Load() 42 if err != nil { 43 panic(err) 44 } 45 tracers.RegisterLookup(true, newJsTracer) 46 } 47 48 // bigIntProgram is compiled once and the exported function mostly invoked to convert 49 // hex strings into big ints. 50 var bigIntProgram = goja.MustCompile("bigInt", bigIntegerJS, false) 51 52 type toBigFn = func(vm *goja.Runtime, val string) (goja.Value, error) 53 type toBufFn = func(vm *goja.Runtime, val []byte) (goja.Value, error) 54 type fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error) 55 56 func toBuf(vm *goja.Runtime, bufType goja.Value, val []byte) (goja.Value, error) { 57 // bufType is usually Uint8Array. This is equivalent to `new Uint8Array(val)` in JS. 58 return vm.New(bufType, vm.ToValue(vm.NewArrayBuffer(val))) 59 } 60 61 func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString bool) ([]byte, error) { 62 obj := buf.ToObject(vm) 63 switch obj.ClassName() { 64 case "String": 65 if !allowString { 66 break 67 } 68 return common.FromHex(obj.String()), nil 69 70 case "Array": 71 var b []byte 72 if err := vm.ExportTo(buf, &b); err != nil { 73 return nil, err 74 } 75 return b, nil 76 77 case "Object": 78 if !obj.Get("constructor").SameAs(bufType) { 79 break 80 } 81 b := obj.Get("buffer").Export().(goja.ArrayBuffer).Bytes() 82 return b, nil 83 } 84 return nil, fmt.Errorf("invalid buffer type") 85 } 86 87 // jsTracer is an implementation of the Tracer interface which evaluates 88 // JS functions on the relevant EVM hooks. It uses Goja as its JS engine. 89 type jsTracer struct { 90 vm *goja.Runtime 91 env *vm.EVM 92 toBig toBigFn // Converts a hex string into a JS bigint 93 toBuf toBufFn // Converts a []byte into a JS buffer 94 fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte 95 ctx map[string]goja.Value // KV-bag passed to JS in `result` 96 activePrecompiles []common.Address // List of active precompiles at current block 97 traceStep bool // True if tracer object exposes a `step()` method 98 traceFrame bool // True if tracer object exposes the `enter()` and `exit()` methods 99 gasLimit uint64 // Amount of gas bought for the whole tx 100 err error // Any error that should stop tracing 101 obj *goja.Object // Trace object 102 103 // Methods exposed by tracer 104 result goja.Callable 105 fault goja.Callable 106 step goja.Callable 107 enter goja.Callable 108 exit goja.Callable 109 110 // Underlying structs being passed into JS 111 log *steplog 112 frame *callframe 113 frameResult *callframeResult 114 115 // Goja-wrapping of types prepared for JS consumption 116 logValue goja.Value 117 dbValue goja.Value 118 frameValue goja.Value 119 frameResultValue goja.Value 120 } 121 122 // newJsTracer instantiates a new JS tracer instance. code is either 123 // the name of a built-in JS tracer or a Javascript snippet which 124 // evaluates to an expression returning an object with certain methods. 125 // The methods `result` and `fault` are required to be present. 126 // The methods `step`, `enter`, and `exit` are optional, but note that 127 // `enter` and `exit` always go together. 128 func newJsTracer(code string, ctx *tracers.Context) (tracers.Tracer, error) { 129 if c, ok := assetTracers[code]; ok { 130 code = c 131 } 132 vm := goja.New() 133 // By default field names are exported to JS as is, i.e. capitalized. 134 vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) 135 t := &jsTracer{ 136 vm: vm, 137 ctx: make(map[string]goja.Value), 138 } 139 if ctx == nil { 140 ctx = new(tracers.Context) 141 } 142 if ctx.BlockHash != (common.Hash{}) { 143 t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes()) 144 if ctx.TxHash != (common.Hash{}) { 145 t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex) 146 t.ctx["txHash"] = vm.ToValue(ctx.TxHash.Bytes()) 147 } 148 } 149 150 t.setTypeConverters() 151 t.setBuiltinFunctions() 152 ret, err := vm.RunString("(" + code + ")") 153 if err != nil { 154 return nil, err 155 } 156 // Check tracer's interface for required and optional methods. 157 obj := ret.ToObject(vm) 158 result, ok := goja.AssertFunction(obj.Get("result")) 159 if !ok { 160 return nil, errors.New("trace object must expose a function result()") 161 } 162 fault, ok := goja.AssertFunction(obj.Get("fault")) 163 if !ok { 164 return nil, errors.New("trace object must expose a function fault()") 165 } 166 step, ok := goja.AssertFunction(obj.Get("step")) 167 t.traceStep = ok 168 enter, hasEnter := goja.AssertFunction(obj.Get("enter")) 169 exit, hasExit := goja.AssertFunction(obj.Get("exit")) 170 if hasEnter != hasExit { 171 return nil, errors.New("trace object must expose either both or none of enter() and exit()") 172 } 173 t.traceFrame = hasEnter 174 t.obj = obj 175 t.step = step 176 t.enter = enter 177 t.exit = exit 178 t.result = result 179 t.fault = fault 180 // Setup objects carrying data to JS. These are created once and re-used. 181 t.log = &steplog{ 182 vm: vm, 183 op: &opObj{vm: vm}, 184 memory: &memoryObj{vm: vm, toBig: t.toBig, toBuf: t.toBuf}, 185 stack: &stackObj{vm: vm, toBig: t.toBig}, 186 contract: &contractObj{vm: vm, toBig: t.toBig, toBuf: t.toBuf}, 187 } 188 t.frame = &callframe{vm: vm, toBig: t.toBig, toBuf: t.toBuf} 189 t.frameResult = &callframeResult{vm: vm, toBuf: t.toBuf} 190 t.frameValue = t.frame.setupObject() 191 t.frameResultValue = t.frameResult.setupObject() 192 t.logValue = t.log.setupObject() 193 return t, nil 194 } 195 196 // CaptureTxStart implements the Tracer interface and is invoked at the beginning of 197 // transaction processing. 198 func (t *jsTracer) CaptureTxStart(gasLimit uint64) { 199 t.gasLimit = gasLimit 200 } 201 202 // CaptureTxStart implements the Tracer interface and is invoked at the end of 203 // transaction processing. 204 func (t *jsTracer) CaptureTxEnd(restGas uint64) {} 205 206 // CaptureStart implements the Tracer interface to initialize the tracing operation. 207 func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { 208 t.env = env 209 db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} 210 t.dbValue = db.setupObject() 211 if create { 212 t.ctx["type"] = t.vm.ToValue("CREATE") 213 } else { 214 t.ctx["type"] = t.vm.ToValue("CALL") 215 } 216 t.ctx["from"] = t.vm.ToValue(from.Bytes()) 217 t.ctx["to"] = t.vm.ToValue(to.Bytes()) 218 t.ctx["input"] = t.vm.ToValue(input) 219 t.ctx["gas"] = t.vm.ToValue(gas) 220 t.ctx["gasPrice"] = t.vm.ToValue(env.TxContext.GasPrice) 221 valueBig, err := t.toBig(t.vm, value.String()) 222 if err != nil { 223 t.err = err 224 return 225 } 226 t.ctx["value"] = valueBig 227 t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64()) 228 // Update list of precompiles based on current block 229 rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) 230 t.activePrecompiles = vm.ActivePrecompiles(rules) 231 t.ctx["intrinsicGas"] = t.vm.ToValue(t.gasLimit - gas) 232 } 233 234 // CaptureState implements the Tracer interface to trace a single step of VM execution. 235 func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { 236 if !t.traceStep { 237 return 238 } 239 if t.err != nil { 240 return 241 } 242 243 log := t.log 244 log.op.op = op 245 log.memory.memory = scope.Memory 246 log.stack.stack = scope.Stack 247 log.contract.contract = scope.Contract 248 log.pc = uint(pc) 249 log.gas = uint(gas) 250 log.cost = uint(cost) 251 log.depth = uint(depth) 252 log.err = err 253 if _, err := t.step(t.obj, t.logValue, t.dbValue); err != nil { 254 t.onError("step", err) 255 } 256 } 257 258 // CaptureFault implements the Tracer interface to trace an execution fault 259 func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { 260 if t.err != nil { 261 return 262 } 263 // Other log fields have been already set as part of the last CaptureState. 264 t.log.err = err 265 if _, err := t.fault(t.obj, t.logValue, t.dbValue); err != nil { 266 t.onError("fault", err) 267 } 268 } 269 270 // CaptureEnd is called after the call finishes to finalize the tracing. 271 func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, duration time.Duration, err error) { 272 t.ctx["output"] = t.vm.ToValue(output) 273 t.ctx["time"] = t.vm.ToValue(duration.String()) 274 t.ctx["gasUsed"] = t.vm.ToValue(gasUsed) 275 if err != nil { 276 t.ctx["error"] = t.vm.ToValue(err.Error()) 277 } 278 } 279 280 // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). 281 func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { 282 if !t.traceFrame { 283 return 284 } 285 if t.err != nil { 286 return 287 } 288 289 t.frame.typ = typ.String() 290 t.frame.from = from 291 t.frame.to = to 292 t.frame.input = common.CopyBytes(input) 293 t.frame.gas = uint(gas) 294 t.frame.value = nil 295 if value != nil { 296 t.frame.value = new(big.Int).SetBytes(value.Bytes()) 297 } 298 299 if _, err := t.enter(t.obj, t.frameValue); err != nil { 300 t.onError("enter", err) 301 } 302 } 303 304 // CaptureExit is called when EVM exits a scope, even if the scope didn't 305 // execute any code. 306 func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) { 307 if !t.traceFrame { 308 return 309 } 310 311 t.frameResult.gasUsed = uint(gasUsed) 312 t.frameResult.output = common.CopyBytes(output) 313 t.frameResult.err = err 314 315 if _, err := t.exit(t.obj, t.frameResultValue); err != nil { 316 t.onError("exit", err) 317 } 318 } 319 320 // GetResult calls the Javascript 'result' function and returns its value, or any accumulated error 321 func (t *jsTracer) GetResult() (json.RawMessage, error) { 322 ctx := t.vm.ToValue(t.ctx) 323 res, err := t.result(t.obj, ctx, t.dbValue) 324 if err != nil { 325 return nil, wrapError("result", err) 326 } 327 encoded, err := json.Marshal(res) 328 if err != nil { 329 return nil, err 330 } 331 return json.RawMessage(encoded), t.err 332 } 333 334 // Stop terminates execution of the tracer at the first opportune moment. 335 func (t *jsTracer) Stop(err error) { 336 t.vm.Interrupt(err) 337 } 338 339 // onError is called anytime the running JS code is interrupted 340 // and returns an error. It in turn pings the EVM to cancel its 341 // execution. 342 func (t *jsTracer) onError(context string, err error) { 343 t.err = wrapError(context, err) 344 // `env` is set on CaptureStart which comes before any JS execution. 345 // So it should be non-nil. 346 t.env.Cancel() 347 } 348 349 func wrapError(context string, err error) error { 350 return fmt.Errorf("%v in server-side tracer function '%v'", err, context) 351 } 352 353 // setBuiltinFunctions injects Go functions which are available to tracers into the environment. 354 // It depends on type converters having been set up. 355 func (t *jsTracer) setBuiltinFunctions() { 356 vm := t.vm 357 // TODO: load console from goja-nodejs 358 vm.Set("toHex", func(v goja.Value) string { 359 b, err := t.fromBuf(vm, v, false) 360 if err != nil { 361 vm.Interrupt(err) 362 return "" 363 } 364 return hexutil.Encode(b) 365 }) 366 vm.Set("toWord", func(v goja.Value) goja.Value { 367 // TODO: add test with []byte len < 32 or > 32 368 b, err := t.fromBuf(vm, v, true) 369 if err != nil { 370 vm.Interrupt(err) 371 return nil 372 } 373 b = common.BytesToHash(b).Bytes() 374 res, err := t.toBuf(vm, b) 375 if err != nil { 376 vm.Interrupt(err) 377 return nil 378 } 379 return res 380 }) 381 vm.Set("toAddress", func(v goja.Value) goja.Value { 382 a, err := t.fromBuf(vm, v, true) 383 if err != nil { 384 vm.Interrupt(err) 385 return nil 386 } 387 a = common.BytesToAddress(a).Bytes() 388 res, err := t.toBuf(vm, a) 389 if err != nil { 390 vm.Interrupt(err) 391 return nil 392 } 393 return res 394 }) 395 vm.Set("toContract", func(from goja.Value, nonce uint) goja.Value { 396 a, err := t.fromBuf(vm, from, true) 397 if err != nil { 398 vm.Interrupt(err) 399 return nil 400 } 401 addr := common.BytesToAddress(a) 402 b := crypto.CreateAddress(addr, uint64(nonce)).Bytes() 403 res, err := t.toBuf(vm, b) 404 if err != nil { 405 vm.Interrupt(err) 406 return nil 407 } 408 return res 409 }) 410 vm.Set("toContract2", func(from goja.Value, salt string, initcode goja.Value) goja.Value { 411 a, err := t.fromBuf(vm, from, true) 412 if err != nil { 413 vm.Interrupt(err) 414 return nil 415 } 416 addr := common.BytesToAddress(a) 417 code, err := t.fromBuf(vm, initcode, true) 418 if err != nil { 419 vm.Interrupt(err) 420 return nil 421 } 422 code = common.CopyBytes(code) 423 codeHash := crypto.Keccak256(code) 424 b := crypto.CreateAddress2(addr, common.HexToHash(salt), codeHash).Bytes() 425 res, err := t.toBuf(vm, b) 426 if err != nil { 427 vm.Interrupt(err) 428 return nil 429 } 430 return res 431 }) 432 vm.Set("isPrecompiled", func(v goja.Value) bool { 433 a, err := t.fromBuf(vm, v, true) 434 if err != nil { 435 vm.Interrupt(err) 436 return false 437 } 438 addr := common.BytesToAddress(a) 439 for _, p := range t.activePrecompiles { 440 if p == addr { 441 return true 442 } 443 } 444 return false 445 }) 446 vm.Set("slice", func(slice goja.Value, start, end int) goja.Value { 447 b, err := t.fromBuf(vm, slice, false) 448 if err != nil { 449 vm.Interrupt(err) 450 return nil 451 } 452 if start < 0 || start > end || end > len(b) { 453 vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start)) 454 return nil 455 } 456 res, err := t.toBuf(vm, b[start:end]) 457 if err != nil { 458 vm.Interrupt(err) 459 return nil 460 } 461 return res 462 }) 463 } 464 465 // setTypeConverters sets up utilities for converting Go types into those 466 // suitable for JS consumption. 467 func (t *jsTracer) setTypeConverters() error { 468 // Inject bigint logic. 469 // TODO: To be replaced after goja adds support for native JS bigint. 470 toBigCode, err := t.vm.RunProgram(bigIntProgram) 471 if err != nil { 472 return err 473 } 474 // Used to create JS bigint objects from go. 475 toBigFn, ok := goja.AssertFunction(toBigCode) 476 if !ok { 477 return errors.New("failed to bind bigInt func") 478 } 479 toBigWrapper := func(vm *goja.Runtime, val string) (goja.Value, error) { 480 return toBigFn(goja.Undefined(), vm.ToValue(val)) 481 } 482 t.toBig = toBigWrapper 483 // NOTE: We need this workaround to create JS buffers because 484 // goja doesn't at the moment expose constructors for typed arrays. 485 // 486 // Cache uint8ArrayType once to be used every time for less overhead. 487 uint8ArrayType := t.vm.Get("Uint8Array") 488 toBufWrapper := func(vm *goja.Runtime, val []byte) (goja.Value, error) { 489 return toBuf(vm, uint8ArrayType, val) 490 } 491 t.toBuf = toBufWrapper 492 fromBufWrapper := func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error) { 493 return fromBuf(vm, uint8ArrayType, buf, allowString) 494 } 495 t.fromBuf = fromBufWrapper 496 return nil 497 } 498 499 type opObj struct { 500 vm *goja.Runtime 501 op vm.OpCode 502 } 503 504 func (o *opObj) ToNumber() int { 505 return int(o.op) 506 } 507 508 func (o *opObj) ToString() string { 509 return o.op.String() 510 } 511 512 func (o *opObj) IsPush() bool { 513 return o.op.IsPush() 514 } 515 516 func (o *opObj) setupObject() *goja.Object { 517 obj := o.vm.NewObject() 518 obj.Set("toNumber", o.vm.ToValue(o.ToNumber)) 519 obj.Set("toString", o.vm.ToValue(o.ToString)) 520 obj.Set("isPush", o.vm.ToValue(o.IsPush)) 521 return obj 522 } 523 524 type memoryObj struct { 525 memory *vm.Memory 526 vm *goja.Runtime 527 toBig toBigFn 528 toBuf toBufFn 529 } 530 531 func (mo *memoryObj) Slice(begin, end int64) goja.Value { 532 b, err := mo.slice(begin, end) 533 if err != nil { 534 mo.vm.Interrupt(err) 535 return nil 536 } 537 res, err := mo.toBuf(mo.vm, b) 538 if err != nil { 539 mo.vm.Interrupt(err) 540 return nil 541 } 542 return res 543 } 544 545 // slice returns the requested range of memory as a byte slice. 546 func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { 547 if end == begin { 548 return []byte{}, nil 549 } 550 if end < begin || begin < 0 { 551 return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end) 552 } 553 if mo.memory.Len() < int(end) { 554 return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), begin, end-begin) 555 } 556 return mo.memory.GetCopy(begin, end-begin), nil 557 } 558 559 func (mo *memoryObj) GetUint(addr int64) goja.Value { 560 value, err := mo.getUint(addr) 561 if err != nil { 562 mo.vm.Interrupt(err) 563 return nil 564 } 565 res, err := mo.toBig(mo.vm, value.String()) 566 if err != nil { 567 mo.vm.Interrupt(err) 568 return nil 569 } 570 return res 571 } 572 573 // getUint returns the 32 bytes at the specified address interpreted as a uint. 574 func (mo *memoryObj) getUint(addr int64) (*big.Int, error) { 575 if mo.memory.Len() < int(addr)+32 || addr < 0 { 576 return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), addr, 32) 577 } 578 return new(big.Int).SetBytes(mo.memory.GetPtr(addr, 32)), nil 579 } 580 581 func (mo *memoryObj) Length() int { 582 return mo.memory.Len() 583 } 584 585 func (m *memoryObj) setupObject() *goja.Object { 586 o := m.vm.NewObject() 587 o.Set("slice", m.vm.ToValue(m.Slice)) 588 o.Set("getUint", m.vm.ToValue(m.GetUint)) 589 o.Set("length", m.vm.ToValue(m.Length)) 590 return o 591 } 592 593 type stackObj struct { 594 stack *vm.Stack 595 vm *goja.Runtime 596 toBig toBigFn 597 } 598 599 func (s *stackObj) Peek(idx int) goja.Value { 600 value, err := s.peek(idx) 601 if err != nil { 602 s.vm.Interrupt(err) 603 return nil 604 } 605 res, err := s.toBig(s.vm, value.String()) 606 if err != nil { 607 s.vm.Interrupt(err) 608 return nil 609 } 610 return res 611 } 612 613 // peek returns the nth-from-the-top element of the stack. 614 func (s *stackObj) peek(idx int) (*big.Int, error) { 615 if len(s.stack.Data()) <= idx || idx < 0 { 616 return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx) 617 } 618 return s.stack.Back(idx).ToBig(), nil 619 } 620 621 func (s *stackObj) Length() int { 622 return len(s.stack.Data()) 623 } 624 625 func (s *stackObj) setupObject() *goja.Object { 626 o := s.vm.NewObject() 627 o.Set("peek", s.vm.ToValue(s.Peek)) 628 o.Set("length", s.vm.ToValue(s.Length)) 629 return o 630 } 631 632 type dbObj struct { 633 db vm.StateDB 634 vm *goja.Runtime 635 toBig toBigFn 636 toBuf toBufFn 637 fromBuf fromBufFn 638 } 639 640 func (do *dbObj) GetBalance(addrSlice goja.Value) goja.Value { 641 a, err := do.fromBuf(do.vm, addrSlice, false) 642 if err != nil { 643 do.vm.Interrupt(err) 644 return nil 645 } 646 addr := common.BytesToAddress(a) 647 value := do.db.GetBalance(addr) 648 res, err := do.toBig(do.vm, value.String()) 649 if err != nil { 650 do.vm.Interrupt(err) 651 return nil 652 } 653 return res 654 } 655 656 func (do *dbObj) GetNonce(addrSlice goja.Value) uint64 { 657 a, err := do.fromBuf(do.vm, addrSlice, false) 658 if err != nil { 659 do.vm.Interrupt(err) 660 return 0 661 } 662 addr := common.BytesToAddress(a) 663 return do.db.GetNonce(addr) 664 } 665 666 func (do *dbObj) GetCode(addrSlice goja.Value) goja.Value { 667 a, err := do.fromBuf(do.vm, addrSlice, false) 668 if err != nil { 669 do.vm.Interrupt(err) 670 return nil 671 } 672 addr := common.BytesToAddress(a) 673 code := do.db.GetCode(addr) 674 res, err := do.toBuf(do.vm, code) 675 if err != nil { 676 do.vm.Interrupt(err) 677 return nil 678 } 679 return res 680 } 681 682 func (do *dbObj) GetState(addrSlice goja.Value, hashSlice goja.Value) goja.Value { 683 a, err := do.fromBuf(do.vm, addrSlice, false) 684 if err != nil { 685 do.vm.Interrupt(err) 686 return nil 687 } 688 addr := common.BytesToAddress(a) 689 h, err := do.fromBuf(do.vm, hashSlice, false) 690 if err != nil { 691 do.vm.Interrupt(err) 692 return nil 693 } 694 hash := common.BytesToHash(h) 695 state := do.db.GetState(addr, hash).Bytes() 696 res, err := do.toBuf(do.vm, state) 697 if err != nil { 698 do.vm.Interrupt(err) 699 return nil 700 } 701 return res 702 } 703 704 func (do *dbObj) Exists(addrSlice goja.Value) bool { 705 a, err := do.fromBuf(do.vm, addrSlice, false) 706 if err != nil { 707 do.vm.Interrupt(err) 708 return false 709 } 710 addr := common.BytesToAddress(a) 711 return do.db.Exist(addr) 712 } 713 714 func (do *dbObj) setupObject() *goja.Object { 715 o := do.vm.NewObject() 716 o.Set("getBalance", do.vm.ToValue(do.GetBalance)) 717 o.Set("getNonce", do.vm.ToValue(do.GetNonce)) 718 o.Set("getCode", do.vm.ToValue(do.GetCode)) 719 o.Set("getState", do.vm.ToValue(do.GetState)) 720 o.Set("exists", do.vm.ToValue(do.Exists)) 721 return o 722 } 723 724 type contractObj struct { 725 contract *vm.Contract 726 vm *goja.Runtime 727 toBig toBigFn 728 toBuf toBufFn 729 } 730 731 func (co *contractObj) GetCaller() goja.Value { 732 caller := co.contract.Caller().Bytes() 733 res, err := co.toBuf(co.vm, caller) 734 if err != nil { 735 co.vm.Interrupt(err) 736 return nil 737 } 738 return res 739 } 740 741 func (co *contractObj) GetAddress() goja.Value { 742 addr := co.contract.Address().Bytes() 743 res, err := co.toBuf(co.vm, addr) 744 if err != nil { 745 co.vm.Interrupt(err) 746 return nil 747 } 748 return res 749 } 750 751 func (co *contractObj) GetValue() goja.Value { 752 value := co.contract.Value() 753 res, err := co.toBig(co.vm, value.String()) 754 if err != nil { 755 co.vm.Interrupt(err) 756 return nil 757 } 758 return res 759 } 760 761 func (co *contractObj) GetInput() goja.Value { 762 input := common.CopyBytes(co.contract.Input) 763 res, err := co.toBuf(co.vm, input) 764 if err != nil { 765 co.vm.Interrupt(err) 766 return nil 767 } 768 return res 769 } 770 771 func (c *contractObj) setupObject() *goja.Object { 772 o := c.vm.NewObject() 773 o.Set("getCaller", c.vm.ToValue(c.GetCaller)) 774 o.Set("getAddress", c.vm.ToValue(c.GetAddress)) 775 o.Set("getValue", c.vm.ToValue(c.GetValue)) 776 o.Set("getInput", c.vm.ToValue(c.GetInput)) 777 return o 778 } 779 780 type callframe struct { 781 vm *goja.Runtime 782 toBig toBigFn 783 toBuf toBufFn 784 785 typ string 786 from common.Address 787 to common.Address 788 input []byte 789 gas uint 790 value *big.Int 791 } 792 793 func (f *callframe) GetType() string { 794 return f.typ 795 } 796 797 func (f *callframe) GetFrom() goja.Value { 798 from := f.from.Bytes() 799 res, err := f.toBuf(f.vm, from) 800 if err != nil { 801 f.vm.Interrupt(err) 802 return nil 803 } 804 return res 805 } 806 807 func (f *callframe) GetTo() goja.Value { 808 to := f.to.Bytes() 809 res, err := f.toBuf(f.vm, to) 810 if err != nil { 811 f.vm.Interrupt(err) 812 return nil 813 } 814 return res 815 } 816 817 func (f *callframe) GetInput() goja.Value { 818 input := f.input 819 res, err := f.toBuf(f.vm, input) 820 if err != nil { 821 f.vm.Interrupt(err) 822 return nil 823 } 824 return res 825 } 826 827 func (f *callframe) GetGas() uint { 828 return f.gas 829 } 830 831 func (f *callframe) GetValue() goja.Value { 832 if f.value == nil { 833 return goja.Undefined() 834 } 835 res, err := f.toBig(f.vm, f.value.String()) 836 if err != nil { 837 f.vm.Interrupt(err) 838 return nil 839 } 840 return res 841 } 842 843 func (f *callframe) setupObject() *goja.Object { 844 o := f.vm.NewObject() 845 o.Set("getType", f.vm.ToValue(f.GetType)) 846 o.Set("getFrom", f.vm.ToValue(f.GetFrom)) 847 o.Set("getTo", f.vm.ToValue(f.GetTo)) 848 o.Set("getInput", f.vm.ToValue(f.GetInput)) 849 o.Set("getGas", f.vm.ToValue(f.GetGas)) 850 o.Set("getValue", f.vm.ToValue(f.GetValue)) 851 return o 852 } 853 854 type callframeResult struct { 855 vm *goja.Runtime 856 toBuf toBufFn 857 858 gasUsed uint 859 output []byte 860 err error 861 } 862 863 func (r *callframeResult) GetGasUsed() uint { 864 return r.gasUsed 865 } 866 867 func (r *callframeResult) GetOutput() goja.Value { 868 res, err := r.toBuf(r.vm, r.output) 869 if err != nil { 870 r.vm.Interrupt(err) 871 return nil 872 } 873 return res 874 } 875 876 func (r *callframeResult) GetError() goja.Value { 877 if r.err != nil { 878 return r.vm.ToValue(r.err.Error()) 879 } 880 return goja.Undefined() 881 } 882 883 func (r *callframeResult) setupObject() *goja.Object { 884 o := r.vm.NewObject() 885 o.Set("getGasUsed", r.vm.ToValue(r.GetGasUsed)) 886 o.Set("getOutput", r.vm.ToValue(r.GetOutput)) 887 o.Set("getError", r.vm.ToValue(r.GetError)) 888 return o 889 } 890 891 type steplog struct { 892 vm *goja.Runtime 893 894 op *opObj 895 memory *memoryObj 896 stack *stackObj 897 contract *contractObj 898 899 pc uint 900 gas uint 901 cost uint 902 depth uint 903 refund uint 904 err error 905 } 906 907 func (l *steplog) GetPC() uint { 908 return l.pc 909 } 910 911 func (l *steplog) GetGas() uint { 912 return l.gas 913 } 914 915 func (l *steplog) GetCost() uint { 916 return l.cost 917 } 918 919 func (l *steplog) GetDepth() uint { 920 return l.depth 921 } 922 923 func (l *steplog) GetRefund() uint { 924 return l.refund 925 } 926 927 func (l *steplog) GetError() goja.Value { 928 if l.err != nil { 929 return l.vm.ToValue(l.err.Error()) 930 } 931 return goja.Undefined() 932 } 933 934 func (l *steplog) setupObject() *goja.Object { 935 o := l.vm.NewObject() 936 // Setup basic fields. 937 o.Set("getPC", l.vm.ToValue(l.GetPC)) 938 o.Set("getGas", l.vm.ToValue(l.GetGas)) 939 o.Set("getCost", l.vm.ToValue(l.GetCost)) 940 o.Set("getDepth", l.vm.ToValue(l.GetDepth)) 941 o.Set("getRefund", l.vm.ToValue(l.GetRefund)) 942 o.Set("getError", l.vm.ToValue(l.GetError)) 943 // Setup nested objects. 944 o.Set("op", l.op.setupObject()) 945 o.Set("stack", l.stack.setupObject()) 946 o.Set("memory", l.memory.setupObject()) 947 o.Set("contract", l.contract.setupObject()) 948 return o 949 }