aboutsummaryrefslogtreecommitdiff
path: root/cmd/h/run.go
blob: fb55bb7de187bf60f17eee69b9188c51772ca986 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package main

import (
	"errors"
	"time"

	"github.com/perlin-network/life/compiler"
	"github.com/perlin-network/life/exec"
)

type Process struct {
	Output []byte
}

// ResolveGlobal does nothing, currently.
func (p *Process) ResolveGlobal(module, field string) int64 { return 0 }

// ResolveFunc resolves h's ABI and importable function.
func (p *Process) ResolveFunc(module, field string) exec.FunctionImport {
	switch module {
	case "h":
		switch field {
		case "h":
			return func(vm *exec.VirtualMachine) int64 {
				frame := vm.GetCurrentFrame()
				data := frame.Locals[0]
				p.Output = append(p.Output, byte(data))

				return 0
			}

		default:
			panic("impossible state")
		}

	default:
		panic("impossible state")
	}
}

type ExecResult struct {
	Output   string        `json:"out"`
	GasUsed  uint64        `json:"gas"`
	ExecTime time.Duration `json:"exec_duration"`
}

func run(bin []byte) (*ExecResult, error) {
	p := &Process{}

	var cfg exec.VMConfig
	gp := &compiler.SimpleGasPolicy{GasPerInstruction: 1}
	vm, err := exec.NewVirtualMachine(bin, cfg, p, gp)
	if err != nil {
		return nil, err
	}

	mainFunc, ok := vm.GetFunctionExport("h")
	if !ok {
		return nil, errors.New("impossible state: no h function exposed")
	}

	t0 := time.Now()
	_, err = vm.Run(mainFunc)
	if err != nil {
		return nil, err
	}

	return &ExecResult{
		Output:   string(p.Output),
		GasUsed:  vm.Gas,
		ExecTime: time.Since(t0),
	}, nil
}