github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/evm/evm.go (about) 1 // Copyright Monax Industries Limited 2 // SPDX-License-Identifier: Apache-2.0 3 4 package evm 5 6 import ( 7 "fmt" 8 9 "github.com/hyperledger/burrow/acm" 10 "github.com/hyperledger/burrow/acm/acmstate" 11 "github.com/hyperledger/burrow/execution/defaults" 12 "github.com/hyperledger/burrow/execution/engine" 13 "github.com/hyperledger/burrow/execution/exec" 14 "github.com/hyperledger/burrow/execution/native" 15 "github.com/hyperledger/burrow/logging" 16 ) 17 18 const ( 19 DataStackInitialCapacity = 1024 20 MaximumAllowedBlockLookBack = 256 21 uint64Length = 8 22 ) 23 24 type EVM struct { 25 options engine.Options 26 sequence uint64 27 // Provide any foreign dispatchers to allow calls between VMs 28 engine.Externals 29 externalDispatcher engine.Dispatcher 30 // User dispatcher.CallableProvider to get access to other VMs 31 logger *logging.Logger 32 } 33 34 func New(options engine.Options) *EVM { 35 options = defaults.CompleteOptions(options) 36 vm := &EVM{ 37 options: options, 38 } 39 vm.logger = options.Logger.WithScope("NewVM").With("evm_nonce", options.Nonce) 40 vm.externalDispatcher = engine.Dispatchers{&vm.Externals, options.Natives, vm} 41 return vm 42 } 43 44 func Default() *EVM { 45 return New(engine.Options{}) 46 } 47 48 // Initiate an EVM call against the provided state pushing events to eventSink. code should contain the EVM bytecode, 49 // input the CallData (readable by CALLDATALOAD), value the amount of native token to transfer with the call 50 // an quantity metering the number of computational steps available to the execution according to the gas schedule. 51 func (vm *EVM) Execute(st acmstate.ReaderWriter, blockchain engine.Blockchain, eventSink exec.EventSink, 52 params engine.CallParams, code []byte) ([]byte, error) { 53 54 // Make it appear as if natives are stored in state 55 st = native.NewState(vm.options.Natives, st) 56 57 state := engine.State{ 58 CallFrame: engine.NewCallFrame(st).WithMaxCallStackDepth(vm.options.CallStackMaxDepth), 59 Blockchain: blockchain, 60 EventSink: eventSink, 61 } 62 63 output, err := vm.Contract(code).Call(state, params) 64 if err == nil { 65 // Only sync back when there was no exception 66 err = state.CallFrame.Sync() 67 } 68 // Always return output - we may have a reverted exception for which the return is meaningful 69 return output, err 70 } 71 72 // Sets a new nonce and resets the sequence number. Nonces should only be used once! 73 // A global counter or sufficient randomness will work. 74 func (vm *EVM) SetNonce(nonce []byte) { 75 vm.options.Nonce = nonce 76 vm.sequence = 0 77 } 78 79 func (vm *EVM) SetLogger(logger *logging.Logger) { 80 vm.logger = logger 81 } 82 83 func (vm *EVM) Dispatch(acc *acm.Account) engine.Callable { 84 // Let the EVM handle code-less (e.g. those created by a call) contracts (so only return nil if there is _other_ non-EVM code) 85 if len(acc.EVMCode) == 0 && len(acc.Code()) != 0 { 86 return nil 87 } 88 return vm.Contract(acc.EVMCode) 89 } 90 91 func (vm *EVM) Contract(code []byte) *Contract { 92 return &Contract{ 93 EVM: vm, 94 Code: NewCode(code), 95 } 96 } 97 98 func (vm *EVM) debugf(format string, a ...interface{}) { 99 if vm.options.DebugOpcodes { 100 fmt.Printf(format, a...) 101 } 102 }