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 }