Coverage Summary for Class: ProgramResult (org.ethereum.vm.program)
Class |
Class, %
|
Method, %
|
Line, %
|
ProgramResult |
100%
(1/1)
|
40.6%
(13/32)
|
30.2%
(26/86)
|
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;
21
22 import org.ethereum.core.Transaction;
23 import org.ethereum.vm.CallCreate;
24 import org.ethereum.vm.DataWord;
25 import org.ethereum.vm.GasCost;
26 import org.ethereum.vm.LogInfo;
27
28 import java.util.*;
29
30 import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
31
32 /**
33 * @author Roman Mandeleil
34 * @since 07.06.2014
35 */
36 public class ProgramResult {
37
38 private long gasUsed;
39 private byte[] hReturn = EMPTY_BYTE_ARRAY;
40 private Exception exception;
41 private boolean revert;
42
43 // Important:
44 // DataWord is used as a ByteArrayWrapper, because Java data Maps/Sets cannot distiguish duplicate
45 // keys if the key is of type byte[].
46 private Map<DataWord, byte[]> codeChanges;
47
48 private Set<DataWord> deleteAccounts;
49 private List<InternalTransaction> internalTransactions;
50 private List<LogInfo> logInfoList;
51 private long futureRefund = 0;
52
53 /*
54 * for testing runs ,
55 * call/create is not executed
56 * but dummy recorded
57 */
58 private List<CallCreate> callCreateList;
59
60 public void clearUsedGas() {
61 gasUsed = 0;
62 }
63
64 public void spendGas(long gas) {
65 gasUsed = GasCost.add(gasUsed, gas);
66 }
67
68 public void setRevert() {
69 this.revert = true;
70 }
71
72 public boolean isRevert() {
73 return revert;
74 }
75
76 public void refundGas(long gas) {
77 gasUsed = GasCost.subtract(gasUsed, gas);
78 }
79
80 public void setHReturn(byte[] hReturn) {
81 this.hReturn = hReturn;
82
83 }
84
85 public byte[] getHReturn() {
86 return hReturn;
87 }
88
89 public Exception getException() {
90 return exception;
91 }
92
93 public long getGasUsed() {
94 return gasUsed;
95 }
96
97 public void setException(Exception exception) {
98 this.exception = exception;
99 }
100
101
102 public Set<DataWord> getDeleteAccounts() {
103 if (deleteAccounts == null) {
104 deleteAccounts = new HashSet<>();
105 }
106 return deleteAccounts;
107 }
108
109 public Map<DataWord, byte[]> getCodeChanges() {
110 if (codeChanges == null) {
111 codeChanges = new HashMap<>();
112 }
113 return codeChanges;
114 }
115
116 public void addCodeChange(DataWord addr, byte[] newCode) {
117 getCodeChanges().put(addr, newCode);
118 }
119
120
121 public void addDeleteAccount(DataWord address) {
122 getDeleteAccounts().add(address);
123 }
124
125 public void addDeleteAccounts(Set<DataWord> accounts) {
126 getDeleteAccounts().addAll(accounts);
127 }
128
129 public void clearFieldsOnException() {
130 if (deleteAccounts!=null) {
131 deleteAccounts.clear();
132 }
133 if (logInfoList!=null) {
134 logInfoList.clear();
135 }
136 if (codeChanges!=null) {
137 codeChanges.clear();
138 }
139 resetFutureRefund();
140 }
141
142
143 public List<LogInfo> getLogInfoList() {
144 if (logInfoList == null) {
145 logInfoList = new ArrayList<>();
146 }
147 return logInfoList;
148 }
149
150 public void addLogInfo(LogInfo logInfo) {
151 getLogInfoList().add(logInfo);
152 }
153
154 public void addLogInfos(List<LogInfo> logInfos) {
155 getLogInfoList().addAll(logInfos);
156 }
157
158 public List<CallCreate> getCallCreateList() {
159 if (callCreateList == null) {
160 callCreateList = new ArrayList<>();
161 }
162 return callCreateList;
163 }
164
165 public void addCallCreate(byte[] data, byte[] destination, long gasLimit, byte[] value) {
166 getCallCreateList().add(new CallCreate(data, destination, gasLimit, value));
167 }
168
169 public List<InternalTransaction> getInternalTransactions() {
170 if (internalTransactions == null) {
171 internalTransactions = new ArrayList<>();
172 }
173 return internalTransactions;
174 }
175
176 public InternalTransaction addInternalTransaction(
177 Transaction parentTransaction,
178 int deep,
179 byte[] nonce,
180 DataWord gasPrice,
181 DataWord gasLimit,
182 byte[] senderAddress,
183 byte[] receiveAddress,
184 byte[] value,
185 byte[] data,
186 String note
187 ) {
188 byte[] parentHash = parentTransaction.getHash().getBytes();
189 byte[] originHash = parentHash;
190 if (parentTransaction instanceof InternalTransaction) {
191 originHash = ((InternalTransaction) parentTransaction).getOriginHash();
192 }
193 InternalTransaction transaction = new InternalTransaction(
194 originHash,
195 parentHash,
196 deep,
197 getInternalTransactions().size(),
198 nonce,
199 gasPrice,
200 gasLimit,
201 senderAddress,
202 receiveAddress,
203 value,
204 data,
205 note
206 );
207 getInternalTransactions().add(transaction);
208 return transaction;
209 }
210
211 public void addInternalTransactions(List<InternalTransaction> internalTransactions) {
212 getInternalTransactions().addAll(internalTransactions);
213 }
214
215 public void rejectInternalTransactions() {
216 for (InternalTransaction internalTx : getInternalTransactions()) {
217 internalTx.reject();
218 }
219 }
220
221 public void rejectLogInfos() {
222 for (LogInfo logInfo : getLogInfoList()) {
223 logInfo.reject();
224 }
225 }
226
227 public void addFutureRefund(long gasValue) {
228 futureRefund += gasValue;
229 }
230
231 public long getFutureRefund() {
232 return futureRefund;
233 }
234
235 public void resetFutureRefund() {
236 futureRefund = 0;
237 }
238
239 public void merge(ProgramResult another) {
240 addInternalTransactions(another.getInternalTransactions());
241 if (another.getException() == null && !another.isRevert()) {
242 addDeleteAccounts(another.getDeleteAccounts());
243 addLogInfos(another.getLogInfoList());
244 addFutureRefund(another.getFutureRefund());
245 }
246 }
247
248 public static ProgramResult empty() {
249 ProgramResult result = new ProgramResult();
250 result.setHReturn(EMPTY_BYTE_ARRAY);
251 return result;
252 }
253 }