1 /*
2 	This file is part of solidity.
3 
4 	solidity is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU 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 	solidity 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 General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18 
19 #include <libevmasm/GasMeter.h>
20 
21 #include <libevmasm/KnownState.h>
22 
23 using namespace std;
24 using namespace solidity;
25 using namespace solidity::util;
26 using namespace solidity::evmasm;
27 
operator +=(GasConsumption const & _other)28 GasMeter::GasConsumption& GasMeter::GasConsumption::operator+=(GasConsumption const& _other)
29 {
30 	if (_other.isInfinite && !isInfinite)
31 		*this = infinite();
32 	if (isInfinite)
33 		return *this;
34 	bigint v = bigint(value) + _other.value;
35 	if (v > numeric_limits<u256>::max())
36 		*this = infinite();
37 	else
38 		value = u256(v);
39 	return *this;
40 }
41 
estimateMax(AssemblyItem const & _item,bool _includeExternalCosts)42 GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _includeExternalCosts)
43 {
44 	GasConsumption gas;
45 	switch (_item.type())
46 	{
47 	case Push:
48 	case PushTag:
49 	case PushData:
50 	case PushSub:
51 	case PushSubSize:
52 	case PushProgramSize:
53 	case PushLibraryAddress:
54 	case PushDeployTimeAddress:
55 		gas = runGas(Instruction::PUSH1);
56 		break;
57 	case Tag:
58 		gas = runGas(Instruction::JUMPDEST);
59 		break;
60 	case Operation:
61 	{
62 		ExpressionClasses& classes = m_state->expressionClasses();
63 		switch (_item.instruction())
64 		{
65 		case Instruction::SSTORE:
66 		{
67 			ExpressionClasses::Id slot = m_state->relativeStackElement(0);
68 			ExpressionClasses::Id value = m_state->relativeStackElement(-1);
69 			if (classes.knownZero(value) || (
70 				m_state->storageContent().count(slot) &&
71 				classes.knownNonZero(m_state->storageContent().at(slot))
72 			))
73 				gas = GasCosts::totalSstoreResetGas(m_evmVersion); //@todo take refunds into account
74 			else
75 				gas = GasCosts::totalSstoreSetGas(m_evmVersion);
76 			break;
77 		}
78 		case Instruction::SLOAD:
79 			gas = GasCosts::sloadGas(m_evmVersion);
80 			break;
81 		case Instruction::RETURN:
82 		case Instruction::REVERT:
83 			gas = runGas(_item.instruction());
84 			gas += memoryGas(0, -1);
85 			break;
86 		case Instruction::MLOAD:
87 		case Instruction::MSTORE:
88 			gas = runGas(_item.instruction());
89 			gas += memoryGas(classes.find(Instruction::ADD, {
90 				m_state->relativeStackElement(0),
91 				classes.find(AssemblyItem(32))
92 			}));
93 			break;
94 		case Instruction::MSTORE8:
95 			gas = runGas(_item.instruction());
96 			gas += memoryGas(classes.find(Instruction::ADD, {
97 				m_state->relativeStackElement(0),
98 				classes.find(AssemblyItem(1))
99 			}));
100 			break;
101 		case Instruction::KECCAK256:
102 			gas = GasCosts::keccak256Gas;
103 			gas += memoryGas(0, -1);
104 			gas += wordGas(GasCosts::keccak256WordGas, m_state->relativeStackElement(-1));
105 			break;
106 		case Instruction::CALLDATACOPY:
107 		case Instruction::CODECOPY:
108 		case Instruction::RETURNDATACOPY:
109 			gas = runGas(_item.instruction());
110 			gas += memoryGas(0, -2);
111 			gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2));
112 			break;
113 		case Instruction::EXTCODESIZE:
114 			gas = GasCosts::extCodeGas(m_evmVersion);
115 			break;
116 		case Instruction::EXTCODEHASH:
117 			gas = GasCosts::balanceGas(m_evmVersion);
118 			break;
119 		case Instruction::EXTCODECOPY:
120 			gas = GasCosts::extCodeGas(m_evmVersion);
121 			gas += memoryGas(-1, -3);
122 			gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3));
123 			break;
124 		case Instruction::LOG0:
125 		case Instruction::LOG1:
126 		case Instruction::LOG2:
127 		case Instruction::LOG3:
128 		case Instruction::LOG4:
129 		{
130 			gas = GasCosts::logGas + GasCosts::logTopicGas * getLogNumber(_item.instruction());
131 			gas += memoryGas(0, -1);
132 			if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
133 				gas += GasCosts::logDataGas * (*value);
134 			else
135 				gas = GasConsumption::infinite();
136 			break;
137 		}
138 		case Instruction::CALL:
139 		case Instruction::CALLCODE:
140 		case Instruction::DELEGATECALL:
141 		case Instruction::STATICCALL:
142 		{
143 			if (_includeExternalCosts)
144 				// We assume that we do not know the target contract and thus, the consumption is infinite.
145 				gas = GasConsumption::infinite();
146 			else
147 			{
148 				gas = GasCosts::callGas(m_evmVersion);
149 				if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(0)))
150 					gas += (*value);
151 				else
152 					gas = GasConsumption::infinite();
153 				if (_item.instruction() == Instruction::CALL)
154 					gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
155 				int valueSize = 1;
156 				if (_item.instruction() == Instruction::DELEGATECALL || _item.instruction() == Instruction::STATICCALL)
157 					valueSize = 0;
158 				else if (!classes.knownZero(m_state->relativeStackElement(-1 - valueSize)))
159 					gas += GasCosts::callValueTransferGas;
160 				gas += memoryGas(-2 - valueSize, -3 - valueSize);
161 				gas += memoryGas(-4 - valueSize, -5 - valueSize);
162 			}
163 			break;
164 		}
165 		case Instruction::SELFDESTRUCT:
166 			gas = GasCosts::selfdestructGas(m_evmVersion);
167 			gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
168 			break;
169 		case Instruction::CREATE:
170 		case Instruction::CREATE2:
171 			if (_includeExternalCosts)
172 				// We assume that we do not know the target contract and thus, the consumption is infinite.
173 				gas = GasConsumption::infinite();
174 			else
175 			{
176 				gas = GasCosts::createGas;
177 				gas += memoryGas(-1, -2);
178 			}
179 			break;
180 		case Instruction::EXP:
181 			gas = GasCosts::expGas;
182 			if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
183 			{
184 				if (*value)
185 				{
186 					// Note: msb() counts from 0 and throws on 0 as input.
187 					unsigned const significantByteCount  = (boost::multiprecision::msb(*value) + 1 + 7) / 8;
188 					gas += GasCosts::expByteGas(m_evmVersion) * significantByteCount;
189 				}
190 			}
191 			else
192 				gas += GasCosts::expByteGas(m_evmVersion) * 32;
193 			break;
194 		case Instruction::BALANCE:
195 			gas = GasCosts::balanceGas(m_evmVersion);
196 			break;
197 		case Instruction::CHAINID:
198 			gas = runGas(Instruction::CHAINID);
199 			break;
200 		case Instruction::SELFBALANCE:
201 			gas = runGas(Instruction::SELFBALANCE);
202 			break;
203 		default:
204 			gas = runGas(_item.instruction());
205 			break;
206 		}
207 		break;
208 	}
209 	default:
210 		gas = GasConsumption::infinite();
211 		break;
212 	}
213 
214 	m_state->feedItem(_item);
215 	return gas;
216 }
217 
wordGas(u256 const & _multiplier,ExpressionClasses::Id _value)218 GasMeter::GasConsumption GasMeter::wordGas(u256 const& _multiplier, ExpressionClasses::Id _value)
219 {
220 	u256 const* value = m_state->expressionClasses().knownConstant(_value);
221 	if (!value)
222 		return GasConsumption::infinite();
223 	return GasConsumption(_multiplier * ((*value + 31) / 32));
224 }
225 
memoryGas(ExpressionClasses::Id _position)226 GasMeter::GasConsumption GasMeter::memoryGas(ExpressionClasses::Id _position)
227 {
228 	u256 const* value = m_state->expressionClasses().knownConstant(_position);
229 	if (!value)
230 		return GasConsumption::infinite();
231 	if (*value < m_largestMemoryAccess)
232 		return GasConsumption(0);
233 	u256 previous = m_largestMemoryAccess;
234 	m_largestMemoryAccess = *value;
235 	auto memGas = [=](u256 const& pos) -> u256
236 	{
237 		u256 size = (pos + 31) / 32;
238 		return GasCosts::memoryGas * size + size * size / GasCosts::quadCoeffDiv;
239 	};
240 	return memGas(*value) - memGas(previous);
241 }
242 
memoryGas(int _stackPosOffset,int _stackPosSize)243 GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosSize)
244 {
245 	ExpressionClasses& classes = m_state->expressionClasses();
246 	if (classes.knownZero(m_state->relativeStackElement(_stackPosSize)))
247 		return GasConsumption(0);
248 	else
249 		return memoryGas(classes.find(Instruction::ADD, {
250 			m_state->relativeStackElement(_stackPosOffset),
251 			m_state->relativeStackElement(_stackPosSize)
252 		}));
253 }
254 
runGas(Instruction _instruction)255 unsigned GasMeter::runGas(Instruction _instruction)
256 {
257 	if (_instruction == Instruction::JUMPDEST)
258 		return 1;
259 
260 	switch (instructionInfo(_instruction).gasPriceTier)
261 	{
262 	case Tier::Zero:    return GasCosts::tier0Gas;
263 	case Tier::Base:    return GasCosts::tier1Gas;
264 	case Tier::VeryLow: return GasCosts::tier2Gas;
265 	case Tier::Low:     return GasCosts::tier3Gas;
266 	case Tier::Mid:     return GasCosts::tier4Gas;
267 	case Tier::High:    return GasCosts::tier5Gas;
268 	case Tier::Ext:     return GasCosts::tier6Gas;
269 	default: break;
270 	}
271 	assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction).name);
272 	return 0;
273 }
274 
dataGas(bytes const & _data,bool _inCreation,langutil::EVMVersion _evmVersion)275 u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion)
276 {
277 	bigint gas = 0;
278 	if (_inCreation)
279 	{
280 		for (auto b: _data)
281 			gas += (b != 0) ? GasCosts::txDataNonZeroGas(_evmVersion) : GasCosts::txDataZeroGas;
282 	}
283 	else
284 		gas = bigint(GasCosts::createDataGas) * _data.size();
285 	assertThrow(gas < bigint(u256(-1)), OptimizerException, "Gas cost exceeds 256 bits.");
286 	return u256(gas);
287 }
288 
289 
dataGas(uint64_t _length,bool _inCreation,langutil::EVMVersion _evmVersion)290 u256 GasMeter::dataGas(uint64_t _length, bool _inCreation, langutil::EVMVersion _evmVersion)
291 {
292 	bigint gas = bigint(_length) * (_inCreation ? GasCosts::txDataNonZeroGas(_evmVersion) : GasCosts::createDataGas);
293 	assertThrow(gas < bigint(u256(-1)), OptimizerException, "Gas cost exceeds 256 bits.");
294 	return u256(gas);
295 }
296