eth/tracers/js: fix type inconsistencies (#28488)

This change fixes two type-inconsistencies in the JS tracer:

- In most places we return byte arrays as a `Uint8Array` to the tracer. However it seems we missed doing the conversion for `ctx` fields which are passed to the tracer during `result`. They are passed as simple arrays. I think Uint8Arrays are more suitable and we should change this inconsistency. Note: this will be a breaking-change. But I believe the effect is small. If we look at our tracers we see that these fields (`ctx.from`, `ctx.to`, etc.) are used in 2 ways. Passed to `toHex` which takes both array or buffer. Or the length was measured which is the same for both types.
- The `slice` taking in `int, int` params versus `memory.slice` taking `int64, int64` params. I suggest changing `slice` types to `int64`. This should have no effect almost in any case.
This commit is contained in:
Sina Mahmoodi 2023-11-28 17:30:35 +03:30 committed by GitHub
parent 248dc50ee8
commit bbc5db8405
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -142,19 +142,29 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer
vm: vm, vm: vm,
ctx: make(map[string]goja.Value), ctx: make(map[string]goja.Value),
} }
t.setTypeConverters()
t.setBuiltinFunctions()
if ctx == nil { if ctx == nil {
ctx = new(tracers.Context) ctx = new(tracers.Context)
} }
if ctx.BlockHash != (common.Hash{}) { if ctx.BlockHash != (common.Hash{}) {
t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes()) blockHash, err := t.toBuf(vm, ctx.BlockHash.Bytes())
if err != nil {
return nil, err
}
t.ctx["blockHash"] = blockHash
if ctx.TxHash != (common.Hash{}) { if ctx.TxHash != (common.Hash{}) {
t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex) t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex)
t.ctx["txHash"] = vm.ToValue(ctx.TxHash.Bytes()) txHash, err := t.toBuf(vm, ctx.TxHash.Bytes())
if err != nil {
return nil, err
}
t.ctx["txHash"] = txHash
} }
} }
t.setTypeConverters()
t.setBuiltinFunctions()
ret, err := vm.RunString("(" + code + ")") ret, err := vm.RunString("(" + code + ")")
if err != nil { if err != nil {
return nil, err return nil, err
@ -224,6 +234,10 @@ func (t *jsTracer) CaptureTxEnd(restGas uint64) {
// CaptureStart implements the Tracer interface to initialize the tracing operation. // CaptureStart implements the Tracer interface to initialize the tracing operation.
func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
cancel := func(err error) {
t.err = err
t.env.Cancel()
}
t.env = env t.env = env
db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf}
t.dbValue = db.setupObject() t.dbValue = db.setupObject()
@ -232,19 +246,34 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr
} else { } else {
t.ctx["type"] = t.vm.ToValue("CALL") t.ctx["type"] = t.vm.ToValue("CALL")
} }
t.ctx["from"] = t.vm.ToValue(from.Bytes()) fromVal, err := t.toBuf(t.vm, from.Bytes())
t.ctx["to"] = t.vm.ToValue(to.Bytes()) if err != nil {
t.ctx["input"] = t.vm.ToValue(input) cancel(err)
return
}
t.ctx["from"] = fromVal
toVal, err := t.toBuf(t.vm, to.Bytes())
if err != nil {
cancel(err)
return
}
t.ctx["to"] = toVal
inputVal, err := t.toBuf(t.vm, input)
if err != nil {
cancel(err)
return
}
t.ctx["input"] = inputVal
t.ctx["gas"] = t.vm.ToValue(t.gasLimit) t.ctx["gas"] = t.vm.ToValue(t.gasLimit)
gasPriceBig, err := t.toBig(t.vm, env.TxContext.GasPrice.String()) gasPriceBig, err := t.toBig(t.vm, env.TxContext.GasPrice.String())
if err != nil { if err != nil {
t.err = err cancel(err)
return return
} }
t.ctx["gasPrice"] = gasPriceBig t.ctx["gasPrice"] = gasPriceBig
valueBig, err := t.toBig(t.vm, value.String()) valueBig, err := t.toBig(t.vm, value.String())
if err != nil { if err != nil {
t.err = err cancel(err)
return return
} }
t.ctx["value"] = valueBig t.ctx["value"] = valueBig
@ -293,10 +322,15 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
// CaptureEnd is called after the call finishes to finalize the tracing. // CaptureEnd is called after the call finishes to finalize the tracing.
func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
t.ctx["output"] = t.vm.ToValue(output)
if err != nil { if err != nil {
t.ctx["error"] = t.vm.ToValue(err.Error()) t.ctx["error"] = t.vm.ToValue(err.Error())
} }
outputVal, err := t.toBuf(t.vm, output)
if err != nil {
t.err = err
return
}
t.ctx["output"] = outputVal
} }
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
@ -465,13 +499,13 @@ func (t *jsTracer) setBuiltinFunctions() {
} }
return false return false
}) })
vm.Set("slice", func(slice goja.Value, start, end int) goja.Value { vm.Set("slice", func(slice goja.Value, start, end int64) goja.Value {
b, err := t.fromBuf(vm, slice, false) b, err := t.fromBuf(vm, slice, false)
if err != nil { if err != nil {
vm.Interrupt(err) vm.Interrupt(err)
return nil return nil
} }
if start < 0 || start > end || end > len(b) { if start < 0 || start > end || end > int64(len(b)) {
vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start)) vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start))
return nil return nil
} }