Coverage Summary for Class: TraceModuleImpl (co.rsk.rpc.modules.trace)
Class |
Class, %
|
Method, %
|
Line, %
|
TraceModuleImpl |
0%
(0/1)
|
0%
(0/7)
|
0%
(0/60)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2018 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package co.rsk.rpc.modules.trace;
20
21 import co.rsk.config.VmConfig;
22 import co.rsk.core.bc.BlockExecutor;
23 import com.fasterxml.jackson.databind.JsonNode;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import org.ethereum.core.Block;
26 import org.ethereum.core.Blockchain;
27 import org.ethereum.core.Transaction;
28 import org.ethereum.db.BlockStore;
29 import org.ethereum.db.ReceiptStore;
30 import org.ethereum.db.TransactionInfo;
31 import org.ethereum.rpc.exception.RskJsonRpcRequestException;
32 import org.ethereum.vm.trace.ProgramTraceProcessor;
33 import org.ethereum.vm.trace.Serializers;
34 import org.ethereum.vm.trace.SummarizedProgramTrace;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import java.util.ArrayList;
39 import java.util.List;
40
41 import static org.ethereum.rpc.TypeConverter.stringHexToBigInteger;
42 import static org.ethereum.rpc.TypeConverter.stringHexToByteArray;
43
44 public class TraceModuleImpl implements TraceModule {
45 private static final Logger logger = LoggerFactory.getLogger("web3");
46
47 private final Blockchain blockchain;
48 private final BlockStore blockStore;
49 private final ReceiptStore receiptStore;
50
51 private final BlockExecutor blockExecutor;
52
53 public TraceModuleImpl(
54 Blockchain blockchain,
55 BlockStore blockStore,
56 ReceiptStore receiptStore,
57 BlockExecutor blockExecutor) {
58 this.blockchain = blockchain;
59 this.blockStore = blockStore;
60 this.receiptStore = receiptStore;
61 this.blockExecutor = blockExecutor;
62 }
63
64 @Override
65 public JsonNode traceTransaction(String transactionHash) throws Exception {
66 logger.trace("trace_transaction({})", transactionHash);
67
68 byte[] hash = stringHexToByteArray(transactionHash);
69 TransactionInfo txInfo = this.receiptStore.getInMainChain(hash, this.blockStore);
70
71 if (txInfo == null) {
72 logger.trace("No transaction info for {}", transactionHash);
73 return null;
74 }
75
76 Block block = this.blockchain.getBlockByHash(txInfo.getBlockHash());
77 Block parent = this.blockchain.getBlockByHash(block.getParentHash().getBytes());
78 Transaction tx = block.getTransactionsList().get(txInfo.getIndex());
79 txInfo.setTransaction(tx);
80
81 ProgramTraceProcessor programTraceProcessor = new ProgramTraceProcessor();
82 this.blockExecutor.traceBlock(programTraceProcessor, VmConfig.LIGHT_TRACE, block, parent.getHeader(), false, false);
83
84 SummarizedProgramTrace programTrace = (SummarizedProgramTrace)programTraceProcessor.getProgramTrace(tx.getHash());
85
86 if (programTrace == null) {
87 return null;
88 }
89
90 List<TransactionTrace> traces = TraceTransformer.toTraces(programTrace, txInfo, block.getNumber());
91 ObjectMapper mapper = Serializers.createMapper(true);
92 return mapper.valueToTree(traces);
93 }
94
95 @Override
96 public JsonNode traceBlock(String blockArgument) throws Exception {
97 logger.trace("trace_block({})", blockArgument);
98
99 Block block = this.getByJsonArgument(blockArgument);
100
101 if (block == null) {
102 logger.trace("No block for {}", blockArgument);
103 return null;
104 }
105
106 Block parent = this.blockchain.getBlockByHash(block.getParentHash().getBytes());
107
108 List<TransactionTrace> blockTraces = new ArrayList<>();
109
110 if (block.getNumber() != 0) {
111 ProgramTraceProcessor programTraceProcessor = new ProgramTraceProcessor();
112 this.blockExecutor.traceBlock(programTraceProcessor, VmConfig.LIGHT_TRACE, block, parent.getHeader(), false, false);
113
114 for (Transaction tx : block.getTransactionsList()) {
115 TransactionInfo txInfo = receiptStore.getInMainChain(tx.getHash().getBytes(), this.blockStore);
116 txInfo.setTransaction(tx);
117
118 SummarizedProgramTrace programTrace = (SummarizedProgramTrace) programTraceProcessor.getProgramTrace(tx.getHash());
119
120 if (programTrace == null) {
121 return null;
122 }
123
124 List<TransactionTrace> traces = TraceTransformer.toTraces(programTrace, txInfo, block.getNumber());
125
126 blockTraces.addAll(traces);
127 }
128 }
129
130 ObjectMapper mapper = Serializers.createMapper(true);
131
132 return mapper.valueToTree(blockTraces);
133 }
134
135 private Block getByJsonArgument(String arg) {
136 if (arg.length() < 20) {
137 return this.getByJsonBlockId(arg);
138 }
139 else {
140 return this.getByJsonBlockHash(arg);
141 }
142 }
143
144 private Block getByJsonBlockHash(String arg) {
145 byte[] hash = stringHexToByteArray(arg);
146
147 return this.blockchain.getBlockByHash(hash);
148 }
149
150 private Block getByJsonBlockId(String id) {
151 if ("earliest".equalsIgnoreCase(id)) {
152 return this.blockchain.getBlockByNumber(0);
153 } else if ("latest".equalsIgnoreCase(id)) {
154 return this.blockchain.getBestBlock();
155 } else if ("pending".equalsIgnoreCase(id)) {
156 throw RskJsonRpcRequestException.unimplemented("The method don't support 'pending' as a parameter yet");
157 } else {
158 try {
159 long blockNumber = stringHexToBigInteger(id).longValue();
160 return this.blockchain.getBlockByNumber(blockNumber);
161 } catch (NumberFormatException | StringIndexOutOfBoundsException e) {
162 throw RskJsonRpcRequestException.invalidParamError("invalid blocknumber " + id);
163 }
164 }
165 }
166 }