github.com/theQRL/go-zond@v0.2.1/core/vm/zvm.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vm 18 19 import ( 20 "math/big" 21 "sync/atomic" 22 23 "github.com/holiman/uint256" 24 "github.com/theQRL/go-zond/common" 25 "github.com/theQRL/go-zond/core/types" 26 "github.com/theQRL/go-zond/crypto" 27 "github.com/theQRL/go-zond/params" 28 ) 29 30 type ( 31 // CanTransferFunc is the signature of a transfer guard function 32 CanTransferFunc func(StateDB, common.Address, *big.Int) bool 33 // TransferFunc is the signature of a transfer function 34 TransferFunc func(StateDB, common.Address, common.Address, *big.Int) 35 // GetHashFunc returns the n'th block hash in the blockchain 36 // and is used by the BLOCKHASH ZVM op code. 37 GetHashFunc func(uint64) common.Hash 38 ) 39 40 func (zvm *ZVM) precompile(addr common.Address) (PrecompiledContract, bool) { 41 precompiles := PrecompiledContractsBerlin 42 p, ok := precompiles[addr] 43 return p, ok 44 } 45 46 // BlockContext provides the ZVM with auxiliary information. Once provided 47 // it shouldn't be modified. 48 type BlockContext struct { 49 // CanTransfer returns whether the account contains 50 // sufficient ether to transfer the value 51 CanTransfer CanTransferFunc 52 // Transfer transfers ether from one account to the other 53 Transfer TransferFunc 54 // GetHash returns the hash corresponding to n 55 GetHash GetHashFunc 56 57 // Block information 58 Coinbase common.Address // Provides information for COINBASE 59 GasLimit uint64 // Provides information for GASLIMIT 60 BlockNumber *big.Int // Provides information for NUMBER 61 Time uint64 // Provides information for TIME 62 BaseFee *big.Int // Provides information for BASEFEE 63 Random *common.Hash // Provides information for PREVRANDAO 64 } 65 66 // TxContext provides the ZVM with information about a transaction. 67 // All fields can change between transactions. 68 type TxContext struct { 69 // Message information 70 Origin common.Address // Provides information for ORIGIN 71 GasPrice *big.Int // Provides information for GASPRICE 72 } 73 74 // ZVM is the Zond Virtual Machine base object and provides 75 // the necessary tools to run a contract on the given state with 76 // the provided context. It should be noted that any error 77 // generated through any of the calls should be considered a 78 // revert-state-and-consume-all-gas operation, no checks on 79 // specific errors should ever be performed. The interpreter makes 80 // sure that any errors generated are to be considered faulty code. 81 // 82 // The ZVM should never be reused and is not thread safe. 83 type ZVM struct { 84 // Context provides auxiliary blockchain related information 85 Context BlockContext 86 TxContext 87 // StateDB gives access to the underlying state 88 StateDB StateDB 89 // Depth is the current call stack 90 depth int 91 92 // chainConfig contains information about the current chain 93 chainConfig *params.ChainConfig 94 // chain rules contains the chain rules for the current epoch 95 chainRules params.Rules 96 // virtual machine configuration options used to initialise the 97 // zvm. 98 Config Config 99 // global (to this context) zond virtual machine 100 // used throughout the execution of the tx. 101 interpreter *ZVMInterpreter 102 // abort is used to abort the ZVM calling operations 103 abort atomic.Bool 104 // callGasTemp holds the gas available for the current call. This is needed because the 105 // available gas is calculated in gasCall* according to the 63/64 rule and later 106 // applied in opCall*. 107 callGasTemp uint64 108 } 109 110 // NewZVM returns a new ZVM. The returned ZVM is not thread safe and should 111 // only ever be used *once*. 112 func NewZVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *ZVM { 113 zvm := &ZVM{ 114 Context: blockCtx, 115 TxContext: txCtx, 116 StateDB: statedb, 117 Config: config, 118 chainConfig: chainConfig, 119 chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Time), 120 } 121 zvm.interpreter = NewZVMInterpreter(zvm) 122 return zvm 123 } 124 125 // Reset resets the ZVM with a new transaction context.Reset 126 // This is not threadsafe and should only be done very cautiously. 127 func (zvm *ZVM) Reset(txCtx TxContext, statedb StateDB) { 128 zvm.TxContext = txCtx 129 zvm.StateDB = statedb 130 } 131 132 // Cancel cancels any running ZVM operation. This may be called concurrently and 133 // it's safe to be called multiple times. 134 func (zvm *ZVM) Cancel() { 135 zvm.abort.Store(true) 136 } 137 138 // Cancelled returns true if Cancel has been called 139 func (zvm *ZVM) Cancelled() bool { 140 return zvm.abort.Load() 141 } 142 143 // Interpreter returns the current interpreter 144 func (zvm *ZVM) Interpreter() *ZVMInterpreter { 145 return zvm.interpreter 146 } 147 148 // SetBlockContext updates the block context of the ZVM. 149 func (zvm *ZVM) SetBlockContext(blockCtx BlockContext) { 150 zvm.Context = blockCtx 151 num := blockCtx.BlockNumber 152 timestamp := blockCtx.Time 153 zvm.chainRules = zvm.chainConfig.Rules(num, timestamp) 154 } 155 156 // Call executes the contract associated with the addr with the given input as 157 // parameters. It also handles any necessary value transfer required and takes 158 // the necessary steps to create accounts and reverses the state in case of an 159 // execution error or failed value transfer. 160 func (zvm *ZVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 161 // Fail if we're trying to execute above the call depth limit 162 if zvm.depth > int(params.CallCreateDepth) { 163 return nil, gas, ErrDepth 164 } 165 // Fail if we're trying to transfer more than the available balance 166 if value.Sign() != 0 && !zvm.Context.CanTransfer(zvm.StateDB, caller.Address(), value) { 167 return nil, gas, ErrInsufficientBalance 168 } 169 snapshot := zvm.StateDB.Snapshot() 170 p, isPrecompile := zvm.precompile(addr) 171 debug := zvm.Config.Tracer != nil 172 173 if !zvm.StateDB.Exist(addr) { 174 if !isPrecompile && value.Sign() == 0 { 175 // Calling a non existing account, don't do anything, but ping the tracer 176 if debug { 177 if zvm.depth == 0 { 178 zvm.Config.Tracer.CaptureStart(zvm, caller.Address(), addr, false, input, gas, value) 179 zvm.Config.Tracer.CaptureEnd(ret, 0, nil) 180 } else { 181 zvm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) 182 zvm.Config.Tracer.CaptureExit(ret, 0, nil) 183 } 184 } 185 return nil, gas, nil 186 } 187 zvm.StateDB.CreateAccount(addr) 188 } 189 zvm.Context.Transfer(zvm.StateDB, caller.Address(), addr, value) 190 191 // Capture the tracer start/end events in debug mode 192 if debug { 193 if zvm.depth == 0 { 194 zvm.Config.Tracer.CaptureStart(zvm, caller.Address(), addr, false, input, gas, value) 195 defer func(startGas uint64) { // Lazy evaluation of the parameters 196 zvm.Config.Tracer.CaptureEnd(ret, startGas-gas, err) 197 }(gas) 198 } else { 199 // Handle tracer events for entering and exiting a call frame 200 zvm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) 201 defer func(startGas uint64) { 202 zvm.Config.Tracer.CaptureExit(ret, startGas-gas, err) 203 }(gas) 204 } 205 } 206 207 if isPrecompile { 208 ret, gas, err = RunPrecompiledContract(p, input, gas) 209 } else { 210 // Initialise a new contract and set the code that is to be used by the ZVM. 211 // The contract is a scoped environment for this execution context only. 212 code := zvm.StateDB.GetCode(addr) 213 if len(code) == 0 { 214 ret, err = nil, nil // gas is unchanged 215 } else { 216 addrCopy := addr 217 // If the account has no code, we can abort here 218 // The depth-check is already done, and precompiles handled above 219 contract := NewContract(caller, AccountRef(addrCopy), value, gas) 220 contract.SetCallCode(&addrCopy, zvm.StateDB.GetCodeHash(addrCopy), code) 221 ret, err = zvm.interpreter.Run(contract, input, false) 222 gas = contract.Gas 223 } 224 } 225 // When an error was returned by the ZVM or when setting the creation code 226 // above we revert to the snapshot and consume any gas remaining. Additionally 227 // when we're in homestead this also counts for code storage gas errors. 228 if err != nil { 229 zvm.StateDB.RevertToSnapshot(snapshot) 230 if err != ErrExecutionReverted { 231 gas = 0 232 } 233 // TODO: consider clearing up unused snapshots: 234 //} else { 235 // zvm.StateDB.DiscardSnapshot(snapshot) 236 } 237 return ret, gas, err 238 } 239 240 // DelegateCall executes the contract associated with the addr with the given input 241 // as parameters. It reverses the state in case of an execution error. 242 // 243 // DelegateCall differs from CallCode in the sense that it executes the given address' 244 // code with the caller as context and the caller is set to the caller of the caller. 245 func (zvm *ZVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 246 // Fail if we're trying to execute above the call depth limit 247 if zvm.depth > int(params.CallCreateDepth) { 248 return nil, gas, ErrDepth 249 } 250 var snapshot = zvm.StateDB.Snapshot() 251 252 // Invoke tracer hooks that signal entering/exiting a call frame 253 if zvm.Config.Tracer != nil { 254 // NOTE: caller must, at all times be a contract. It should never happen 255 // that caller is something other than a Contract. 256 parent := caller.(*Contract) 257 // DELEGATECALL inherits value from parent call 258 zvm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value) 259 defer func(startGas uint64) { 260 zvm.Config.Tracer.CaptureExit(ret, startGas-gas, err) 261 }(gas) 262 } 263 264 // It is allowed to call precompiles, even via delegatecall 265 if p, isPrecompile := zvm.precompile(addr); isPrecompile { 266 ret, gas, err = RunPrecompiledContract(p, input, gas) 267 } else { 268 addrCopy := addr 269 // Initialise a new contract and make initialise the delegate values 270 contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate() 271 contract.SetCallCode(&addrCopy, zvm.StateDB.GetCodeHash(addrCopy), zvm.StateDB.GetCode(addrCopy)) 272 ret, err = zvm.interpreter.Run(contract, input, false) 273 gas = contract.Gas 274 } 275 if err != nil { 276 zvm.StateDB.RevertToSnapshot(snapshot) 277 if err != ErrExecutionReverted { 278 gas = 0 279 } 280 } 281 return ret, gas, err 282 } 283 284 // StaticCall executes the contract associated with the addr with the given input 285 // as parameters while disallowing any modifications to the state during the call. 286 // Opcodes that attempt to perform such modifications will result in exceptions 287 // instead of performing the modifications. 288 func (zvm *ZVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { 289 // Fail if we're trying to execute above the call depth limit 290 if zvm.depth > int(params.CallCreateDepth) { 291 return nil, gas, ErrDepth 292 } 293 // We take a snapshot here. This is a bit counter-intuitive, and could probably be skipped. 294 // However, even a staticcall is considered a 'touch'. On mainnet, static calls were introduced 295 // after all empty accounts were deleted, so this is not required. However, if we omit this, 296 // then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json. 297 // We could change this, but for now it's left for legacy reasons 298 var snapshot = zvm.StateDB.Snapshot() 299 300 // We do an AddBalance of zero here, just in order to trigger a touch. 301 // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, 302 // but is the correct thing to do and matters on other networks, in tests, and potential 303 // future scenarios 304 zvm.StateDB.AddBalance(addr, big0) 305 306 // Invoke tracer hooks that signal entering/exiting a call frame 307 if zvm.Config.Tracer != nil { 308 zvm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) 309 defer func(startGas uint64) { 310 zvm.Config.Tracer.CaptureExit(ret, startGas-gas, err) 311 }(gas) 312 } 313 314 if p, isPrecompile := zvm.precompile(addr); isPrecompile { 315 ret, gas, err = RunPrecompiledContract(p, input, gas) 316 } else { 317 // At this point, we use a copy of address. If we don't, the go compiler will 318 // leak the 'contract' to the outer scope, and make allocation for 'contract' 319 // even if the actual execution ends on RunPrecompiled above. 320 addrCopy := addr 321 // Initialise a new contract and set the code that is to be used by the ZVM. 322 // The contract is a scoped environment for this execution context only. 323 contract := NewContract(caller, AccountRef(addrCopy), new(big.Int), gas) 324 contract.SetCallCode(&addrCopy, zvm.StateDB.GetCodeHash(addrCopy), zvm.StateDB.GetCode(addrCopy)) 325 // When an error was returned by the ZVM or when setting the creation code 326 // above we revert to the snapshot and consume any gas remaining. Additionally 327 // when we're in Homestead this also counts for code storage gas errors. 328 ret, err = zvm.interpreter.Run(contract, input, true) 329 gas = contract.Gas 330 } 331 if err != nil { 332 zvm.StateDB.RevertToSnapshot(snapshot) 333 if err != ErrExecutionReverted { 334 gas = 0 335 } 336 } 337 return ret, gas, err 338 } 339 340 type codeAndHash struct { 341 code []byte 342 hash common.Hash 343 } 344 345 func (c *codeAndHash) Hash() common.Hash { 346 if c.hash == (common.Hash{}) { 347 c.hash = crypto.Keccak256Hash(c.code) 348 } 349 return c.hash 350 } 351 352 // create creates a new contract using code as deployment code. 353 func (zvm *ZVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) { 354 // Depth check execution. Fail if we're trying to execute above the 355 // limit. 356 if zvm.depth > int(params.CallCreateDepth) { 357 return nil, common.Address{}, gas, ErrDepth 358 } 359 if !zvm.Context.CanTransfer(zvm.StateDB, caller.Address(), value) { 360 return nil, common.Address{}, gas, ErrInsufficientBalance 361 } 362 nonce := zvm.StateDB.GetNonce(caller.Address()) 363 if nonce+1 < nonce { 364 return nil, common.Address{}, gas, ErrNonceUintOverflow 365 } 366 zvm.StateDB.SetNonce(caller.Address(), nonce+1) 367 // We add this to the access list _before_ taking a snapshot. Even if the creation fails, 368 // the access-list change should not be rolled back 369 zvm.StateDB.AddAddressToAccessList(address) 370 // Ensure there's no existing contract already at the designated address 371 contractHash := zvm.StateDB.GetCodeHash(address) 372 if zvm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) { 373 return nil, common.Address{}, 0, ErrContractAddressCollision 374 } 375 // Create a new account on the state 376 snapshot := zvm.StateDB.Snapshot() 377 zvm.StateDB.CreateAccount(address) 378 zvm.StateDB.SetNonce(address, 1) 379 zvm.Context.Transfer(zvm.StateDB, caller.Address(), address, value) 380 381 // Initialise a new contract and set the code that is to be used by the ZVM. 382 // The contract is a scoped environment for this execution context only. 383 contract := NewContract(caller, AccountRef(address), value, gas) 384 contract.SetCodeOptionalHash(&address, codeAndHash) 385 386 if zvm.Config.Tracer != nil { 387 if zvm.depth == 0 { 388 zvm.Config.Tracer.CaptureStart(zvm, caller.Address(), address, true, codeAndHash.code, gas, value) 389 } else { 390 zvm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) 391 } 392 } 393 394 ret, err := zvm.interpreter.Run(contract, nil, false) 395 396 // Check whether the max code size has been exceeded, assign err if the case. 397 if err == nil && len(ret) > params.MaxCodeSize { 398 err = ErrMaxCodeSizeExceeded 399 } 400 401 // Reject code starting with 0xEF if EIP-3541 is enabled. 402 if err == nil && len(ret) >= 1 && ret[0] == 0xEF { 403 err = ErrInvalidCode 404 } 405 406 // if the contract creation ran successfully and no errors were returned 407 // calculate the gas required to store the code. If the code could not 408 // be stored due to not enough gas set an error and let it be handled 409 // by the error checking condition below. 410 if err == nil { 411 createDataGas := uint64(len(ret)) * params.CreateDataGas 412 if contract.UseGas(createDataGas) { 413 zvm.StateDB.SetCode(address, ret) 414 } else { 415 err = ErrCodeStoreOutOfGas 416 } 417 } 418 419 // When an error was returned by the ZVM or when setting the creation code 420 // above we revert to the snapshot and consume any gas remaining. Additionally 421 // when we're in homestead this also counts for code storage gas errors. 422 if err != nil && (err != ErrCodeStoreOutOfGas) { 423 zvm.StateDB.RevertToSnapshot(snapshot) 424 if err != ErrExecutionReverted { 425 contract.UseGas(contract.Gas) 426 } 427 } 428 429 if zvm.Config.Tracer != nil { 430 if zvm.depth == 0 { 431 zvm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err) 432 } else { 433 zvm.Config.Tracer.CaptureExit(ret, gas-contract.Gas, err) 434 } 435 } 436 return ret, address, contract.Gas, err 437 } 438 439 // Create creates a new contract using code as deployment code. 440 func (zvm *ZVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { 441 contractAddr = crypto.CreateAddress(caller.Address(), zvm.StateDB.GetNonce(caller.Address())) 442 return zvm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE) 443 } 444 445 // Create2 creates a new contract using code as deployment code. 446 // 447 // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] 448 // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. 449 func (zvm *ZVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { 450 codeAndHash := &codeAndHash{code: code} 451 contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) 452 return zvm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2) 453 } 454 455 // ChainConfig returns the environment's chain configuration 456 func (zvm *ZVM) ChainConfig() *params.ChainConfig { return zvm.chainConfig }