Coverage Summary for Class: GasCost (org.ethereum.vm)
Class |
Method, %
|
Line, %
|
GasCost |
66.7%
(6/9)
|
55%
(22/40)
|
GasCost$InvalidGasException |
0%
(0/4)
|
0%
(0/7)
|
Total |
46.2%
(6/13)
|
46.8%
(22/47)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 package org.ethereum.vm;
22
23 import org.ethereum.util.ByteUtil;
24
25 import java.math.BigInteger;
26
27 /**
28 * The fundamental network cost unit. Paid for exclusively by SBTC, which is converted
29 * freely to and from Gas as required. Gas does not exist outside of the internal RSK
30 * computation engine; its price is set by the Transaction and miners are free to
31 * ignore Transactions whose Gas price is too low.
32 *
33 * GasCost includes static methods to operate on longs which represent Gas. These methods
34 * should always be used when calculating gas.
35 */
36 public class GasCost {
37 /* backwards compatibility, remove eventually */
38 public static final long STEP = 1;
39 public static final long SSTORE = 300;
40 /* backwards compatibility, remove eventually */
41 public static final long ZEROSTEP = 0;
42 public static final long QUICKSTEP = 2;
43 public static final long FASTESTSTEP = 3;
44 public static final long FASTSTEP = 5;
45 public static final long MIDSTEP = 8;
46 public static final long SLOWSTEP = 10;
47 public static final long EXTSTEP = 20;
48
49 public static final long GENESISGASLIMIT = 1000000;
50 public static final long MINGASLIMIT = 125000;
51
52 public static final long BALANCE = 400;
53 public static final long SHA3 = 30;
54 public static final long SHA3_WORD = 6;
55 public static final long SLOAD = 200;
56 public static final long STOP = 0;
57 public static final long SUICIDE = 5000;
58 public static final long CLEAR_SSTORE = 5000;
59 public static final long SET_SSTORE = 20000;
60 public static final long RESET_SSTORE = 5000;
61 public static final long REFUND_SSTORE = 15000;
62 public static final long CREATE = 32000;
63
64 public static final long JUMPDEST = 1;
65 public static final long CREATE_DATA_BYTE = 5;
66 public static final long CALL = 700;
67 public static final long STIPEND_CALL = 2300; // For transferring coins in CALL, this is always passed to child
68 public static final long VT_CALL = 9000; //value transfer call
69 public static final long NEW_ACCT_CALL = 25000; //new account call
70 public static final long MEMORY = 3; // TODO: Memory in V0 is more expensive than V1: This MUST be modified before release
71 public static final long MEMORY_V1 =3;
72 public static final long SUICIDE_REFUND = 24000;
73 public static final long QUAD_COEFF_DIV = 512;
74 public static final long CREATE_DATA = 200; // paid for each new byte of code
75 public static final long REPLACE_DATA = 50; // paid for each byte of code replaced
76 public static final long TX_NO_ZERO_DATA = 68;
77 public static final long TX_ZERO_DATA = 4;
78 public static final long TRANSACTION = 21000;
79 public static final long TRANSACTION_DEFAULT = 90000; //compatibility with ethereum (mmarquez)
80 public static final long TRANSACTION_CREATE_CONTRACT = 53000;
81 public static final long LOG_GAS = 375;
82 public static final long LOG_DATA_GAS = 8;
83 public static final long LOG_TOPIC_GAS = 375;
84 public static final long COPY_GAS = 3;
85 public static final long EXP_GAS = 10;
86 public static final long EXP_BYTE_GAS = 50;
87 public static final long IDENTITY = 15;
88 public static final long IDENTITY_WORD = 3;
89 public static final long RIPEMD160 = 600;
90 public static final long RIPEMD160_WORD = 120;
91 public static final long SHA256 = 60;
92 public static final long SHA256_WORD = 12;
93 public static final long EC_RECOVER = 3000;
94 public static final long EXT_CODE_SIZE = 700;
95 public static final long EXT_CODE_COPY = 700;
96 public static final long EXT_CODE_HASH = 400;
97 public static final long CODEREPLACE = 15000;
98 public static final long NEW_ACCT_SUICIDE = 25000;
99 public static final long RETURN = 0;
100
101 public static final long MAX_GAS = Long.MAX_VALUE;
102
103 /**
104 * An exception which is thrown be methods in GasCost when
105 * an operation overflows, has invalid inputs or wants to return
106 * an invalid gas value.
107 */
108 public static class InvalidGasException extends IllegalArgumentException {
109
110 private InvalidGasException(long invalidValue) {
111 super(String.format("Got invalid gas value: %d", invalidValue));
112 }
113
114 private InvalidGasException(byte[] bytes) {
115 super(String.format("Got invalid gas value as bytes array: %s", ByteUtil.toHexStringOrEmpty(bytes)));
116 }
117
118 private InvalidGasException(String str) {
119 super(String.format("Got invalid gas value, tried operation: %s", str));
120 }
121
122 }
123
124 // Everything in this class should be static, do not initialize.
125 private GasCost() { }
126
127 /**
128 * Converts a byte array to gas. Byte arrays are signed two bit compliments.
129 * The byte array must have at most 8 values in it so as to fit in a long.
130 * Be careful so as not to send a negative byte array.
131 * @param bytes represents the number which will be converted to gas.
132 * @return the gas equivalent of the byte array.
133 * @throws InvalidGasException if the array has more than 8 values or
134 * is negative.
135 */
136 public static long toGas(byte[] bytes) throws InvalidGasException {
137 if (bytes.length > 8) {
138 return Long.MAX_VALUE;
139 }
140 long result = ByteUtil.byteArrayToLong(bytes);
141 if (result < 0) {
142 throw new InvalidGasException(bytes);
143 }
144 return result;
145 }
146
147 /**
148 * Convert a BigInteger to gas.
149 * @throws InvalidGasException if the big integer is negative or is bigger than Long.MAX_VALUE.
150 */
151 public static long toGas(BigInteger big) throws InvalidGasException {
152 if (big.compareTo(BigInteger.ZERO) < 0) {
153 throw new InvalidGasException(big.toByteArray());
154 }
155 return toGas(big.toByteArray());
156 }
157
158 /**
159 * Make sure the number is a valid gas value.
160 * @return: the number, if is positive or zero.
161 * @throws InvalidGasException if the number is negative.
162 */
163 public static long toGas(long number) throws InvalidGasException {
164 if (number < 0) {
165 throw new InvalidGasException(number);
166 }
167 return number;
168 }
169
170 /**
171 * Adds two longs numbers representing gas, capping at Long.MAX_VALUE.
172 * @param x some gas.
173 * @param y another gas.
174 * @return the sum of the two numbers, capped.
175 * @throws InvalidGasException if any of the inputs is negative
176 */
177 public static long add(long x, long y) throws InvalidGasException {
178 if (x < 0 || y < 0) {
179 throw new InvalidGasException(String.format("%d + %d", x, y));
180 }
181 long result = x + y;
182 if (result < 0) {
183 return Long.MAX_VALUE;
184 }
185 return result;
186 }
187
188 /**
189 * Multply two longs representing gas, capping at Long.MAX_VALUE.
190 * @param x some gas.
191 * @param y another gas.
192 * @return the multiplication of the two numbers, capped.
193 * @throws InvalidGasException if any of the inputs is negative
194 */
195 public static long multiply(long x, long y) throws InvalidGasException {
196 if (x < 0 || y < 0) {
197 throw new InvalidGasException(String.format("%d * %d", x, y));
198 }
199 long result = x * y;
200 if (multiplicationOverflowed(x, y, result)) {
201 return Long.MAX_VALUE;
202 }
203 return result;
204 }
205
206 /**
207 * Subtracts two longs representing gas.
208 * @throws InvalidGasException if any of the inputs are negative or the
209 * result of the subtraction is negative.
210 */
211 public static long subtract(long x, long y) throws InvalidGasException {
212 if (y < 0 || y > x) {
213 throw new InvalidGasException(String.format("%d - %d", x, y));
214 }
215 return x - y;
216 }
217
218 /**
219 * Calculate the total gas cost given a baseline cost, the cost of an unit and how many units
220 * are passed. The operation is capped at Long.MAX_VALUE.
221 * @param baseCost a baseline cost.
222 * @param unitCost the cost of a single unit.
223 * @param units how many units.
224 * @return baseCost + unitCost * units, capped at Long.MAX_VALUE
225 * @throws InvalidGasException if any of the inputs are negative.
226 */
227 public static long calculateTotal(long baseCost, long unitCost, long units) throws InvalidGasException {
228 if (baseCost < 0 || unitCost < 0 || units < 0) {
229 throw new InvalidGasException(String.format("%d + %d * %d", baseCost, unitCost, units));
230 }
231 long mult = unitCost * units;
232 if (multiplicationOverflowed(unitCost, units, mult)) {
233 return Long.MAX_VALUE;
234 }
235 long result = baseCost + mult;
236 if (result < 0) {
237 return Long.MAX_VALUE;
238 }
239 return result;
240 }
241
242 /**
243 * Returns whether r is overflowed in `x * y = r`
244 * Both x and y must be positive.
245 */
246 private static boolean multiplicationOverflowed(long x, long y, long result) {
247 // Heavily inspired on Math.multiplyExact
248 // https://github.com/frohoff/jdk8u-jdk/blob/master/src/share/classes/java/lang/Math.java#L882/
249 // changed because a precondition states that both x and y must be positive.
250 if (((x | y) >>> 31 != 0)) {
251 // Some bits greater than 2^31 that might cause overflow
252 // Check the result using the divide operator
253 // and check for the special case of Long.MIN_VALUE * -1
254 return (y != 0) && (result/ y != x);
255 }
256 return false;
257 }
258 }