Coverage Summary for Class: TransactionReceipt (org.ethereum.core)
Class |
Class, %
|
Method, %
|
Line, %
|
TransactionReceipt |
100%
(1/1)
|
65.4%
(17/26)
|
66%
(68/103)
|
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.core;
21
22 import org.bouncycastle.util.BigIntegers;
23 import org.ethereum.util.*;
24 import org.ethereum.vm.LogInfo;
25
26 import java.math.BigInteger;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.List;
30
31 import static co.rsk.util.ListArrayUtil.nullToEmpty;
32 import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
33
34 /**
35 * The transaction receipt is a tuple of three items
36 * comprising the transaction, together with the post-transaction state,
37 * and the cumulative gas used in the block containing the transaction receipt
38 * as of immediately after the transaction has happened,
39 */
40 public class TransactionReceipt {
41
42 private Transaction transaction;
43
44 protected static final byte[] FAILED_STATUS = EMPTY_BYTE_ARRAY;
45 protected static final byte[] SUCCESS_STATUS = new byte[]{0x01};
46
47 private byte[] postTxState = EMPTY_BYTE_ARRAY;
48 private byte[] cumulativeGas = EMPTY_BYTE_ARRAY;
49 private byte[] gasUsed = EMPTY_BYTE_ARRAY;
50 private byte[] status = EMPTY_BYTE_ARRAY;
51
52 private Bloom bloomFilter = new Bloom();
53 private List<LogInfo> logInfoList = new ArrayList<>();
54
55 /* Tx Receipt in encoded form */
56 private byte[] rlpEncoded;
57
58 public TransactionReceipt() {
59 }
60
61 public TransactionReceipt(byte[] rlp) {
62
63 ArrayList<RLPElement> params = RLP.decode2(rlp);
64 RLPList receipt = (RLPList) params.get(0);
65
66 RLPItem postTxStateRLP = (RLPItem) receipt.get(0);
67 RLPItem cumulativeGasRLP = (RLPItem) receipt.get(1);
68 RLPItem bloomRLP = (RLPItem) receipt.get(2);
69 RLPList logs = (RLPList) receipt.get(3);
70 RLPItem gasUsedRLP = (RLPItem) receipt.get(4);
71
72 postTxState = nullToEmpty(postTxStateRLP.getRLPData());
73 cumulativeGas = cumulativeGasRLP.getRLPData() == null ? EMPTY_BYTE_ARRAY : cumulativeGasRLP.getRLPData();
74 bloomFilter = new Bloom(bloomRLP.getRLPData());
75 gasUsed = gasUsedRLP.getRLPData() == null ? EMPTY_BYTE_ARRAY : gasUsedRLP.getRLPData();
76
77 if (receipt.size() > 5 ) {
78 byte[] transactionStatus = nullToEmpty(receipt.get(5).getRLPData());
79 this.status = transactionStatus;
80 }
81
82 for (int k = 0; k < logs.size(); k++) {
83 RLPElement log = logs.get(k);
84 LogInfo logInfo = new LogInfo(log.getRLPData());
85 logInfoList.add(logInfo);
86 }
87
88 rlpEncoded = rlp;
89 }
90
91
92 public TransactionReceipt(byte[] postTxState, byte[] cumulativeGas, byte[] gasUsed,
93 Bloom bloomFilter, List<LogInfo> logInfoList, byte[] status) {
94 this.postTxState = postTxState;
95 this.cumulativeGas = cumulativeGas;
96 this.gasUsed = gasUsed;
97 this.bloomFilter = bloomFilter;
98 this.logInfoList = logInfoList;
99 if (Arrays.equals(status, FAILED_STATUS) || Arrays.equals(status, SUCCESS_STATUS)) {
100 this.status = status;
101 }
102 }
103
104 public byte[] getPostTxState() {
105 return postTxState;
106 }
107
108 public byte[] getCumulativeGas() {
109 return cumulativeGas;
110 }
111
112 // TODO: return gas used for this transaction instead of cumulative gas
113 public byte[] getGasUsed() {
114 return gasUsed;
115 }
116
117 public long getCumulativeGasLong() {
118 return new BigInteger(1, cumulativeGas).longValue();
119 }
120
121
122 public Bloom getBloomFilter() {
123 return bloomFilter;
124 }
125
126 public List<LogInfo> getLogInfoList() {
127 return logInfoList;
128 }
129
130 /* [postTxState, cumulativeGas, bloomFilter, logInfoList] */
131 public byte[] getEncoded() {
132
133 if (rlpEncoded != null) {
134 return rlpEncoded;
135 }
136
137 byte[] postTxStateRLP = RLP.encodeElement(this.postTxState);
138 byte[] cumulativeGasRLP = RLP.encodeElement(this.cumulativeGas);
139 byte[] gasUsedRLP = RLP.encodeElement(this.gasUsed);
140 byte[] bloomRLP = RLP.encodeElement(this.bloomFilter.getData());
141 byte[] statusRLP = RLP.encodeElement(this.status);
142
143 final byte[] logInfoListRLP;
144 if (logInfoList != null) {
145 byte[][] logInfoListE = new byte[logInfoList.size()][];
146
147 int i = 0;
148 for (LogInfo logInfo : logInfoList) {
149 logInfoListE[i] = logInfo.getEncoded();
150 ++i;
151 }
152 logInfoListRLP = RLP.encodeList(logInfoListE);
153 } else {
154 logInfoListRLP = RLP.encodeList();
155 }
156
157 rlpEncoded = RLP.encodeList(postTxStateRLP, cumulativeGasRLP, bloomRLP, logInfoListRLP, gasUsedRLP, statusRLP);
158
159 return rlpEncoded;
160 }
161
162 public void setStatus(byte[] status) {
163 if (Arrays.equals(status, FAILED_STATUS)){
164 this.status = FAILED_STATUS;
165 } else if (Arrays.equals(status, SUCCESS_STATUS)){
166 this.status = SUCCESS_STATUS;
167 }
168 }
169
170 public boolean isSuccessful() {
171 return Arrays.equals(this.status, SUCCESS_STATUS);
172 }
173
174 public void setTxStatus(boolean success) {
175 this.postTxState = success ? new byte[]{1} : new byte[0];
176 rlpEncoded = null;
177 }
178
179 public boolean hasTxStatus() {
180 return postTxState != null && postTxState.length <= 1;
181 }
182
183 public boolean isTxStatusOK() {
184 return postTxState != null && postTxState.length == 1 && postTxState[0] == 1;
185 }
186
187 public void setPostTxState(byte[] postTxState) {
188 this.postTxState = postTxState;
189 }
190
191 public void setCumulativeGas(long cumulativeGas) {
192 this.cumulativeGas = BigIntegers.asUnsignedByteArray(BigInteger.valueOf(cumulativeGas));
193 }
194
195 public void setGasUsed(long gasUsed) {
196 this.gasUsed = BigIntegers.asUnsignedByteArray(BigInteger.valueOf(gasUsed));
197 }
198
199 public void setCumulativeGas(byte[] cumulativeGas) {
200 this.cumulativeGas = cumulativeGas;
201 }
202
203 public void setGasUsed(byte[] gasUsed) {
204 this.gasUsed = gasUsed;
205 }
206
207 public void setLogInfoList(List<LogInfo> logInfoList) {
208 if (logInfoList == null) {
209 return;
210 }
211
212 this.rlpEncoded = null;
213 this.logInfoList = logInfoList;
214
215 for (LogInfo loginfo : logInfoList) {
216 bloomFilter.or(loginfo.getBloom());
217 }
218 }
219
220 public void setTransaction(Transaction transaction) {
221 this.transaction = transaction;
222 }
223
224 public Transaction getTransaction() {
225 return transaction;
226 }
227
228 @Override
229 public String toString() {
230
231 // todo: fix that
232
233 return "TransactionReceipt[" +
234 "\n , " + (hasTxStatus() ? ("txStatus=" + (isSuccessful()? "OK" : "FAILED"))
235 : ("postTxState=" + ByteUtil.toHexString(postTxState))) +
236 "\n , cumulativeGas=" + ByteUtil.toHexString(cumulativeGas) +
237 "\n , bloom=" + bloomFilter.toString() +
238 "\n , logs=" + logInfoList +
239 ']';
240 }
241
242 public byte[] getStatus() {
243 return this.status;
244 }
245 }