Coverage Summary for Class: DetailedProgramTrace (org.ethereum.vm.trace)

Class Class, % Method, % Line, %
DetailedProgramTrace 0% (0/1) 0% (0/31) 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 org.ethereum.vm.trace; 21  22 import co.rsk.config.VmConfig; 23 import co.rsk.core.RskAddress; 24 import co.rsk.core.bc.AccountInformationProvider; 25 import co.rsk.rpc.modules.trace.ProgramSubtrace; 26 import com.fasterxml.jackson.annotation.JsonIgnore; 27 import org.ethereum.util.ByteUtil; 28 import org.ethereum.vm.DataWord; 29 import org.ethereum.vm.OpCode; 30 import org.ethereum.vm.program.Memory; 31 import org.ethereum.vm.program.Stack; 32 import org.ethereum.vm.program.Storage; 33 import org.ethereum.vm.program.invoke.ProgramInvoke; 34 import org.slf4j.Logger; 35 import org.slf4j.LoggerFactory; 36  37 import java.util.*; 38  39 import static java.lang.String.format; 40 import static org.ethereum.util.ByteUtil.toHexStringOrEmpty; 41 import static org.ethereum.vm.trace.Serializers.serializeFieldsOnly; 42  43 public class DetailedProgramTrace implements ProgramTrace { 44  45  private static final Logger logger = LoggerFactory.getLogger("vm"); 46  47  private String contractAddress; 48  private Map<String, String> initStorage = new HashMap<>(); 49  50  private List<Op> structLogs = new LinkedList<>(); 51  private String result; 52  private String error; 53  private boolean reverted; 54  55  private int storageSize; 56  57  private Map<String, String> currentStorage = new HashMap<>(); 58  59  @JsonIgnore 60  private boolean fullStorage; 61  62  @JsonIgnore 63  private DataWord storageKey; 64  65  @JsonIgnore 66  private final ProgramInvoke programInvoke; 67  68  @JsonIgnore 69  private final List<ProgramSubtrace> subtraces = new ArrayList<>(); 70  71  public DetailedProgramTrace(VmConfig config, ProgramInvoke programInvoke) { 72  this.programInvoke = programInvoke; 73  74  if (config.vmTrace() && programInvoke != null) { 75  contractAddress = ByteUtil.toHexString(programInvoke.getOwnerAddress().getLast20Bytes()); 76  77  AccountInformationProvider informationProvider = getInformationProvider(programInvoke); 78  RskAddress ownerAddress = new RskAddress(programInvoke.getOwnerAddress()); 79  if (!informationProvider.isContract(ownerAddress)) { 80  storageSize = 0; 81  fullStorage = true; 82  } else { 83  storageSize = informationProvider.getStorageKeysCount(ownerAddress); 84  if (storageSize <= config.vmTraceInitStorageLimit()) { 85  fullStorage = true; 86  87  String address = toHexStringOrEmpty(programInvoke.getOwnerAddress().getLast20Bytes()); 88  Iterator<DataWord> keysIterator = informationProvider.getStorageKeys(ownerAddress); 89  while (keysIterator.hasNext()) { 90  // TODO: solve NULL key/value storage problem 91  DataWord key = keysIterator.next(); 92  byte[] value = informationProvider.getStorageBytes(ownerAddress, key); 93  if (key == null || value == null) { 94  logger.info("Null storage key/value: address[{}]", address); 95  continue; 96  } 97  98  initStorage.put(key.toString(), DataWord.valueOf(value).toString()); 99  } 100  101  if (!initStorage.isEmpty()) { 102  logger.info("{} entries loaded to transaction's initStorage", initStorage.size()); 103  } 104  } 105  } 106  107  saveCurrentStorage(initStorage); 108  } 109  } 110  111  @Override 112  public ProgramInvoke getProgramInvoke() { 113  return this.programInvoke; 114  } 115  116  private void saveCurrentStorage(Map<String, String> storage) { 117  this.currentStorage = new HashMap<>(storage); 118  } 119  120  public boolean isEmpty() { 121  return contractAddress == null; 122  } 123  124  private static AccountInformationProvider getInformationProvider(ProgramInvoke programInvoke) { 125  return programInvoke.getRepository(); 126  } 127  128  public List<Op> getStructLogs() { 129  return structLogs == null ? null : Collections.unmodifiableList(structLogs); 130  } 131  132  public void setStructLogs(List<Op> structLogs) { 133  this.structLogs = structLogs == null ? null : Collections.unmodifiableList(structLogs); 134  } 135  136  public String getResult() { 137  return result; 138  } 139  140  public void setResult(String result) { 141  this.result = result; 142  } 143  144  public String getError() { 145  return error; 146  } 147  148  public void setError(String error) { 149  this.error = error; 150  } 151  152  public boolean getReverted() { return reverted; } 153  154  public boolean isFullStorage() { 155  return fullStorage; 156  } 157  158  public void setFullStorage(boolean fullStorage) { 159  this.fullStorage = fullStorage; 160  } 161  162  public int getStorageSize() { 163  return storageSize; 164  } 165  166  public void setStorageSize(int storageSize) { 167  this.storageSize = storageSize; 168  } 169  170  public Map<String, String> getInitStorage() { 171  return initStorage; 172  } 173  174  public void setInitStorage(Map<String, String> initStorage) { 175  this.initStorage = initStorage; 176  } 177  178  public String getContractAddress() { 179  return contractAddress; 180  } 181  182  public void setContractAddress(String contractAddress) { 183  this.contractAddress = contractAddress; 184  } 185  186  public ProgramTrace result(byte[] result) { 187  setResult(toHexStringOrEmpty(result)); 188  return this; 189  } 190  191  public ProgramTrace error(Exception error) { 192  setError(error == null ? "" : format("%s: %s", error.getClass(), error.getMessage())); 193  return this; 194  } 195  196  @Override 197  public ProgramTrace revert(boolean reverted) { 198  this.reverted = reverted; 199  return this; 200  } 201  202  @Override 203  public void saveGasCost(long gasCost) { 204  structLogs.get(structLogs.size() - 1).setGasCost(gasCost); 205  } 206  207  @Override 208  public Op addOp(byte code, int pc, int deep, long gas, Memory memory, Stack stack, Storage storage) { 209  Op op = new Op(); 210  OpCode opcode = OpCode.code(code); 211  op.setOp(opcode); 212  op.setDepth(deep); 213  op.setGas(gas); 214  op.setPc(pc); 215  216  op.setMemory(memory); 217  op.setStack(stack); 218  219  if (this.storageKey != null) { 220  RskAddress currentAddress = new RskAddress(this.contractAddress); 221  DataWord value = storage.getStorageValue(currentAddress, this.storageKey); 222  223  if (value != null) { 224  this.currentStorage = new HashMap<>(this.currentStorage); 225  this.currentStorage.put(this.storageKey.toString(), value.toString()); 226  } 227  else { 228  this.currentStorage.remove(this.storageKey.toString()); 229  } 230  231  this.storageSize = this.currentStorage.size(); 232  this.storageKey = null; 233  } 234  235  if (opcode == OpCode.SSTORE || opcode == OpCode.SLOAD) { 236  this.storageKey = stack.peek(); 237  } 238  239  op.setStorage(this.currentStorage); 240  241  structLogs.add(op); 242  243  return op; 244  } 245  246  @Override 247  public void addSubTrace(ProgramSubtrace programSubTrace) { 248  this.subtraces.add(programSubTrace); 249  } 250  251  @Override 252  public List<ProgramSubtrace> getSubtraces() { 253  return Collections.unmodifiableList(this.subtraces); 254  } 255  256  /** 257  * Used for merging sub calls execution. 258  */ 259  @Override 260  public void merge(ProgramTrace programTrace) { 261  this.structLogs.addAll(((DetailedProgramTrace)programTrace).structLogs); 262  } 263  264  public String asJsonString(boolean formatted) { 265  return serializeFieldsOnly(this, formatted); 266  } 267  268  @Override 269  public String toString() { 270  return asJsonString(true); 271  } 272 }