-
Notifications
You must be signed in to change notification settings - Fork 175
/
fvm.go
100 lines (81 loc) · 3.17 KB
/
fvm.go
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package fvm
import (
"fmt"
"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/interpreter"
"github.com/rs/zerolog"
errors "github.com/onflow/flow-go/fvm/errors"
"github.com/onflow/flow-go/fvm/programs"
"github.com/onflow/flow-go/fvm/state"
"github.com/onflow/flow-go/model/flow"
)
// An Procedure is an operation (or set of operations) that reads or writes ledger state.
type Procedure interface {
Run(vm *VirtualMachine, ctx Context, sth *state.StateHolder, programs *programs.Programs) error
}
func NewInterpreterRuntime() runtime.Runtime {
return runtime.NewInterpreterRuntime(
runtime.WithContractUpdateValidationEnabled(true),
)
}
// A VirtualMachine augments the Cadence runtime with Flow host functionality.
type VirtualMachine struct {
Runtime runtime.Runtime
}
// NewVirtualMachine creates a new virtual machine instance with the provided runtime.
func NewVirtualMachine(rt runtime.Runtime) *VirtualMachine {
return &VirtualMachine{
Runtime: rt,
}
}
// Run runs a procedure against a ledger in the given context.
func (vm *VirtualMachine) Run(ctx Context, proc Procedure, v state.View, programs *programs.Programs) (err error) {
st := state.NewState(v,
state.WithMaxKeySizeAllowed(ctx.MaxStateKeySize),
state.WithMaxValueSizeAllowed(ctx.MaxStateValueSize),
state.WithMaxInteractionSizeAllowed(ctx.MaxStateInteractionSize))
sth := state.NewStateHolder(st)
defer func() {
if r := recover(); r != nil {
// Cadence may fail to encode certain values.
// Return an error for now, which will cause transactions to revert.
//
if encodingErr, ok := r.(interpreter.EncodingUnsupportedValueError); ok {
err = errors.NewEncodingUnsupportedValueError(encodingErr.Value, encodingErr.Path)
return
}
panic(r)
}
}()
err = proc.Run(vm, ctx, sth, programs)
if err != nil {
return err
}
return nil
}
// GetAccount returns an account by address or an error if none exists.
func (vm *VirtualMachine) GetAccount(ctx Context, address flow.Address, v state.View, programs *programs.Programs) (*flow.Account, error) {
st := state.NewState(v,
state.WithMaxKeySizeAllowed(ctx.MaxStateKeySize),
state.WithMaxValueSizeAllowed(ctx.MaxStateValueSize),
state.WithMaxInteractionSizeAllowed(ctx.MaxStateInteractionSize))
sth := state.NewStateHolder(st)
account, err := getAccount(vm, ctx, sth, programs, address)
if err != nil {
return nil, fmt.Errorf("cannot get account: %w", err)
}
return account, nil
}
// invokeMetaTransaction invokes a meta transaction inside the context of an outer transaction.
//
// Errors that occur in a meta transaction are propagated as a single error that can be
// captured by the Cadence runtime and eventually disambiguated by the parent context.
func (vm *VirtualMachine) invokeMetaTransaction(ctx Context, tx *TransactionProcedure, sth *state.StateHolder, programs *programs.Programs) (errors.Error, error) {
invocator := NewTransactionInvocator(zerolog.Nop())
// do not deduct fees or check storage in meta transactions
ctx.TransactionFeesEnabled = false
ctx.LimitAccountStorage = false
err := invocator.Process(vm, &ctx, tx, sth, programs)
txErr, fatalErr := errors.SplitErrorTypes(err)
return txErr, fatalErr
}