mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-03 01:27:38 +00:00
tracers: replace duktape with goja (#4113)
Reasons: * duktape is not maintained * on macOS it produces a warning: unused function '_duk_debugger_attach' (this slows down incremental builds and pollutes the test logs) Why goja? Geth has migrated some parts to goja (console and clef signer tool), although not migrated tracers yet. * fix isPrecompiled() native function * recursion limit test is obsolete
This commit is contained in:
parent
15ddd32e75
commit
65966f765a
238
eth/tracers/jsvm.go
Normal file
238
eth/tracers/jsvm.go
Normal file
@ -0,0 +1,238 @@
|
||||
package tracers
|
||||
|
||||
import (
|
||||
"github.com/dop251/goja"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type JSVM struct {
|
||||
vm *goja.Runtime
|
||||
stack []goja.Value
|
||||
}
|
||||
|
||||
func JSVMNew() *JSVM {
|
||||
return &JSVM{
|
||||
vm: goja.New(),
|
||||
stack: make([]goja.Value, 0, 100),
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *JSVM) Pop() {
|
||||
vm.stack = vm.stack[:len(vm.stack)-1]
|
||||
}
|
||||
|
||||
func (vm *JSVM) Swap(index1 int, index2 int) {
|
||||
t := vm.stack[len(vm.stack)+index1]
|
||||
vm.stack[len(vm.stack)+index1] = vm.stack[len(vm.stack)+index2]
|
||||
vm.stack[len(vm.stack)+index2] = t
|
||||
}
|
||||
|
||||
func (vm *JSVM) pushAny(val interface{}) {
|
||||
vm.stack = append(vm.stack, vm.vm.ToValue(val))
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushBoolean(val bool) {
|
||||
vm.pushAny(val)
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushInt(val int) {
|
||||
vm.pushAny(val)
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushUint(val uint) {
|
||||
vm.pushAny(val)
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushString(val string) string {
|
||||
vm.pushAny(val)
|
||||
return val
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushFixedBuffer(size int) unsafe.Pointer {
|
||||
buf := make([]byte, size)
|
||||
vm.pushAny(buf)
|
||||
if size == 0 {
|
||||
return unsafe.Pointer(nil)
|
||||
}
|
||||
return unsafe.Pointer(&buf[0])
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushGoFunction(fn0 func(*JSVM) int) {
|
||||
fn := func(this goja.Value, args ...goja.Value) (goja.Value, error) {
|
||||
vm.stack = append(vm.stack, this)
|
||||
vm.stack = append(vm.stack, args...)
|
||||
_ = fn0(vm)
|
||||
result := vm.stack[len(vm.stack)-1]
|
||||
vm.Pop()
|
||||
return result, nil
|
||||
}
|
||||
vm.pushAny(fn)
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushObject() int {
|
||||
vm.stack = append(vm.stack, vm.vm.ToValue(vm.vm.NewObject()))
|
||||
return len(vm.stack) - 1
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushUndefined() {
|
||||
vm.stack = append(vm.stack, goja.Undefined())
|
||||
}
|
||||
|
||||
func (vm *JSVM) GetInt(index int) int {
|
||||
return int(vm.stack[len(vm.stack)+index].Export().(int64))
|
||||
}
|
||||
|
||||
func (vm *JSVM) GetString(index int) string {
|
||||
return vm.stack[len(vm.stack)+index].Export().(string)
|
||||
}
|
||||
|
||||
func (vm *JSVM) GetBuffer(index int) (rawPtr unsafe.Pointer, outSize uint) {
|
||||
v := vm.stack[len(vm.stack)+index]
|
||||
expValue := v.Export()
|
||||
|
||||
// toAddress() and some others are passed a string, but try to parse it with GetBuffer
|
||||
if _, ok := expValue.(string); ok {
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
buf := expValue.([]byte)
|
||||
if len(buf) == 0 {
|
||||
return unsafe.Pointer(nil), 0
|
||||
}
|
||||
return unsafe.Pointer(&buf[0]), uint(len(buf))
|
||||
}
|
||||
|
||||
func (vm *JSVM) GetPropString(objIndex int, key string) bool {
|
||||
obj := vm.stack[objIndex].ToObject(vm.vm)
|
||||
v := obj.Get(key)
|
||||
vm.stack = append(vm.stack, v)
|
||||
return !goja.IsUndefined(v)
|
||||
}
|
||||
|
||||
func (vm *JSVM) PutPropString(objIndex int, key string) {
|
||||
v := vm.stack[len(vm.stack)-1]
|
||||
vm.Pop()
|
||||
|
||||
obj := vm.stack[objIndex].ToObject(vm.vm)
|
||||
err := obj.Set(key, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *JSVM) GetGlobalString(key string) bool {
|
||||
v := vm.vm.GlobalObject().Get(key)
|
||||
vm.stack = append(vm.stack, v)
|
||||
return !goja.IsUndefined(v)
|
||||
}
|
||||
|
||||
func (vm *JSVM) PutGlobalString(key string) {
|
||||
v := vm.stack[len(vm.stack)-1]
|
||||
vm.Pop()
|
||||
|
||||
obj := vm.vm.GlobalObject()
|
||||
err := obj.Set(key, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushGlobalGoFunction(name string, fn0 func(*JSVM) int) {
|
||||
fn := func(this goja.Value, args ...goja.Value) (goja.Value, error) {
|
||||
vm.stack = append(vm.stack, this)
|
||||
vm.stack = append(vm.stack, args...)
|
||||
_ = fn0(vm)
|
||||
result := vm.stack[len(vm.stack)-1]
|
||||
vm.Pop()
|
||||
return result, nil
|
||||
}
|
||||
err := vm.vm.GlobalObject().Set(name, goja.Callable(fn))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *JSVM) PushGlobalObject() int {
|
||||
vm.stack = append(vm.stack, vm.vm.GlobalObject())
|
||||
return len(vm.stack) - 1
|
||||
}
|
||||
|
||||
func (vm *JSVM) Call(numArgs int) {
|
||||
if vm.Pcall(numArgs) != 0 {
|
||||
err := vm.stack[len(vm.stack)-1]
|
||||
vm.Pop()
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *JSVM) Pcall(numArgs int) int {
|
||||
fnValue := vm.stack[len(vm.stack)-numArgs-1]
|
||||
args := vm.stack[len(vm.stack)-numArgs:]
|
||||
vm.stack = vm.stack[:len(vm.stack)-numArgs-1]
|
||||
|
||||
fn, ok := goja.AssertFunction(fnValue)
|
||||
if !ok {
|
||||
panic("AssertFunction")
|
||||
}
|
||||
|
||||
v, err := fn(goja.Undefined(), args...)
|
||||
if err != nil {
|
||||
vm.stack = append(vm.stack, vm.vm.ToValue(err))
|
||||
return 1
|
||||
} else {
|
||||
vm.stack = append(vm.stack, v)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *JSVM) PcallProp(objIndex int, numArgs int) int {
|
||||
key := vm.stack[len(vm.stack)-numArgs-1].String()
|
||||
args := vm.stack[len(vm.stack)-numArgs:]
|
||||
vm.stack = vm.stack[:len(vm.stack)-numArgs-1]
|
||||
|
||||
obj := vm.stack[objIndex].ToObject(vm.vm)
|
||||
fnValue := obj.Get(key)
|
||||
|
||||
fn, ok := goja.AssertFunction(fnValue)
|
||||
if !ok {
|
||||
panic("AssertFunction")
|
||||
}
|
||||
|
||||
v, err := fn(obj, args...)
|
||||
if err != nil {
|
||||
vm.stack = append(vm.stack, vm.vm.ToValue(err))
|
||||
return 1
|
||||
} else {
|
||||
vm.stack = append(vm.stack, v)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *JSVM) SafeToString(index int) string {
|
||||
v := vm.stack[len(vm.stack)+index]
|
||||
return v.ToString().String()
|
||||
}
|
||||
|
||||
func (vm *JSVM) Eval() {
|
||||
src := vm.GetString(-1)
|
||||
vm.Pop()
|
||||
vm.EvalString(src)
|
||||
}
|
||||
|
||||
func (vm *JSVM) EvalString(src string) {
|
||||
v, err := vm.vm.RunString(src)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
vm.stack = append(vm.stack, v)
|
||||
}
|
||||
|
||||
func (vm *JSVM) PevalString(src string) error {
|
||||
v, err := vm.vm.RunString(src)
|
||||
if err != nil {
|
||||
vm.stack = append(vm.stack, vm.vm.ToValue(err))
|
||||
} else {
|
||||
vm.stack = append(vm.stack, v)
|
||||
}
|
||||
return err
|
||||
}
|
177
eth/tracers/jsvm_test.go
Normal file
177
eth/tracers/jsvm_test.go
Normal file
@ -0,0 +1,177 @@
|
||||
package tracers
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSwap(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushInt(1)
|
||||
vm.PushInt(2)
|
||||
vm.Swap(-1, -2)
|
||||
assert.Equal(t, 1, vm.GetInt(-1))
|
||||
vm.Pop()
|
||||
assert.Equal(t, 2, vm.GetInt(-1))
|
||||
}
|
||||
|
||||
func TestPushAndGetInt(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushInt(123)
|
||||
assert.Equal(t, 123, vm.GetInt(-1))
|
||||
}
|
||||
|
||||
func TestPushAndGetString(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushString("hello")
|
||||
assert.Equal(t, "hello", vm.GetString(-1))
|
||||
}
|
||||
|
||||
func TestPushAndGetBuffer(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushFixedBuffer(1)
|
||||
p, s := vm.GetBuffer(-1)
|
||||
assert.Equal(t, uint(1), s)
|
||||
assert.Equal(t, byte(0), *(*byte)(p))
|
||||
}
|
||||
|
||||
func TestPutAndGetPropString(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
objIndex := vm.PushObject()
|
||||
vm.PushString("hello")
|
||||
vm.PutPropString(objIndex, "x")
|
||||
exists := vm.GetPropString(objIndex, "x")
|
||||
assert.Equal(t, true, exists)
|
||||
x := vm.GetString(-1)
|
||||
assert.Equal(t, "hello", x)
|
||||
}
|
||||
|
||||
func TestGetGlobalString(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.EvalString("x = 'hello'")
|
||||
exists := vm.GetGlobalString("x")
|
||||
assert.Equal(t, true, exists)
|
||||
x := vm.GetString(-1)
|
||||
assert.Equal(t, "hello", x)
|
||||
}
|
||||
|
||||
func TestPutGlobalString(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushString("hello")
|
||||
vm.PutGlobalString("x")
|
||||
exists := vm.GetGlobalString("x")
|
||||
assert.Equal(t, true, exists)
|
||||
x := vm.GetString(-1)
|
||||
assert.Equal(t, "hello", x)
|
||||
}
|
||||
|
||||
func TestCall0(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
ctx.PushInt(123)
|
||||
return 1
|
||||
})
|
||||
vm.Call(0)
|
||||
x := vm.GetInt(-1)
|
||||
assert.Equal(t, 123, x)
|
||||
}
|
||||
|
||||
func TestCall1(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
arg := ctx.GetInt(-1)
|
||||
ctx.Pop()
|
||||
ctx.PushInt(arg + 120)
|
||||
return 1
|
||||
})
|
||||
vm.PushInt(3)
|
||||
vm.Call(1)
|
||||
x := vm.GetInt(-1)
|
||||
assert.Equal(t, 123, x)
|
||||
}
|
||||
|
||||
func TestCallPropWithGoFunction(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushGlobalGoFunction("f", func(ctx *JSVM) int {
|
||||
ctx.PushInt(123)
|
||||
return 1
|
||||
})
|
||||
objIndex := vm.PushGlobalObject()
|
||||
vm.PushString("f")
|
||||
errCode := vm.PcallProp(objIndex, 0)
|
||||
assert.Equal(t, 0, errCode)
|
||||
x := vm.GetInt(-1)
|
||||
assert.Equal(t, 123, x)
|
||||
}
|
||||
|
||||
func TestCallProp0(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.EvalString("function f() { return 'hello' }")
|
||||
objIndex := vm.PushGlobalObject()
|
||||
vm.PushString("f")
|
||||
errCode := vm.PcallProp(objIndex, 0)
|
||||
assert.Equal(t, 0, errCode)
|
||||
x := vm.GetString(-1)
|
||||
assert.Equal(t, "hello", x)
|
||||
}
|
||||
|
||||
func TestCallProp1(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.EvalString("function f(s) { return s + '123' }")
|
||||
objIndex := vm.PushGlobalObject()
|
||||
vm.PushString("f")
|
||||
vm.PushString("hello")
|
||||
errCode := vm.PcallProp(objIndex, 1)
|
||||
assert.Equal(t, 0, errCode)
|
||||
x := vm.GetString(-1)
|
||||
assert.Equal(t, "hello123", x)
|
||||
}
|
||||
|
||||
func TestCallPropWithObj(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.EvalString("function f(opts) { return opts.name + '123' }")
|
||||
globalIndex := vm.PushGlobalObject()
|
||||
vm.PushString("f")
|
||||
optsIndex := vm.PushObject()
|
||||
vm.PushString("hello")
|
||||
vm.PutPropString(optsIndex, "name")
|
||||
errCode := vm.PcallProp(globalIndex, 1)
|
||||
assert.Equal(t, 0, errCode)
|
||||
x := vm.GetString(-1)
|
||||
assert.Equal(t, "hello123", x)
|
||||
}
|
||||
|
||||
func TestCallPropWithJSObj(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.EvalString(`
|
||||
function Options() { }
|
||||
Options.prototype.name = function () { return 'hello' }
|
||||
function makeOptions() { return new Options() }
|
||||
function f(opts) { return opts.name() + '123' }
|
||||
`)
|
||||
globalIndex := vm.PushGlobalObject()
|
||||
vm.PushString("f")
|
||||
|
||||
vm.PushString("makeOptions")
|
||||
errCode := vm.PcallProp(globalIndex, 0)
|
||||
assert.Equal(t, 0, errCode)
|
||||
|
||||
errCode = vm.PcallProp(globalIndex, 1)
|
||||
assert.Equal(t, 0, errCode)
|
||||
x := vm.GetString(-1)
|
||||
assert.Equal(t, "hello123", x)
|
||||
}
|
||||
|
||||
func TestSafeToString(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushInt(5)
|
||||
assert.Equal(t, "5", vm.SafeToString(-1))
|
||||
}
|
||||
|
||||
func TestEval(t *testing.T) {
|
||||
vm := JSVMNew()
|
||||
vm.PushString("2 + 3")
|
||||
vm.Eval()
|
||||
x := vm.GetInt(-1)
|
||||
assert.Equal(t, 5, x)
|
||||
}
|
@ -27,7 +27,6 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"gopkg.in/olebedev/go-duktape.v3"
|
||||
|
||||
"github.com/ledgerwatch/erigon/common"
|
||||
"github.com/ledgerwatch/erigon/common/hexutil"
|
||||
@ -57,14 +56,14 @@ func makeSlice(ptr unsafe.Pointer, size uint) []byte {
|
||||
}
|
||||
|
||||
// popSlice pops a buffer off the JavaScript stack and returns it as a slice.
|
||||
func popSlice(ctx *duktape.Context) []byte {
|
||||
func popSlice(ctx *JSVM) []byte {
|
||||
blob := common.CopyBytes(makeSlice(ctx.GetBuffer(-1)))
|
||||
ctx.Pop()
|
||||
return blob
|
||||
}
|
||||
|
||||
// pushBigInt create a JavaScript BigInteger in the VM.
|
||||
func pushBigInt(n *big.Int, ctx *duktape.Context) {
|
||||
func pushBigInt(n *big.Int, ctx *JSVM) {
|
||||
ctx.GetGlobalString("bigInt")
|
||||
ctx.PushString(n.String())
|
||||
ctx.Call(1)
|
||||
@ -77,16 +76,16 @@ type opWrapper struct {
|
||||
|
||||
// pushObject assembles a JSVM object wrapping a swappable opcode and pushes it
|
||||
// onto the VM stack.
|
||||
func (ow *opWrapper) pushObject(vm *duktape.Context) {
|
||||
func (ow *opWrapper) pushObject(vm *JSVM) {
|
||||
obj := vm.PushObject()
|
||||
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(int(ow.op)); return 1 })
|
||||
vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushInt(int(ow.op)); return 1 })
|
||||
vm.PutPropString(obj, "toNumber")
|
||||
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushString(ow.op.String()); return 1 })
|
||||
vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushString(ow.op.String()); return 1 })
|
||||
vm.PutPropString(obj, "toString")
|
||||
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushBoolean(ow.op.IsPush()); return 1 })
|
||||
vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushBoolean(ow.op.IsPush()); return 1 })
|
||||
vm.PutPropString(obj, "isPush")
|
||||
}
|
||||
|
||||
@ -128,13 +127,14 @@ func (mw *memoryWrapper) getUint(addr int64) *big.Int {
|
||||
|
||||
// pushObject assembles a JSVM object wrapping a swappable memory and pushes it
|
||||
// onto the VM stack.
|
||||
func (mw *memoryWrapper) pushObject(vm *duktape.Context) {
|
||||
func (mw *memoryWrapper) pushObject(vm *JSVM) {
|
||||
obj := vm.PushObject()
|
||||
|
||||
// Generate the `slice` method which takes two ints and returns a buffer
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
blob := mw.slice(int64(ctx.GetInt(-2)), int64(ctx.GetInt(-1)))
|
||||
ctx.Pop2()
|
||||
ctx.Pop()
|
||||
ctx.Pop()
|
||||
|
||||
ptr := ctx.PushFixedBuffer(len(blob))
|
||||
copy(makeSlice(ptr, uint(len(blob))), blob)
|
||||
@ -143,7 +143,7 @@ func (mw *memoryWrapper) pushObject(vm *duktape.Context) {
|
||||
vm.PutPropString(obj, "slice")
|
||||
|
||||
// Generate the `getUint` method which takes an int and returns a bigint
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
offset := int64(ctx.GetInt(-1))
|
||||
ctx.Pop()
|
||||
|
||||
@ -171,14 +171,14 @@ func (sw *stackWrapper) peek(idx int) *big.Int {
|
||||
|
||||
// pushObject assembles a JSVM object wrapping a swappable stack and pushes it
|
||||
// onto the VM stack.
|
||||
func (sw *stackWrapper) pushObject(vm *duktape.Context) {
|
||||
func (sw *stackWrapper) pushObject(vm *JSVM) {
|
||||
obj := vm.PushObject()
|
||||
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(sw.stack.Len()); return 1 })
|
||||
vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushInt(sw.stack.Len()); return 1 })
|
||||
vm.PutPropString(obj, "length")
|
||||
|
||||
// Generate the `peek` method which takes an int and returns a bigint
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
offset := ctx.GetInt(-1)
|
||||
ctx.Pop()
|
||||
|
||||
@ -195,25 +195,25 @@ type dbWrapper struct {
|
||||
|
||||
// pushObject assembles a JSVM object wrapping a swappable database and pushes it
|
||||
// onto the VM stack.
|
||||
func (dw *dbWrapper) pushObject(vm *duktape.Context) {
|
||||
func (dw *dbWrapper) pushObject(vm *JSVM) {
|
||||
obj := vm.PushObject()
|
||||
|
||||
// Push the wrapper for statedb.GetBalance
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
pushBigInt(dw.db.GetBalance(common.BytesToAddress(popSlice(ctx))).ToBig(), ctx)
|
||||
return 1
|
||||
})
|
||||
vm.PutPropString(obj, "getBalance")
|
||||
|
||||
// Push the wrapper for statedb.GetNonce
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
ctx.PushInt(int(dw.db.GetNonce(common.BytesToAddress(popSlice(ctx)))))
|
||||
return 1
|
||||
})
|
||||
vm.PutPropString(obj, "getNonce")
|
||||
|
||||
// Push the wrapper for statedb.GetCode
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx)))
|
||||
|
||||
ptr := ctx.PushFixedBuffer(len(code))
|
||||
@ -223,7 +223,7 @@ func (dw *dbWrapper) pushObject(vm *duktape.Context) {
|
||||
vm.PutPropString(obj, "getCode")
|
||||
|
||||
// Push the wrapper for statedb.GetState
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
hash := popSlice(ctx)
|
||||
addr := popSlice(ctx)
|
||||
|
||||
@ -238,7 +238,7 @@ func (dw *dbWrapper) pushObject(vm *duktape.Context) {
|
||||
vm.PutPropString(obj, "getState")
|
||||
|
||||
// Push the wrapper for statedb.Exists
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
ctx.PushBoolean(dw.db.Exist(common.BytesToAddress(popSlice(ctx))))
|
||||
return 1
|
||||
})
|
||||
@ -252,11 +252,11 @@ type contractWrapper struct {
|
||||
|
||||
// pushObject assembles a JSVM object wrapping a swappable contract and pushes it
|
||||
// onto the VM stack.
|
||||
func (cw *contractWrapper) pushObject(vm *duktape.Context) {
|
||||
func (cw *contractWrapper) pushObject(vm *JSVM) {
|
||||
obj := vm.PushObject()
|
||||
|
||||
// Push the wrapper for contract.Caller
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
ptr := ctx.PushFixedBuffer(20)
|
||||
copy(makeSlice(ptr, 20), cw.contract.Caller().Bytes())
|
||||
return 1
|
||||
@ -264,7 +264,7 @@ func (cw *contractWrapper) pushObject(vm *duktape.Context) {
|
||||
vm.PutPropString(obj, "getCaller")
|
||||
|
||||
// Push the wrapper for contract.Address
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
ptr := ctx.PushFixedBuffer(20)
|
||||
copy(makeSlice(ptr, 20), cw.contract.Address().Bytes())
|
||||
return 1
|
||||
@ -272,14 +272,14 @@ func (cw *contractWrapper) pushObject(vm *duktape.Context) {
|
||||
vm.PutPropString(obj, "getAddress")
|
||||
|
||||
// Push the wrapper for contract.Value
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
pushBigInt(cw.contract.Value().ToBig(), ctx)
|
||||
return 1
|
||||
})
|
||||
vm.PutPropString(obj, "getValue")
|
||||
|
||||
// Push the wrapper for contract.Input
|
||||
vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
blob := cw.contract.Input
|
||||
|
||||
ptr := ctx.PushFixedBuffer(len(blob))
|
||||
@ -292,7 +292,7 @@ func (cw *contractWrapper) pushObject(vm *duktape.Context) {
|
||||
// Tracer provides an implementation of Tracer that evaluates a Javascript
|
||||
// function for each VM execution step.
|
||||
type Tracer struct {
|
||||
vm *duktape.Context // Javascript VM instance
|
||||
vm *JSVM // Javascript VM instance
|
||||
|
||||
tracerObject int // Stack index of the tracer JavaScript object
|
||||
stateObject int // Stack index of the global state to pull arguments from
|
||||
@ -336,7 +336,7 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
code = tracer
|
||||
}
|
||||
tracer := &Tracer{
|
||||
vm: duktape.New(),
|
||||
vm: JSVMNew(),
|
||||
ctx: make(map[string]interface{}),
|
||||
opWrapper: new(opWrapper),
|
||||
stackWrapper: new(stackWrapper),
|
||||
@ -359,11 +359,11 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
}
|
||||
|
||||
// Set up builtins for this environment
|
||||
tracer.vm.PushGlobalGoFunction("toHex", func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGlobalGoFunction("toHex", func(ctx *JSVM) int {
|
||||
ctx.PushString(hexutil.Encode(popSlice(ctx)))
|
||||
return 1
|
||||
})
|
||||
tracer.vm.PushGlobalGoFunction("toWord", func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGlobalGoFunction("toWord", func(ctx *JSVM) int {
|
||||
var word common.Hash
|
||||
if ptr, size := ctx.GetBuffer(-1); ptr != nil {
|
||||
word = common.BytesToHash(makeSlice(ptr, size))
|
||||
@ -374,7 +374,7 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
copy(makeSlice(ctx.PushFixedBuffer(32), 32), word[:])
|
||||
return 1
|
||||
})
|
||||
tracer.vm.PushGlobalGoFunction("toAddress", func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGlobalGoFunction("toAddress", func(ctx *JSVM) int {
|
||||
var addr common.Address
|
||||
if ptr, size := ctx.GetBuffer(-1); ptr != nil {
|
||||
addr = common.BytesToAddress(makeSlice(ptr, size))
|
||||
@ -385,7 +385,7 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
copy(makeSlice(ctx.PushFixedBuffer(20), 20), addr[:])
|
||||
return 1
|
||||
})
|
||||
tracer.vm.PushGlobalGoFunction("toContract", func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGlobalGoFunction("toContract", func(ctx *JSVM) int {
|
||||
var from common.Address
|
||||
if ptr, size := ctx.GetBuffer(-2); ptr != nil {
|
||||
from = common.BytesToAddress(makeSlice(ptr, size))
|
||||
@ -393,13 +393,14 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
from = common.HexToAddress(ctx.GetString(-2))
|
||||
}
|
||||
nonce := uint64(ctx.GetInt(-1))
|
||||
ctx.Pop2()
|
||||
ctx.Pop()
|
||||
ctx.Pop()
|
||||
|
||||
contract := crypto.CreateAddress(from, nonce)
|
||||
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
|
||||
return 1
|
||||
})
|
||||
tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *JSVM) int {
|
||||
var from common.Address
|
||||
if ptr, size := ctx.GetBuffer(-3); ptr != nil {
|
||||
from = common.BytesToAddress(makeSlice(ptr, size))
|
||||
@ -416,12 +417,14 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
code = common.FromHex(ctx.GetString(-1))
|
||||
}
|
||||
codeHash := crypto.Keccak256(code)
|
||||
ctx.Pop3()
|
||||
ctx.Pop()
|
||||
ctx.Pop()
|
||||
ctx.Pop()
|
||||
contract := crypto.CreateAddress2(from, salt, codeHash)
|
||||
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
|
||||
return 1
|
||||
})
|
||||
tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *JSVM) int {
|
||||
addr := common.BytesToAddress(popSlice(ctx))
|
||||
for _, p := range tracer.activePrecompiles {
|
||||
if p == addr {
|
||||
@ -429,15 +432,19 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
ctx.PushBoolean(false)
|
||||
|
||||
_, ok := vm.PrecompiledContractsIstanbul[common.BytesToAddress(popSlice(ctx))]
|
||||
ctx.PushBoolean(ok)
|
||||
if _, ok := vm.PrecompiledContractsIstanbul[addr]; ok {
|
||||
ctx.PushBoolean(true)
|
||||
return 1
|
||||
}
|
||||
|
||||
ctx.PushBoolean(false)
|
||||
return 1
|
||||
})
|
||||
tracer.vm.PushGlobalGoFunction("slice", func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGlobalGoFunction("slice", func(ctx *JSVM) int {
|
||||
start, end := ctx.GetInt(-2), ctx.GetInt(-1)
|
||||
ctx.Pop2()
|
||||
ctx.Pop()
|
||||
ctx.Pop()
|
||||
|
||||
blob := popSlice(ctx)
|
||||
size := end - start
|
||||
@ -495,22 +502,22 @@ func New(code string, ctx *Context) (*Tracer, error) {
|
||||
tracer.contractWrapper.pushObject(tracer.vm)
|
||||
tracer.vm.PutPropString(logObject, "contract")
|
||||
|
||||
tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.pcValue); return 1 })
|
||||
tracer.vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushUint(*tracer.pcValue); return 1 })
|
||||
tracer.vm.PutPropString(logObject, "getPC")
|
||||
|
||||
tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.gasValue); return 1 })
|
||||
tracer.vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushUint(*tracer.gasValue); return 1 })
|
||||
tracer.vm.PutPropString(logObject, "getGas")
|
||||
|
||||
tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.costValue); return 1 })
|
||||
tracer.vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushUint(*tracer.costValue); return 1 })
|
||||
tracer.vm.PutPropString(logObject, "getCost")
|
||||
|
||||
tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.depthValue); return 1 })
|
||||
tracer.vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushUint(*tracer.depthValue); return 1 })
|
||||
tracer.vm.PutPropString(logObject, "getDepth")
|
||||
|
||||
tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.refundValue); return 1 })
|
||||
tracer.vm.PushGoFunction(func(ctx *JSVM) int { ctx.PushUint(*tracer.refundValue); return 1 })
|
||||
tracer.vm.PutPropString(logObject, "getRefund")
|
||||
|
||||
tracer.vm.PushGoFunction(func(ctx *duktape.Context) int {
|
||||
tracer.vm.PushGoFunction(func(ctx *JSVM) int {
|
||||
if tracer.errorValue != nil {
|
||||
ctx.PushString(*tracer.errorValue)
|
||||
} else {
|
||||
@ -713,9 +720,6 @@ func (jst *Tracer) GetResult() (json.RawMessage, error) {
|
||||
if err != nil {
|
||||
jst.err = wrapError("result", err)
|
||||
}
|
||||
// Clean up the JavaScript environment
|
||||
jst.vm.DestroyHeap()
|
||||
jst.vm.Destroy()
|
||||
|
||||
return result, jst.err
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func TestTracer(t *testing.T) {
|
||||
}{
|
||||
{ // tests that we don't panic on bad arguments to memory access
|
||||
code: "{depths: [], step: function(log) { this.depths.push(log.memory.slice(-1,-2)); }, fault: function() {}, result: function() { return this.depths; }}",
|
||||
want: `[{},{},{}]`,
|
||||
want: `[[],[],[]]`,
|
||||
}, { // tests that we don't panic on bad arguments to stack peeks
|
||||
code: "{depths: [], step: function(log) { this.depths.push(log.stack.peek(-1)); }, fault: function() {}, result: function() { return this.depths; }}",
|
||||
want: `["0","0","0"]`,
|
||||
@ -124,9 +124,6 @@ func TestTracer(t *testing.T) {
|
||||
}, { // tests intrinsic gas
|
||||
code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx) { return ctx.gasPrice+'.'+ctx.gasUsed+'.'+ctx.intrinsicGas; }}",
|
||||
want: `"100000.6.21000"`,
|
||||
}, { // tests too deep object / serialization crash
|
||||
code: "{step: function() {}, fault: function() {}, result: function() { var o={}; var x=o; for (var i=0; i<1000; i++){ o.foo={}; o=o.foo; } return x; }}",
|
||||
fail: "RangeError: json encode recursion limit in server-side tracer function 'result'",
|
||||
},
|
||||
} {
|
||||
if have, err := execTracer(tt.code); tt.want != string(have) || tt.fail != err {
|
||||
|
9
go.mod
9
go.mod
@ -16,6 +16,7 @@ require (
|
||||
github.com/consensys/gnark-crypto v0.4.0
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48
|
||||
github.com/edsrzf/mmap-go v1.0.0
|
||||
github.com/emicklei/dot v0.16.0
|
||||
github.com/emirpasic/gods v1.12.0
|
||||
@ -63,8 +64,7 @@ require (
|
||||
google.golang.org/grpc v1.46.0
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b
|
||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||
modernc.org/sqlite v1.17.0
|
||||
pgregory.net/rapid v0.4.7
|
||||
)
|
||||
@ -91,6 +91,7 @@ require (
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/etcd-io/bbolt v1.3.3 // indirect
|
||||
github.com/flanglet/kanzi-go v1.9.1-0.20211212184056-72dda96261ee // indirect
|
||||
@ -98,6 +99,7 @@ require (
|
||||
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
|
||||
github.com/go-kit/kit v0.10.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
@ -107,6 +109,7 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||
@ -115,7 +118,6 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/pion/datachannel v1.5.2 // indirect
|
||||
github.com/pion/dtls/v2 v2.1.2 // indirect
|
||||
github.com/pion/ice/v2 v2.1.20 // indirect
|
||||
@ -141,6 +143,7 @@ require (
|
||||
github.com/prometheus/procfs v0.7.2 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/rs/dnscache v0.0.0-20210201191234-295bba877686 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
|
16
go.sum
16
go.sum
@ -197,7 +197,12 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X
|
||||
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E=
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48 h1:iZOop7pqsg+56twTopWgwCGxdB5SI2yDO8Ti7eTRliQ=
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
||||
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
@ -255,6 +260,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
@ -438,6 +445,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@ -499,8 +507,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
@ -1100,14 +1106,12 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
|
||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
Loading…
Reference in New Issue
Block a user