-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcontractframe.go
More file actions
126 lines (119 loc) · 3.46 KB
/
Copy pathcontractframe.go
File metadata and controls
126 lines (119 loc) · 3.46 KB
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
/*
* Copyright (C) 2018 The Cypherium VM (CVM) authors
*
* This file is part of the CVM library.
*
* The CVM library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The CVM library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the CVM library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package cvm
import (
"encoding/binary"
"fmt"
"github.com/syndtr/goleveldb/leveldb"
"log"
"os"
)
//ContractFrame defines the runtime info associated with a contract
type ContractFrame struct {
rf *RegisterFile
mem *Memory
contract *Contract
depth uint64 //Current call depth
pc uint64 //Program counter
jmpc uint64 //Conditional jump counter
gas uint64 //Remaining gas counter
Operations OperationSet
call bool //If this contract is called by another
caller *ContractFrame //Previous caller
sender *ContractFrame //Original caller
log *log.Logger
StateDB *leveldb.DB
}
func NewContractFrame(ctc *Contract, db *leveldb.DB) (cf *ContractFrame) {
cf = &ContractFrame{
rf: NewRegisterFile(),
mem: NewMemory(),
contract: ctc,
pc: 0,
depth: 0,
gas: ctc.GasLimit,
Operations: NewOperationSet(),
call: false,
caller: nil,
sender: nil,
log: log.New(os.Stderr, "", 0),
StateDB: db,
}
return
}
/*
* CallContractFrame sets up a ContractFrame for a contract called by another
* one and sets up the correct calling relationships (sender, caller etc.).
*/
func (cf *ContractFrame) CallContractFrame(ctc *Contract) error {
if cf.depth == MaxCallDepth {
return ErrorCallDepth
}
newCf := &ContractFrame{
rf: NewRegisterFile(),
mem: NewMemory(),
contract: ctc,
pc: 0,
depth: cf.depth + 1,
gas: cf.gas,
Operations: NewOperationSet(),
call: true,
caller: cf,
sender: cf.sender,
log: log.New(os.Stderr, "", 0),
}
//If the sender is not set it means that the caller is the original sender
if newCf.sender == nil {
newCf.sender = cf
}
fmt.Println(newCf.pc, newCf.depth, newCf.call)
newCf.Execute()
return nil
}
/*
* Execute reads the contract associated with the current contract frame and
* execute it
*/
func (cf *ContractFrame) Execute() error {
cf.contract.PrintCode(cf.log)
/*
* A jump out of the code would result an immediate return, the compiler
* should ensure a valid jump
*/
for cf.pc < uint64(len(cf.contract.Code)) && cf.pc >= 0 {
if cf.gas == 0 {
return ErrorOutOfGas
}
opIdx := cf.contract.Code[cf.pc]
op := cf.Operations[opIdx]
regIdx := make([]uint64, op.regNum)
for i := 0; uint64(i) < op.regNum; i++ {
offset := cf.pc + 1 + RegLen*uint64(i)
regIdx[i] = uint64(binary.BigEndian.Uint16(cf.contract.Code[offset : offset+2]))
}
cf.log.Println("pc:", cf.pc, "opname:", op.name, "regs:", regIdx, "gas", cf.gas)
if exeErr := op.execute(cf, regIdx, &op); exeErr != nil {
//log.Println(err.Error())
return exeErr
}
cf.rf.Print(cf.log)
}
return nil
}