forked from celo-org/celo-blockchain
/
context.go
166 lines (142 loc) · 5.92 KB
/
context.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm
import (
"math/big"
"github.com/conclave-dev/celo-blockchain/common"
"github.com/conclave-dev/celo-blockchain/consensus"
"github.com/conclave-dev/celo-blockchain/core/state"
"github.com/conclave-dev/celo-blockchain/core/types"
"github.com/conclave-dev/celo-blockchain/params"
)
// Message represents a message sent to a contract.
type Message interface {
From() common.Address
//FromFrontier() (common.Address, error)
To() *common.Address
GasPrice() *big.Int
Gas() uint64
// FeeCurrency specifies the currency for gas and gateway fees.
// nil correspond to Celo Gold (native currency).
// All other values should correspond to ERC20 contract addresses extended to be compatible with gas payments.
FeeCurrency() *common.Address
GatewayFeeRecipient() *common.Address
GatewayFee() *big.Int
Value() *big.Int
Nonce() uint64
CheckNonce() bool
Data() []byte
}
// ChainContext supports retrieving chain data and consensus parameters
// from the blockchain to be used during transaction processing.
type ChainContext interface {
// Engine retrieves the blockchain's consensus engine.
Engine() consensus.Engine
// GetHeader returns the hash corresponding to the given hash and number.
GetHeader(common.Hash, uint64) *types.Header
// GetHeaderByNumber returns the hash corresponding number.
// FIXME: Use of this function, as implemented, in the EVM context produces undefined behavior
// in the pressence of forks. A new method needs to be created to retrieve a header by number
// in the correct fork.
GetHeaderByNumber(uint64) *types.Header
// GetVMConfig returns the node's vm configuration
GetVMConfig() *Config
CurrentHeader() *types.Header
State() (*state.StateDB, error)
// Config returns the blockchain's chain configuration
Config() *params.ChainConfig
}
// NewEVMContext creates a new context for use in the EVM.
func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) Context {
// If we don't have an explicit author (i.e. not mining), extract from the header
var beneficiary common.Address
if author == nil {
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
} else {
beneficiary = *author
}
var engine consensus.Engine
var getHeaderByNumberFn func(uint64) *types.Header
if chain != nil {
engine = chain.Engine()
getHeaderByNumberFn = chain.GetHeaderByNumber
}
return Context{
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
GetHeaderByNumber: getHeaderByNumberFn,
VerifySeal: VerifySealFn(header, chain),
Origin: msg.From(),
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).SetUint64(header.Time),
GasPrice: new(big.Int).Set(msg.GasPrice()),
Engine: engine,
}
}
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain ChainContext) func(uint64) common.Hash {
var cache map[uint64]common.Hash
return func(n uint64) common.Hash {
// If there's no hash cache yet, make one
if cache == nil {
cache = map[uint64]common.Hash{
ref.Number.Uint64() - 1: ref.ParentHash,
}
}
// Try to fulfill the request from the cache
if hash, ok := cache[n]; ok {
return hash
}
// Not cached, iterate the blocks and cache the hashes (up to a limit of 256)
for i, header := 0, chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil && i <= 256; i, header = i+1, chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
cache[header.Number.Uint64()-1] = header.ParentHash
if n == header.Number.Uint64()-1 {
return header.ParentHash
}
}
return common.Hash{}
}
}
// CanTransfer checks whether there are enough funds in the address' account to make a transfer.
// This does not take the necessary gas into account to make the transfer valid.
func CanTransfer(db StateDB, addr common.Address, amount *big.Int) bool {
return db.GetBalance(addr).Cmp(amount) >= 0
}
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
func Transfer(db StateDB, sender, recipient common.Address, amount *big.Int) {
db.SubBalance(sender, amount)
db.AddBalance(recipient, amount)
}
// VerifySealFn returns a function which returns true when the given header has a verifiable seal.
func VerifySealFn(ref *types.Header, chain ChainContext) func(*types.Header) bool {
return func(header *types.Header) bool {
// If the block is later than the unsealed reference block, return false.
if header.Number.Cmp(ref.Number) > 0 {
return false
}
// FIXME: Implementation currently relies on the Istanbul engine's internal view of the
// chain, so return false if this is not an Istanbul chain. As a consequence of this the
// seal is always verified against the canonical chain, which makes behavior undefined if
// this function is evaluated on a chain which does not have the highest total difficulty.
if chain.Config().Istanbul == nil {
return false
}
// Submit the header to the engine's seal verification function.
return chain.Engine().VerifySeal(nil, header) == nil
}
}