Coverage Summary for Class: ProgramInvokeImpl (org.ethereum.vm.program.invoke)
Class |
Class, %
|
Method, %
|
Line, %
|
ProgramInvokeImpl |
100%
(1/1)
|
33.3%
(10/30)
|
34.8%
(49/141)
|
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 package org.ethereum.vm.program.invoke;
21
22 import org.ethereum.core.Repository;
23 import org.ethereum.db.BlockStore;
24 import org.ethereum.vm.DataWord;
25 import org.ethereum.vm.program.Program;
26
27 import java.math.BigInteger;
28 import java.util.Arrays;
29 import java.util.Map;
30
31 /**
32 * @author Roman Mandeleil
33 * @since 03.06.2014
34 */
35 public class ProgramInvokeImpl implements ProgramInvoke {
36
37 private BlockStore blockStore;
38 /**
39 * TRANSACTION env **
40 */
41 private final DataWord address;
42 private final DataWord origin;
43 private final DataWord caller;
44 private final DataWord balance;
45 private final DataWord gasPrice;
46 private final DataWord callValue;
47 private long gas;
48
49 byte[] msgData;
50
51 /**
52 * BLOCK env **
53 */
54 private final DataWord prevHash;
55 private final DataWord coinbase;
56 private final DataWord timestamp;
57 private final DataWord number;
58 private final DataWord difficulty;
59 private final DataWord gaslimit;
60
61 private final DataWord transactionIndex;
62
63 private Map<DataWord, DataWord> storage;
64
65 private final Repository repository;
66 private boolean byTransaction = true;
67 private boolean byTestingSuite = false;
68 private int callDeep = 0;
69 private boolean isStaticCall = false;
70
71 public ProgramInvokeImpl(DataWord address, DataWord origin, DataWord caller, DataWord balance,
72 DataWord gasPrice,
73 long gas,
74 DataWord callValue, byte[] msgData,
75 DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number, DataWord transactionIndex, DataWord
76 difficulty,
77 DataWord gaslimit, Repository repository, int callDeep, BlockStore blockStore,
78 boolean isStaticCall,
79 boolean byTestingSuite) {
80
81 // Transaction env
82 this.address = address;
83 this.origin = origin;
84 this.caller = caller;
85 this.balance = balance;
86 this.gasPrice = gasPrice;
87 this.gas = gas;
88 this.callValue = callValue;
89 this.msgData = msgData;
90
91 // last Block env
92 this.prevHash = lastHash;
93 this.coinbase = coinbase;
94 this.timestamp = timestamp;
95 this.number = number;
96 this.transactionIndex = transactionIndex;
97 this.difficulty = difficulty;
98 this.gaslimit = gaslimit;
99
100 this.repository = repository;
101 this.byTransaction = false;
102 this.callDeep = callDeep;
103 this.blockStore = blockStore;
104 this.isStaticCall = isStaticCall;
105 this.byTestingSuite = byTestingSuite;
106 }
107
108 public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance,
109 byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData,
110 byte[] lastHash, byte[] coinbase, long timestamp, long number, int transactionIndex, byte[] difficulty,
111 byte[] gaslimit,
112 Repository repository, BlockStore blockStore,
113 boolean byTestingSuite) {
114 this(address, origin, caller, balance, gasPrice, gas, callValue, msgData, lastHash, coinbase,
115 timestamp, number, transactionIndex, difficulty, gaslimit, repository, blockStore);
116
117 this.byTestingSuite = byTestingSuite;
118 }
119
120
121 public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, byte[] balance,
122 byte[] gasPrice, byte[] gas, byte[] callValue, byte[] msgData,
123 byte[] lastHash, byte[] coinbase, long timestamp, long number, int transactionIndex, byte[] difficulty,
124 byte[] gaslimit,
125 Repository repository, BlockStore blockStore) {
126
127 // Transaction env
128 this.address = DataWord.valueOf(address);
129 this.origin = DataWord.valueOf(origin);
130 this.caller = DataWord.valueOf(caller);
131 this.balance = DataWord.valueOf(balance);
132 this.gasPrice = DataWord.valueOf(gasPrice);
133 this.gas = Program.limitToMaxLong(DataWord.valueOf(gas));
134 this.callValue = DataWord.valueOf(callValue);
135 this.msgData = msgData;
136
137 // last Block env
138 this.prevHash = DataWord.valueOf(lastHash);
139 this.coinbase = DataWord.valueOf(coinbase);
140 this.timestamp = DataWord.valueOf(timestamp);
141 this.number = DataWord.valueOf(number);
142 this.transactionIndex = DataWord.valueOf(transactionIndex);
143 this.difficulty = DataWord.valueOf(difficulty);
144 this.gaslimit = DataWord.valueOf(gaslimit);
145
146 this.repository = repository;
147 this.blockStore = blockStore;
148 }
149
150 /* ADDRESS op */
151 public DataWord getOwnerAddress() {
152 return address;
153 }
154
155 /* BALANCE op */
156 public DataWord getBalance() {
157 return balance;
158 }
159
160 /* ORIGIN op */
161 public DataWord getOriginAddress() {
162 return origin;
163 }
164
165 /* CALLER op */
166 public DataWord getCallerAddress() {
167 return caller;
168 }
169
170 /* GASPRICE op */
171 public DataWord getMinGasPrice() {
172 return gasPrice;
173 }
174
175 /* GAS op */
176 public long getGas() {
177 return gas;
178 }
179
180 /* CALLVALUE op */
181 public DataWord getCallValue() {
182 return callValue;
183 }
184
185 /*****************/
186 /*** msg data ***/
187 /*****************/
188 /* NOTE: In the protocol there is no restriction on the maximum message data,
189 * However msgData here is a byte[] and this can't hold more than 2^32-1
190 */
191 private static BigInteger maxMsgData = BigInteger.valueOf(Integer.MAX_VALUE);
192
193 /* CALLDATALOAD op */
194 public DataWord getDataValue(DataWord indexData) {
195
196 BigInteger tempIndex = indexData.value();
197 int index = tempIndex.intValue(); // possible overflow is caught below
198 int size = 32; // maximum datavalue size
199
200 if (msgData == null || index >= msgData.length
201 || tempIndex.compareTo(maxMsgData) == 1) {
202 return DataWord.ZERO;
203 }
204 if (index + size > msgData.length) {
205 size = msgData.length - index;
206 }
207
208 byte[] data = new byte[32];
209 System.arraycopy(msgData, index, data, 0, size);
210 return DataWord.valueOf(data);
211 }
212
213 /* CALLDATASIZE */
214 public DataWord getDataSize() {
215
216 if (msgData == null || msgData.length == 0) {
217 return DataWord.ZERO;
218 }
219 int size = msgData.length;
220 return DataWord.valueOf(size);
221 }
222
223 /* CALLDATACOPY */
224 public byte[] getDataCopy(DataWord offsetData, DataWord lengthData) {
225
226 int offset = offsetData.intValueSafe();
227 int length = lengthData.intValueSafe();
228
229 byte[] data = new byte[length];
230
231 if (msgData == null) {
232 return data;
233 }
234 if (offset > msgData.length) {
235 return data;
236 }
237 if (offset + length > msgData.length) {
238 length = msgData.length - offset;
239 }
240
241 System.arraycopy(msgData, offset, data, 0, length);
242
243 return data;
244 }
245
246
247 /* PREVHASH op */
248 public DataWord getPrevHash() {
249 return prevHash;
250 }
251
252 /* COINBASE op */
253 public DataWord getCoinbase() {
254 return coinbase;
255 }
256
257 /* TIMESTAMP op */
258 public DataWord getTimestamp() {
259 return timestamp;
260 }
261
262 /* NUMBER op */
263 public DataWord getNumber() {
264 return number;
265 }
266
267 /* TXINDEX op */
268 public DataWord getTransactionIndex() {
269 return transactionIndex;
270 }
271
272 /* DIFFICULTY op */
273 public DataWord getDifficulty() {
274 return difficulty;
275 }
276
277 /* GASLIMIT op */
278 public DataWord getGaslimit() {
279 return gaslimit;
280 }
281
282 /* Storage */
283 public Map<DataWord, DataWord> getStorage() {
284 return storage;
285 }
286
287 public Repository getRepository() {
288 return repository;
289 }
290
291 @Override
292 public BlockStore getBlockStore() {
293 return blockStore;
294 }
295
296 @Override
297 public boolean byTransaction() {
298 return byTransaction;
299 }
300
301 @Override
302 public boolean isStaticCall() {
303 return isStaticCall;
304 }
305
306 @Override
307 public boolean byTestingSuite() {
308 return byTestingSuite;
309 }
310
311 @Override
312 public int getCallDeep() {
313 return this.callDeep;
314 }
315
316 @Override
317 public boolean equals(Object o) {
318 if (this == o) {
319 return true;
320 }
321 if (o == null || getClass() != o.getClass()) {
322 return false;
323 }
324
325 ProgramInvokeImpl that = (ProgramInvokeImpl) o;
326
327 if (byTestingSuite != that.byTestingSuite) {
328 return false;
329 }
330 if (byTransaction != that.byTransaction) {
331 return false;
332 }
333 if (address != null ? !address.equals(that.address) : that.address != null) {
334 return false;
335 }
336 if (balance != null ? !balance.equals(that.balance) : that.balance != null) {
337 return false;
338 }
339 if (callValue != null ? !callValue.equals(that.callValue) : that.callValue != null) {
340 return false;
341 }
342 if (caller != null ? !caller.equals(that.caller) : that.caller != null) {
343 return false;
344 }
345 if (coinbase != null ? !coinbase.equals(that.coinbase) : that.coinbase != null) {
346 return false;
347 }
348 if (difficulty != null ? !difficulty.equals(that.difficulty) : that.difficulty != null) {
349 return false;
350 }
351 if (gas!=that.gas) {
352 return false;
353 }
354 if (gasPrice != null ? !gasPrice.equals(that.gasPrice) : that.gasPrice != null) {
355 return false;
356 }
357 if (gaslimit != null ? !gaslimit.equals(that.gaslimit) : that.gaslimit != null) {
358 return false;
359 }
360 if (!Arrays.equals(msgData, that.msgData)) {
361 return false;
362 }
363 if (number != null ? !number.equals(that.number) : that.number != null) {
364 return false;
365 }
366 if (origin != null ? !origin.equals(that.origin) : that.origin != null) {
367 return false;
368 }
369 if (prevHash != null ? !prevHash.equals(that.prevHash) : that.prevHash != null) {
370 return false;
371 }
372 if (repository != null ? !repository.equals(that.repository) : that.repository != null) {
373 return false;
374 }
375 if (storage != null ? !storage.equals(that.storage) : that.storage != null) {
376 return false;
377 }
378 if (timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null) {
379 return false;
380 }
381
382 return true;
383 }
384
385 @Override
386 public String toString() {
387 return "ProgramInvokeImpl{" +
388 "address=" + address +
389 ", origin=" + origin +
390 ", caller=" + caller +
391 ", balance=" + balance +
392 ", gas=" + gas +
393 ", gasPrice=" + gasPrice +
394 ", callValue=" + callValue +
395 ", msgData=" + Arrays.toString(msgData) +
396 ", prevHash=" + prevHash +
397 ", coinbase=" + coinbase +
398 ", timestamp=" + timestamp +
399 ", number=" + number +
400 ", difficulty=" + difficulty +
401 ", gaslimit=" + gaslimit +
402 ", storage=" + storage +
403 ", repository=" + repository +
404 ", byTransaction=" + byTransaction +
405 ", byTestingSuite=" + byTestingSuite +
406 ", callDeep=" + callDeep +
407 '}';
408 }
409 }