-
Notifications
You must be signed in to change notification settings - Fork 143
/
internal.go
172 lines (145 loc) · 5.2 KB
/
internal.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
167
168
169
170
171
172
// Copyright 2020 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
package evmimpl
import (
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/iotaledger/wasp/packages/evm/evmutil"
"github.com/iotaledger/wasp/packages/isc"
"github.com/iotaledger/wasp/packages/kv"
"github.com/iotaledger/wasp/packages/kv/codec"
"github.com/iotaledger/wasp/packages/kv/dict"
"github.com/iotaledger/wasp/packages/parameters"
"github.com/iotaledger/wasp/packages/vm/core/accounts"
"github.com/iotaledger/wasp/packages/vm/core/evm"
"github.com/iotaledger/wasp/packages/vm/core/evm/emulator"
"github.com/iotaledger/wasp/packages/vm/gas"
)
// MintBlock "mints" the Ethereum block after all requests in the ISC
// block have been processed.
// IMPORTANT: Must only be called from the ISC VM
func MintBlock(evmPartition kv.KVStore, chainInfo *isc.ChainInfo, blockTimestamp time.Time) {
createBlockchainDB(evmPartition, chainInfo).MintBlock(timestamp(blockTimestamp))
}
func getTracer(ctx isc.Sandbox) tracers.Tracer {
tracer := ctx.EVMTracer()
if tracer == nil {
return nil
}
if tracer.TxIndex != uint64(ctx.RequestIndex()) {
return nil // trace only the transaction we're interested in
}
return tracer.Tracer
}
func createEmulator(ctx isc.Sandbox) *emulator.EVMEmulator {
return emulator.NewEVMEmulator(newEmulatorContext(ctx))
}
func createBlockchainDB(evmPartition kv.KVStore, chainInfo *isc.ChainInfo) *emulator.BlockchainDB {
return emulator.NewBlockchainDB(evm.EmulatorStateSubrealm(evmPartition), gasLimits(chainInfo).Block, chainInfo.BlockKeepAmount)
}
func saveExecutedTx(
evmPartition kv.KVStore,
chainInfo *isc.ChainInfo,
tx *types.Transaction,
receipt *types.Receipt,
) {
createBlockchainDB(evmPartition, chainInfo).AddTransaction(tx, receipt)
// make sure the nonce is incremented if the state was rolled back by the VM
if receipt.Status != types.ReceiptStatusSuccessful {
emulator.IncNonce(emulator.StateDBSubrealm(evm.EmulatorStateSubrealm(evmPartition)), evmutil.MustGetSender(tx))
}
}
func gasLimits(chainInfo *isc.ChainInfo) emulator.GasLimits {
return emulator.GasLimits{
Block: gas.EVMBlockGasLimit(chainInfo.GasLimits, &chainInfo.GasFeePolicy.EVMGasRatio),
Call: gas.EVMCallGasLimit(chainInfo.GasLimits, &chainInfo.GasFeePolicy.EVMGasRatio),
}
}
// timestamp returns the current timestamp in seconds since epoch
func timestamp(t time.Time) uint64 {
return uint64(t.Unix())
}
func result(value []byte) dict.Dict {
if value == nil {
return nil
}
return dict.Dict{evm.FieldResult: value}
}
type emulatorContext struct {
sandbox isc.Sandbox
}
var _ emulator.Context = &emulatorContext{}
func newEmulatorContext(sandbox isc.Sandbox) *emulatorContext {
return &emulatorContext{
sandbox: sandbox,
}
}
func (ctx *emulatorContext) BlockKeepAmount() int32 {
ret := int32(0)
// do not charge gas for this, internal checks of the emulator require this function to run before executing the request
ctx.WithoutGasBurn(func() {
ret = ctx.sandbox.ChainInfo().BlockKeepAmount
})
return ret
}
func (ctx *emulatorContext) GasLimits() emulator.GasLimits {
var ret emulator.GasLimits
// do not charge gas for this, internal checks of the emulator require this function to run before executing the request
ctx.WithoutGasBurn(func() {
ret = gasLimits(ctx.sandbox.ChainInfo())
})
return ret
}
func (ctx *emulatorContext) MagicContracts() map[common.Address]vm.ISCMagicContract {
return newMagicContract(ctx.sandbox)
}
func (ctx *emulatorContext) State() kv.KVStore {
return evm.EmulatorStateSubrealm(ctx.sandbox.State())
}
func (ctx *emulatorContext) Timestamp() uint64 {
return timestamp(ctx.sandbox.Timestamp())
}
func (*emulatorContext) BaseTokensDecimals() uint32 {
return parameters.L1().BaseToken.Decimals
}
func (ctx *emulatorContext) GetBaseTokensBalance(addr common.Address) *big.Int {
ret := new(big.Int)
// do not charge gas for this, internal checks of the emulator require this function to run before executing the request
ctx.WithoutGasBurn(func() {
res := ctx.sandbox.CallView(
accounts.Contract.Hname(),
accounts.ViewBalanceBaseTokenEVM.Hname(),
dict.Dict{accounts.ParamAgentID: isc.NewEthereumAddressAgentID(ctx.sandbox.ChainID(), addr).Bytes()},
)
ret = codec.MustDecodeBigIntAbs(res.Get(accounts.ParamBalance), big.NewInt(0))
})
return ret
}
func (ctx *emulatorContext) AddBaseTokensBalance(addr common.Address, amount *big.Int) {
ctx.sandbox.Privileged().CreditToAccount(
isc.NewEthereumAddressAgentID(ctx.sandbox.ChainID(), addr),
amount,
)
}
func (ctx *emulatorContext) SubBaseTokensBalance(addr common.Address, amount *big.Int) {
ctx.sandbox.Privileged().DebitFromAccount(
isc.NewEthereumAddressAgentID(ctx.sandbox.ChainID(), addr),
amount,
)
}
func (ctx *emulatorContext) TakeSnapshot() int {
return ctx.sandbox.TakeStateSnapshot()
}
func (ctx *emulatorContext) RevertToSnapshot(i int) {
ctx.sandbox.RevertToStateSnapshot(i)
}
func (ctx *emulatorContext) WithoutGasBurn(f func()) {
prev := ctx.sandbox.Privileged().GasBurnEnabled()
ctx.sandbox.Privileged().GasBurnEnable(false)
f()
ctx.sandbox.Privileged().GasBurnEnable(prev)
}