Call executes the contract associated with the addr with the given input as parameters. It also handles any necessary value transfer required and takes the necessary steps to create accounts and reverses the state in case of an execution error or failed value transfer.
(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int)
| 147 | // the necessary steps to create accounts and reverses the state in case of an |
| 148 | // execution error or failed value transfer. |
| 149 | func (evm *EVM) call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { |
| 150 | if evm.vmConfig.NoRecursion && evm.depth > 0 { |
| 151 | return nil, gas, nil |
| 152 | } |
| 153 | |
| 154 | // Fail if we're trying to execute above the call depth limit |
| 155 | if evm.depth > int(configs.CallCreateDepth) { |
| 156 | return nil, gas, ErrDepth |
| 157 | } |
| 158 | // Fail if we're trying to transfer more than the available balance |
| 159 | if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { |
| 160 | return nil, gas, ErrInsufficientBalance |
| 161 | } |
| 162 | |
| 163 | var ( |
| 164 | to = AccountRef(addr) |
| 165 | snapshot = evm.StateDB.Snapshot() |
| 166 | ) |
| 167 | if !evm.StateDB.Exist(addr) { |
| 168 | if PrimitiveContracts[addr] == nil && value.Sign() == 0 { |
| 169 | // Calling a non existing account, don't do antything, but ping the tracer |
| 170 | if evm.vmConfig.Debug && evm.depth == 0 { |
| 171 | evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) |
| 172 | evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) |
| 173 | } |
| 174 | return nil, gas, nil |
| 175 | } |
| 176 | evm.StateDB.CreateAccount(addr) |
| 177 | } |
| 178 | evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) |
| 179 | |
| 180 | // Initialise a new contract and set the code that is to be used by the EVM. |
| 181 | // The contract is a scoped environment for this execution context only. |
| 182 | contract := NewContract(caller, to, value, gas) |
| 183 | contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) |
| 184 | |
| 185 | start := time.Now() |
| 186 | |
| 187 | // Capture the tracer start/end events in debug mode |
| 188 | if evm.vmConfig.Debug && evm.depth == 0 { |
| 189 | evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) |
| 190 | |
| 191 | defer func() { // Lazy evaluation of the parameters |
| 192 | evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) |
| 193 | }() |
| 194 | } |
| 195 | ret, err = run(evm, contract, input) |
| 196 | |
| 197 | // When an error was returned by the EVM or when setting the creation code |
| 198 | // above we revert to the snapshot and consume any gas remaining. Additionally |
| 199 | // when we're in homestead this also counts for code storage gas errors. |
| 200 | if err != nil { |
| 201 | evm.StateDB.RevertToSnapshot(snapshot) |
| 202 | if err != errExecutionReverted { |
| 203 | contract.UseGas(contract.Gas) |
| 204 | } |
| 205 | } |
| 206 | return ret, contract.Gas, err |