aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/vm.go
blob: 780320d2b53ac17b40e0b97e38b2102a979648ce (plain) (blame)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package vm

import (
    "math/big"

    "github.com/dexon-foundation/dexon/common"
    "github.com/dexon-foundation/dexon/params"
)

const (
    // EVM enum
    EVM = uint8(iota)

    // SQLVM enum
    SQLVM
)

var (
    // MULTIVM flag
    MULTIVM = true
)

// NUMS represents the number of supported VM type.
const NUMS = 2

// VM Create and Call interface.
type VM interface {
    Create(ContractRef, []byte, uint64, *big.Int,
        *ExecPack) ([]byte, common.Address, uint64, error)
    Create2(ContractRef, []byte, uint64, *big.Int, *big.Int,
        *ExecPack) ([]byte, common.Address, uint64, error)
    Call(ContractRef, common.Address, []byte, uint64, *big.Int,
        *ExecPack) ([]byte, uint64, error)
    CallCode(ContractRef, common.Address, []byte, uint64,
        *big.Int, *ExecPack) ([]byte, uint64, error)
    DelegateCall(ContractRef, common.Address, []byte, uint64,
        *ExecPack) ([]byte, uint64, error)
    StaticCall(ContractRef, common.Address, []byte, uint64,
        *ExecPack) ([]byte, uint64, error)
}

type createFunc func(*Context, StateDB, *params.ChainConfig, interface{}) VM

// ExecPack contains runtime context, stateDB, chain config, VM list and VM configs.
type ExecPack struct {
    Context     *Context
    StateDB     StateDB
    ChainConfig *params.ChainConfig
    VMList      [NUMS]VM
    VMConfig    [NUMS]interface{}
}

var createFuncs [NUMS]createFunc

// Register registers VM create function.
func Register(idx uint8, c createFunc) {
    createFuncs[idx] = c
}

// NewExecPack creates a ExecPack instance, and create all VM instance.
func NewExecPack(context *Context, stateDB StateDB, chainConfig *params.ChainConfig, vmConfigs [NUMS]interface{}) ExecPack {
    p := ExecPack{
        Context:     context,
        StateDB:     stateDB,
        ChainConfig: chainConfig,
        VMConfig:    vmConfigs,
    }
    context.ExecPack = &p
    for i := 0; i < NUMS; i++ {
        if createFuncs[i] != nil {
            p.VMList[i] = createFuncs[i](context, stateDB, chainConfig, vmConfigs[i])
        }
    }
    return p
}

// Create is the entry for multiple VMs' Create.
func Create(caller ContractRef, code []byte, gas uint64, value *big.Int,
    p *ExecPack) (ret []byte, contractAddr common.Address,
    leftOverGas uint64, err error) {

    v, code := getVMAndCode(code)
    return p.VMList[v].Create(caller, code, gas, value, p)
}

// Create2 is the entry for multiple VMs' Create2.
func Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int,
    salt *big.Int, p *ExecPack) (ret []byte,
    contractAddr common.Address, leftOverGas uint64, err error) {

    v, code := getVMAndCode(code)
    return p.VMList[v].Create2(caller, code, gas, endowment, salt, p)
}

// Call is the entry for multiple VMs' Call.
func Call(caller ContractRef, addr common.Address, input []byte, gas uint64,
    value *big.Int, p *ExecPack) (ret []byte, leftOverGas uint64, err error) {

    code := p.StateDB.GetCode(addr)
    v, _ := getVMAndCode(code)
    return p.VMList[v].Call(caller, addr, input, gas, value, p)
}

// CallCode is the entry for multiple VMs' CallCode.
func CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64,
    value *big.Int, p *ExecPack) (ret []byte, leftOverGas uint64, err error) {

    code := p.StateDB.GetCode(addr)
    v, _ := getVMAndCode(code)
    return p.VMList[v].CallCode(caller, addr, input, gas, value, p)
}

// DelegateCall is the entry for multiple VMs' DelegateCall.
func DelegateCall(caller ContractRef, addr common.Address, input []byte,
    gas uint64, p *ExecPack) (ret []byte, leftOverGas uint64, err error) {

    code := p.StateDB.GetCode(addr)
    v, _ := getVMAndCode(code)
    return p.VMList[v].DelegateCall(caller, addr, input, gas, p)
}

// StaticCall is the entry for multiple VMs' StaticCall.
func StaticCall(caller ContractRef, addr common.Address, input []byte,
    gas uint64, p *ExecPack) (ret []byte, leftOverGas uint64, err error) {

    code := p.StateDB.GetCode(addr)
    v, _ := getVMAndCode(code)
    return p.VMList[v].StaticCall(caller, addr, input, gas, p)
}

func getVMAndCode(code []byte) (uint8, []byte) {
    if MULTIVM && len(code) > 0 {
        switch code[0] {
        case EVM, SQLVM:
            return code[0], code[1:]
        default:
            return EVM, code
        }
    }
    return EVM, code
}