| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-10 00:25:27 +01:00
										 |  |  | package vm | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-04-03 11:27:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2015-03-10 00:25:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-16 21:46:47 +01:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	GasQuickStep   = big.NewInt(2) | 
					
						
							|  |  |  | 	GasFastestStep = big.NewInt(3) | 
					
						
							|  |  |  | 	GasFastStep    = big.NewInt(5) | 
					
						
							|  |  |  | 	GasMidStep     = big.NewInt(8) | 
					
						
							|  |  |  | 	GasSlowStep    = big.NewInt(10) | 
					
						
							|  |  |  | 	GasExtStep     = big.NewInt(20) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-02 05:17:15 +02:00
										 |  |  | 	GasReturn = big.NewInt(0) | 
					
						
							|  |  |  | 	GasStop   = big.NewInt(0) | 
					
						
							| 
									
										
										
										
											2015-03-16 21:46:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-02 05:17:15 +02:00
										 |  |  | 	GasContractByte = big.NewInt(200) | 
					
						
							| 
									
										
										
										
											2016-10-08 00:23:45 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	n64 = big.NewInt(64) | 
					
						
							| 
									
										
										
										
											2015-03-16 21:46:47 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-08 00:23:45 +02:00
										 |  |  | // calcGas returns the actual gas cost of the call. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The cost of gas was changed during the homestead price change HF. To allow for EIP150 | 
					
						
							|  |  |  | // to be implemented. The returned gas is gas - base * 63 / 64. | 
					
						
							|  |  |  | func callGas(gasTable params.GasTable, availableGas, base, callCost *big.Int) *big.Int { | 
					
						
							|  |  |  | 	if gasTable.CreateBySuicide != nil { | 
					
						
							|  |  |  | 		availableGas = new(big.Int).Sub(availableGas, base) | 
					
						
							|  |  |  | 		g := new(big.Int).Div(availableGas, n64) | 
					
						
							|  |  |  | 		g.Sub(availableGas, g) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if g.Cmp(callCost) < 0 { | 
					
						
							|  |  |  | 			return g | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return callCost | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | // baseCheck checks for any stack error underflows | 
					
						
							| 
									
										
										
										
											2016-08-19 15:19:51 +01:00
										 |  |  | func baseCheck(op OpCode, stack *Stack, gas *big.Int) error { | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | 	// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit | 
					
						
							|  |  |  | 	// PUSH is also allowed to calculate the same price for all PUSHes | 
					
						
							|  |  |  | 	// DUP requirements are handled elsewhere (except for the stack limit check) | 
					
						
							|  |  |  | 	if op >= PUSH1 && op <= PUSH32 { | 
					
						
							|  |  |  | 		op = PUSH1 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-27 16:53:05 +01:00
										 |  |  | 	if op >= DUP1 && op <= DUP16 { | 
					
						
							|  |  |  | 		op = DUP1 | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-10 00:25:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if r, ok := _baseCheck[op]; ok { | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | 		err := stack.require(r.stackPop) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-17 23:09:36 +02:00
										 |  |  | 		if r.stackPush > 0 && stack.len()-r.stackPop+r.stackPush > int(params.StackLimit.Int64()) { | 
					
						
							|  |  |  | 			return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64()) | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-10 00:25:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		gas.Add(gas, r.gas) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-03-10 00:25:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | // casts a arbitrary number to the amount of words (sets of 32 bytes) | 
					
						
							| 
									
										
										
										
											2015-03-10 00:25:27 +01:00
										 |  |  | func toWordSize(size *big.Int) *big.Int { | 
					
						
							|  |  |  | 	tmp := new(big.Int) | 
					
						
							|  |  |  | 	tmp.Add(size, u256(31)) | 
					
						
							|  |  |  | 	tmp.Div(tmp, u256(32)) | 
					
						
							|  |  |  | 	return tmp | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | type req struct { | 
					
						
							|  |  |  | 	stackPop  int | 
					
						
							|  |  |  | 	gas       *big.Int | 
					
						
							| 
									
										
										
										
											2015-04-03 12:28:55 +02:00
										 |  |  | 	stackPush int | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var _baseCheck = map[OpCode]req{ | 
					
						
							|  |  |  | 	// opcode  |  stack pop | gas price | stack push | 
					
						
							| 
									
										
										
										
											2015-04-03 12:28:55 +02:00
										 |  |  | 	ADD:          {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	LT:           {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	GT:           {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	SLT:          {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	SGT:          {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	EQ:           {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	ISZERO:       {1, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	SUB:          {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	AND:          {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	OR:           {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	XOR:          {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	NOT:          {1, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	BYTE:         {2, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	CALLDATALOAD: {1, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	CALLDATACOPY: {3, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	MLOAD:        {1, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	MSTORE:       {2, GasFastestStep, 0}, | 
					
						
							|  |  |  | 	MSTORE8:      {2, GasFastestStep, 0}, | 
					
						
							|  |  |  | 	CODECOPY:     {3, GasFastestStep, 0}, | 
					
						
							|  |  |  | 	MUL:          {2, GasFastStep, 1}, | 
					
						
							|  |  |  | 	DIV:          {2, GasFastStep, 1}, | 
					
						
							|  |  |  | 	SDIV:         {2, GasFastStep, 1}, | 
					
						
							|  |  |  | 	MOD:          {2, GasFastStep, 1}, | 
					
						
							|  |  |  | 	SMOD:         {2, GasFastStep, 1}, | 
					
						
							|  |  |  | 	SIGNEXTEND:   {2, GasFastStep, 1}, | 
					
						
							|  |  |  | 	ADDMOD:       {3, GasMidStep, 1}, | 
					
						
							|  |  |  | 	MULMOD:       {3, GasMidStep, 1}, | 
					
						
							|  |  |  | 	JUMP:         {1, GasMidStep, 0}, | 
					
						
							|  |  |  | 	JUMPI:        {2, GasSlowStep, 0}, | 
					
						
							|  |  |  | 	EXP:          {2, GasSlowStep, 1}, | 
					
						
							|  |  |  | 	ADDRESS:      {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	ORIGIN:       {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	CALLER:       {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	CALLVALUE:    {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	CODESIZE:     {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	GASPRICE:     {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	COINBASE:     {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	TIMESTAMP:    {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	NUMBER:       {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	CALLDATASIZE: {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	DIFFICULTY:   {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	GASLIMIT:     {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	POP:          {1, GasQuickStep, 0}, | 
					
						
							|  |  |  | 	PC:           {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	MSIZE:        {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	GAS:          {0, GasQuickStep, 1}, | 
					
						
							|  |  |  | 	BLOCKHASH:    {1, GasExtStep, 1}, | 
					
						
							| 
									
										
										
										
											2016-10-08 00:23:45 +02:00
										 |  |  | 	BALANCE:      {1, Zero, 1}, | 
					
						
							|  |  |  | 	EXTCODESIZE:  {1, Zero, 1}, | 
					
						
							|  |  |  | 	EXTCODECOPY:  {4, Zero, 0}, | 
					
						
							| 
									
										
										
										
											2015-04-03 12:28:55 +02:00
										 |  |  | 	SLOAD:        {1, params.SloadGas, 1}, | 
					
						
							|  |  |  | 	SSTORE:       {2, Zero, 0}, | 
					
						
							|  |  |  | 	SHA3:         {2, params.Sha3Gas, 1}, | 
					
						
							|  |  |  | 	CREATE:       {3, params.CreateGas, 1}, | 
					
						
							| 
									
										
										
										
											2016-10-08 00:23:45 +02:00
										 |  |  | 	// Zero is calculated in the gasSwitch | 
					
						
							|  |  |  | 	CALL:         {7, Zero, 1}, | 
					
						
							|  |  |  | 	CALLCODE:     {7, Zero, 1}, | 
					
						
							|  |  |  | 	DELEGATECALL: {6, Zero, 1}, | 
					
						
							| 
									
										
										
										
											2015-04-03 12:28:55 +02:00
										 |  |  | 	SUICIDE:      {1, Zero, 0}, | 
					
						
							| 
									
										
										
										
											2016-10-08 00:23:45 +02:00
										 |  |  | 	JUMPDEST:     {0, params.JumpdestGas, 0}, | 
					
						
							| 
									
										
										
										
											2015-04-03 12:28:55 +02:00
										 |  |  | 	RETURN:       {2, Zero, 0}, | 
					
						
							|  |  |  | 	PUSH1:        {0, GasFastestStep, 1}, | 
					
						
							|  |  |  | 	DUP1:         {0, Zero, 1}, | 
					
						
							| 
									
										
										
										
											2015-03-27 16:09:57 +01:00
										 |  |  | } |