Coverage Summary for Class: TraceTransformer (co.rsk.rpc.modules.trace)

Class Class, % Method, % Line, %
TraceTransformer 0% (0/1) 0% (0/7) 0% (0/83)


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 co.rsk.rpc.modules.trace; 21  22 import co.rsk.core.RskAddress; 23 import org.bouncycastle.util.encoders.Hex; 24 import org.ethereum.db.TransactionInfo; 25 import org.ethereum.rpc.TypeConverter; 26 import org.ethereum.vm.DataWord; 27 import org.ethereum.vm.program.ProgramResult; 28 import org.ethereum.vm.program.invoke.InvokeData; 29 import org.ethereum.vm.trace.SummarizedProgramTrace; 30  31 import java.math.BigInteger; 32 import java.util.ArrayList; 33 import java.util.List; 34  35 public class TraceTransformer { 36  private TraceTransformer() { 37  38  } 39  40  public static List<TransactionTrace> toTraces(SummarizedProgramTrace trace, TransactionInfo txInfo, long blockNumber) { 41  List<TransactionTrace> traces = new ArrayList<>(); 42  43  addTrace(traces, trace, txInfo, blockNumber, new TraceAddress()); 44  45  return traces; 46  } 47  48  private static void addTrace(List<TransactionTrace> traces, SummarizedProgramTrace trace, TransactionInfo txInfo, long blockNumber, TraceAddress traceAddress) { 49  boolean isContractCreation = txInfo.getReceipt().getTransaction().isContractCreation(); 50  CallType callType = isContractCreation ? CallType.NONE : CallType.CALL; 51  byte[] creationInput = isContractCreation ? txInfo.getReceipt().getTransaction().getData() : null; 52  53  ProgramResult programResult = ProgramResult.empty(); 54  programResult.spendGas(new BigInteger(1, txInfo.getReceipt().getGasUsed()).longValue()); 55  56  if (trace.getReverted()) { 57  programResult.setRevert(); 58  } 59  60  CreationData creationData = null; 61  TraceType traceType = TraceType.CALL; 62  63  if (isContractCreation) { 64  String outputText = trace.getResult(); 65  byte[] createdCode = outputText == null ? new byte[0] : Hex.decode(outputText); 66  RskAddress createdAddress = txInfo.getReceipt().getTransaction().getContractAddress(); 67  creationData = new CreationData(creationInput, createdCode, createdAddress); 68  traceType = TraceType.CREATE; 69  } 70  71  int nsubtraces = trace.getSubtraces().size(); 72  73  traces.add(toTrace(traceType, trace.getInvokeData(), programResult, txInfo, blockNumber, traceAddress, callType, creationData, null, trace.getError(), nsubtraces, null)); 74  75  for (int k = 0; k < nsubtraces; k++) { 76  addTrace(traces, trace.getSubtraces().get(k), txInfo, blockNumber, new TraceAddress(traceAddress, k)); 77  } 78  } 79  80  private static void addTrace(List<TransactionTrace> traces, ProgramSubtrace subtrace, TransactionInfo txInfo, long blockNumber, TraceAddress traceAddress) { 81  traces.add(toTrace(subtrace.getTraceType(), subtrace.getInvokeData(), subtrace.getProgramResult(), txInfo, blockNumber, traceAddress, subtrace.getCallType(), subtrace.getCreationData(), subtrace.getCreationMethod(), null, subtrace.getSubtraces().size(), subtrace.getCodeAddress())); 82  83  int nsubtraces = subtrace.getSubtraces().size(); 84  85  for (int k = 0; k < nsubtraces; k++) { 86  addTrace(traces, subtrace.getSubtraces().get(k), txInfo, blockNumber, new TraceAddress(traceAddress, k)); 87  } 88  } 89  90  public static TransactionTrace toTrace(TraceType traceType, InvokeData invoke, ProgramResult programResult, TransactionInfo txInfo, long blockNumber, TraceAddress traceAddress, CallType callType, CreationData creationData, String creationMethod, String err, int nsubtraces, DataWord codeAddress) { 91  TraceAction action = toAction(traceType, invoke, callType, creationData == null ? null : creationData.getCreationInput(), creationMethod, codeAddress); 92  TraceResult result = null; 93  String error = null; 94  95  if (traceType != TraceType.SUICIDE) { 96  result = toResult(programResult, creationData == null ? null : creationData.getCreatedCode(), creationData == null ? null : creationData.getCreatedAddress()); 97  98  error = err != null && err.isEmpty() ? null : err; 99  100  if (programResult.getException() != null) { 101  error = programResult.getException().toString(); 102  } 103  else if (programResult.isRevert()) { 104  error = "Reverted"; 105  } 106  107  if (error != null) { 108  result = null; 109  } 110  } 111  112  String blockHash = TypeConverter.toUnformattedJsonHex(txInfo.getBlockHash()); 113  String transactionHash = txInfo.getReceipt().getTransaction().getHash().toJsonString(); 114  int transactionPosition = txInfo.getIndex(); 115  String type = traceType.name().toLowerCase(); 116  117  return new TransactionTrace( 118  action, 119  blockHash, 120  blockNumber, 121  transactionHash, 122  transactionPosition, 123  type, 124  nsubtraces, 125  traceAddress, 126  result, 127  error 128  ); 129  } 130  131  public static TraceResult toResult(ProgramResult programResult, byte[] createdCode, RskAddress createdAddress) { 132  String gasUsed = TypeConverter.toQuantityJsonHex(programResult.getGasUsed()); 133  String output = null; 134  String address = null; 135  String code = null; 136  137  if (createdCode != null && createdAddress != null) { 138  code = TypeConverter.toUnformattedJsonHex(createdCode); 139  address = createdAddress.toJsonString(); 140  } 141  else { 142  output = TypeConverter.toUnformattedJsonHex(programResult.getHReturn()); 143  } 144  145  return new TraceResult(gasUsed, output, code, address); 146  } 147  148  public static TraceAction toAction(TraceType traceType, InvokeData invoke, CallType callType, byte[] creationInput, String creationMethod, DataWord codeAddress) { 149  String from; 150  151  if (callType == CallType.DELEGATECALL) { 152  from = new RskAddress(invoke.getOwnerAddress().getLast20Bytes()).toJsonString(); 153  } 154  else { 155  from = new RskAddress(invoke.getCallerAddress().getLast20Bytes()).toJsonString(); 156  } 157  158  String to = null; 159  String gas = null; 160  161  DataWord callValue = invoke.getCallValue(); 162  163  String input = null; 164  String value = null; 165  String address = null; 166  String refundAddress = null; 167  String balance = null; 168  String init = null; 169  170  if (traceType == TraceType.CREATE) { 171  init = TypeConverter.toUnformattedJsonHex(creationInput); 172  value = TypeConverter.toQuantityJsonHex(callValue.getData()); 173  gas = TypeConverter.toQuantityJsonHex(invoke.getGas()); 174  } 175  176  if (traceType == TraceType.CALL) { 177  input = TypeConverter.toUnformattedJsonHex(invoke.getDataCopy(DataWord.ZERO, invoke.getDataSize()));; 178  value = TypeConverter.toQuantityJsonHex(callValue.getData()); 179  180  if (callType == CallType.DELEGATECALL) { 181  // The code address should not be null in a DELEGATECALL case 182  // but handling the case here 183  if (codeAddress != null) { 184  to = new RskAddress(codeAddress.getLast20Bytes()).toJsonString(); 185  } 186  } 187  else { 188  to = new RskAddress(invoke.getOwnerAddress().getLast20Bytes()).toJsonString(); 189  } 190  191  gas = TypeConverter.toQuantityJsonHex(invoke.getGas()); 192  } 193  194  if (traceType == TraceType.SUICIDE) { 195  address = from; 196  from = null; 197  balance = TypeConverter.toQuantityJsonHex(callValue.getData()); 198  refundAddress = new RskAddress(invoke.getOwnerAddress().getLast20Bytes()).toJsonString(); 199  } 200  201  return new TraceAction( 202  callType, 203  from, 204  to, 205  gas, 206  input, 207  init, 208  creationMethod, 209  value, 210  address, 211  refundAddress, 212  balance 213  ); 214  } 215 }