/
contract.go
152 lines (127 loc) · 4.04 KB
/
contract.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
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
142
143
144
145
146
147
148
149
150
151
152
package vm
import (
"math/big"
sdk "github.com/netcloth/netcloth-chain/types"
)
// ContractRef is a interface to the contract's backing object
type ContractRef interface {
Address() sdk.AccAddress
}
// AccountRef implements ContractRef
type AccountRef sdk.AccAddress
// Address casts AccountRef to a Address
func (ar AccountRef) Address() sdk.AccAddress {
return (sdk.AccAddress)(ar)
}
// Contract implements ContractRef
type Contract struct {
// CallerAddress is the result of the caller which initialised this
// contract. However when the "call method" is delegated this value
// needs to be initialised to that of the caller's caller.
CallerAddress sdk.AccAddress
caller ContractRef
self ContractRef
jumpdests map[sdk.Hash]bitvec // Aggregated result of JUMPDEST analysis.
analysis bitvec // Locally cached result of JUMPDEST analysis
Code []byte
CodeHash sdk.Hash
CodeAddr *sdk.AccAddress
Input []byte
Gas uint64
value *big.Int
}
func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object}
if parent, ok := caller.(*Contract); ok {
c.jumpdests = parent.jumpdests
} else {
c.jumpdests = make(map[sdk.Hash]bitvec)
}
c.Gas = gas
c.value = value
return c
}
func (c *Contract) validJumpdest(dest *big.Int) bool {
udest := dest.Uint64()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) {
return false
}
// Only JUMPDESTs allowed for destinations
if OpCode(c.Code[udest]) != JUMPDEST {
return false
}
// Do we have a contract hash already ?
if c.CodeHash != (sdk.Hash{}) {
analysis, exist := c.jumpdests[c.CodeHash]
if !exist {
analysis = codeBitmap(c.Code)
c.jumpdests[c.CodeHash] = analysis
}
return analysis.codeSegment(udest)
}
// We don't have the code hash, most likely a piece of initcode not already
// in state trie. In that case, we do an analysis, and save it locally, so
// we don't have to recalculate it for every JUMP instruction in the execution
// However, we don't save it within the parent context
if c.analysis == nil {
c.analysis = codeBitmap(c.Code)
}
return c.analysis.codeSegment(udest)
}
func (c *Contract) AsDelegate() *Contract {
// NOTE: caller must, at all times be a contract.
parent := c.caller.(*Contract)
c.CallerAddress = parent.CallerAddress
c.value = parent.value
return c
}
// GetOp returns the n'th element in the contract's byte array
func (c *Contract) GetOp(n uint64) OpCode {
return OpCode(c.GetByte(n))
}
// GetByte returns the n'th byte in the contract's byte array
func (c *Contract) GetByte(n uint64) byte {
if n < uint64(len(c.Code)) {
return c.Code[n]
}
return 0
}
// Caller returns the caller of the contract.
//
// Caller will recursively call caller when the contract is a delegate
// call, including that of caller's caller.
func (c *Contract) Caller() sdk.AccAddress {
return c.CallerAddress
}
// UseGas attempts the use gas and subtracts it and returns true on success
func (c *Contract) UseGas(gas uint64) (ok bool) {
if c.Gas < gas {
return false
}
c.Gas -= gas
return true
}
// Address returns the contract address
func (c *Contract) Address() sdk.AccAddress {
return c.self.Address()
}
// Value returns the contract value (sent to it from it's caller)
func (c *Contract) Value() *big.Int {
return c.value
}
// SetCallCode sets the code of the contract and address of the backing data
// object
func (c *Contract) SetCallCode(addr *sdk.AccAddress, hash sdk.Hash, code []byte) {
c.Code = code
c.CodeHash = hash
c.CodeAddr = addr
}
// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash.
// In case hash is not provided, the jumpdest analysis will not be saved to the parent context
func (c *Contract) SetCodeOptionalHash(addr *sdk.AccAddress, codeAndHash *codeAndHash) {
c.Code = codeAndHash.code
c.CodeHash = codeAndHash.hash
c.CodeAddr = addr
}