| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // 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. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-04 10:28:02 +01:00
										 |  |  | package core | 
					
						
							| 
									
										
										
										
											2014-12-03 17:06:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-17 11:19:23 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-03-23 16:59:09 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/vm" | 
					
						
							| 
									
										
										
										
											2015-03-24 11:49:30 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2015-04-02 05:17:15 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2014-12-03 17:06:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | // Call executes within the given contract | 
					
						
							|  |  |  | func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	// Depth check execution. Fail if we're trying to execute above the | 
					
						
							|  |  |  | 	// limit. | 
					
						
							|  |  |  | 	if env.Depth() > int(params.CallCreateDepth.Int64()) { | 
					
						
							|  |  |  | 		caller.ReturnGas(gas, gasPrice) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return nil, vm.DepthError | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !env.CanTransfer(caller.Address(), value) { | 
					
						
							|  |  |  | 		caller.ReturnGas(gas, gasPrice) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address())) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snapshotPreTransfer := env.SnapshotDatabase() | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		from = env.Db().GetAccount(caller.Address()) | 
					
						
							|  |  |  | 		to   vm.Account | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if !env.Db().Exist(addr) { | 
					
						
							|  |  |  | 		if vm.Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber()) && value.BitLen() == 0 { | 
					
						
							|  |  |  | 			caller.ReturnGas(gas, gasPrice) | 
					
						
							|  |  |  | 			return nil, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		to = env.Db().CreateAccount(addr) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		to = env.Db().GetAccount(addr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	env.Transfer(from, to, value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// initialise a new contract and set the code that is to be used by the | 
					
						
							|  |  |  | 	// EVM. The contract is a scoped environment for this execution context | 
					
						
							|  |  |  | 	// only. | 
					
						
							|  |  |  | 	contract := vm.NewContract(caller, to, value, gas, gasPrice) | 
					
						
							|  |  |  | 	contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr)) | 
					
						
							|  |  |  | 	defer contract.Finalise() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret, err = env.Vm().Run(contract, input) | 
					
						
							|  |  |  | 	// When an error was returned by the EVM or when setting the creation code | 
					
						
							|  |  |  | 	// above we revert to the snapshot and consume any gas remaining. Additionally | 
					
						
							|  |  |  | 	// when we're in homestead this also counts for code storage gas errors. | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		contract.UseGas(contract.Gas) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		env.RevertToSnapshot(snapshotPreTransfer) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 	return ret, err | 
					
						
							| 
									
										
										
										
											2014-12-03 17:06:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | // CallCode executes the given address' code as the given contract address | 
					
						
							|  |  |  | func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	// Depth check execution. Fail if we're trying to execute above the | 
					
						
							|  |  |  | 	// limit. | 
					
						
							|  |  |  | 	if env.Depth() > int(params.CallCreateDepth.Int64()) { | 
					
						
							|  |  |  | 		caller.ReturnGas(gas, gasPrice) | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 		return nil, vm.DepthError | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !env.CanTransfer(caller.Address(), value) { | 
					
						
							|  |  |  | 		caller.ReturnGas(gas, gasPrice) | 
					
						
							| 
									
										
										
										
											2014-12-03 17:06:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 		return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address())) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		snapshotPreTransfer = env.SnapshotDatabase() | 
					
						
							|  |  |  | 		to                  = env.Db().GetAccount(caller.Address()) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// initialise a new contract and set the code that is to be used by the | 
					
						
							|  |  |  | 	// EVM. The contract is a scoped environment for this execution context | 
					
						
							|  |  |  | 	// only. | 
					
						
							|  |  |  | 	contract := vm.NewContract(caller, to, value, gas, gasPrice) | 
					
						
							|  |  |  | 	contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr)) | 
					
						
							|  |  |  | 	defer contract.Finalise() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret, err = env.Vm().Run(contract, input) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:23:20 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 		contract.UseGas(contract.Gas) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		env.RevertToSnapshot(snapshotPreTransfer) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:23:20 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return ret, err | 
					
						
							| 
									
										
										
										
											2015-03-28 20:03:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | // Create creates a new contract with the given code | 
					
						
							|  |  |  | func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) { | 
					
						
							| 
									
										
										
										
											2015-08-02 02:20:41 +02:00
										 |  |  | 	// Depth check execution. Fail if we're trying to execute above the | 
					
						
							|  |  |  | 	// limit. | 
					
						
							| 
									
										
										
										
											2015-04-02 05:17:15 +02:00
										 |  |  | 	if env.Depth() > int(params.CallCreateDepth.Int64()) { | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 		caller.ReturnGas(gas, gasPrice) | 
					
						
							| 
									
										
										
										
											2015-01-05 17:37:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 		return nil, common.Address{}, vm.DepthError | 
					
						
							| 
									
										
										
										
											2014-12-17 23:58:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 	if !env.CanTransfer(caller.Address(), value) { | 
					
						
							|  |  |  | 		caller.ReturnGas(gas, gasPrice) | 
					
						
							| 
									
										
										
										
											2015-08-02 02:20:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 		return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address())) | 
					
						
							| 
									
										
										
										
											2015-08-02 02:20:41 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	// Create a new account on the state | 
					
						
							|  |  |  | 	nonce := env.Db().GetNonce(caller.Address()) | 
					
						
							|  |  |  | 	env.Db().SetNonce(caller.Address(), nonce+1) | 
					
						
							| 
									
										
										
										
											2016-06-29 11:44:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 	snapshotPreTransfer := env.SnapshotDatabase() | 
					
						
							| 
									
										
										
										
											2015-04-01 10:53:32 +02:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 		addr = crypto.CreateAddress(caller.Address(), nonce) | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 		from = env.Db().GetAccount(caller.Address()) | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 		to   = env.Db().CreateAccount(addr) | 
					
						
							| 
									
										
										
										
											2015-04-01 10:53:32 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	if env.ChainConfig().IsEIP158(env.BlockNumber()) { | 
					
						
							|  |  |  | 		env.Db().SetNonce(addr, 1) | 
					
						
							| 
									
										
										
										
											2015-04-01 10:53:32 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 	env.Transfer(from, to, value) | 
					
						
							| 
									
										
										
										
											2014-12-09 20:27:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 	// initialise a new contract and set the code that is to be used by the | 
					
						
							|  |  |  | 	// EVM. The contract is a scoped environment for this execution context | 
					
						
							|  |  |  | 	// only. | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 	contract := vm.NewContract(caller, to, value, gas, gasPrice) | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	contract.SetCallCode(&addr, crypto.Keccak256Hash(code), code) | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 	defer contract.Finalise() | 
					
						
							| 
									
										
										
										
											2015-03-13 13:44:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	ret, err = env.Vm().Run(contract, nil) | 
					
						
							| 
									
										
										
										
											2016-11-11 10:23:30 +01:00
										 |  |  | 	// check whether the max code size has been exceeded | 
					
						
							|  |  |  | 	maxCodeSizeExceeded := len(ret) > params.MaxCodeSize | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 	// if the contract creation ran successfully and no errors were returned | 
					
						
							|  |  |  | 	// calculate the gas required to store the code. If the code could not | 
					
						
							|  |  |  | 	// be stored due to not enough gas set an error and let it be handled | 
					
						
							|  |  |  | 	// by the error checking condition below. | 
					
						
							| 
									
										
										
										
											2016-11-11 10:23:30 +01:00
										 |  |  | 	if err == nil && !maxCodeSizeExceeded { | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 		dataGas := big.NewInt(int64(len(ret))) | 
					
						
							|  |  |  | 		dataGas.Mul(dataGas, params.CreateDataGas) | 
					
						
							|  |  |  | 		if contract.UseGas(dataGas) { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 			env.Db().SetCode(addr, ret) | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 			err = vm.CodeStoreOutOfGasError | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// When an error was returned by the EVM or when setting the creation code | 
					
						
							|  |  |  | 	// above we revert to the snapshot and consume any gas remaining. Additionally | 
					
						
							|  |  |  | 	// when we're in homestead this also counts for code storage gas errors. | 
					
						
							| 
									
										
										
										
											2016-11-11 10:23:30 +01:00
										 |  |  | 	if maxCodeSizeExceeded || | 
					
						
							|  |  |  | 		(err != nil && (env.ChainConfig().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError)) { | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 		contract.UseGas(contract.Gas) | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 		env.RevertToSnapshot(snapshotPreTransfer) | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Nothing should be returned when an error is thrown. | 
					
						
							|  |  |  | 		return nil, addr, err | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	return ret, addr, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | // DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope | 
					
						
							|  |  |  | func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) { | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	// Depth check execution. Fail if we're trying to execute above the | 
					
						
							|  |  |  | 	// limit. | 
					
						
							|  |  |  | 	if env.Depth() > int(params.CallCreateDepth.Int64()) { | 
					
						
							|  |  |  | 		caller.ReturnGas(gas, gasPrice) | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 		return nil, vm.DepthError | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-29 11:44:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		snapshot = env.SnapshotDatabase() | 
					
						
							|  |  |  | 		to       = env.Db().GetAccount(caller.Address()) | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2014-12-03 17:06:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 	// Iinitialise a new contract and make initialise the delegate values | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	contract := vm.NewContract(caller, to, caller.Value(), gas, gasPrice).AsDelegate() | 
					
						
							|  |  |  | 	contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr)) | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 	defer contract.Finalise() | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	ret, err = env.Vm().Run(contract, input) | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 		contract.UseGas(contract.Gas) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-04 12:36:02 +02:00
										 |  |  | 		env.RevertToSnapshot(snapshot) | 
					
						
							| 
									
										
										
										
											2015-11-27 15:40:29 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-19 23:50:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	return ret, err | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // generic transfer method | 
					
						
							| 
									
										
										
										
											2015-10-06 12:35:05 +02:00
										 |  |  | func Transfer(from, to vm.Account, amount *big.Int) { | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 	from.SubBalance(amount) | 
					
						
							|  |  |  | 	to.AddBalance(amount) | 
					
						
							| 
									
										
										
										
											2014-12-03 17:06:54 +01:00
										 |  |  | } |