Coverage Summary for Class: Web3Impl (org.ethereum.rpc)
Class |
Method, %
|
Line, %
|
Web3Impl |
60.2%
(56/93)
|
57.9%
(250/432)
|
Web3Impl$MockitoMock$456173098 |
Web3Impl$MockitoMock$456173098$auxiliary$0Tltp5Bx |
Web3Impl$MockitoMock$456173098$auxiliary$10ejwKyY |
Web3Impl$MockitoMock$456173098$auxiliary$164b0JAc |
Web3Impl$MockitoMock$456173098$auxiliary$2BmmjRWs |
Web3Impl$MockitoMock$456173098$auxiliary$2ljGiQ4P |
Web3Impl$MockitoMock$456173098$auxiliary$2MYa41lc |
Web3Impl$MockitoMock$456173098$auxiliary$3Vi196tx |
Web3Impl$MockitoMock$456173098$auxiliary$42LKUI4M |
Web3Impl$MockitoMock$456173098$auxiliary$51lUSlW5 |
Web3Impl$MockitoMock$456173098$auxiliary$5k1dOn8D |
Web3Impl$MockitoMock$456173098$auxiliary$6Ye12YKi |
Web3Impl$MockitoMock$456173098$auxiliary$7c0e8391 |
Web3Impl$MockitoMock$456173098$auxiliary$7ctutsrw |
Web3Impl$MockitoMock$456173098$auxiliary$8aQ2c0fY |
Web3Impl$MockitoMock$456173098$auxiliary$8WV8Uh1t |
Web3Impl$MockitoMock$456173098$auxiliary$a3vQIYxI |
Web3Impl$MockitoMock$456173098$auxiliary$A7LpwEAO |
Web3Impl$MockitoMock$456173098$auxiliary$a8YDWdVT |
Web3Impl$MockitoMock$456173098$auxiliary$Am26rICx |
Web3Impl$MockitoMock$456173098$auxiliary$cejWW216 |
Web3Impl$MockitoMock$456173098$auxiliary$cgqRc0WQ |
Web3Impl$MockitoMock$456173098$auxiliary$CJcH92in |
Web3Impl$MockitoMock$456173098$auxiliary$crQJu9GA |
Web3Impl$MockitoMock$456173098$auxiliary$CVdyASMZ |
Web3Impl$MockitoMock$456173098$auxiliary$d3aOC5vf |
Web3Impl$MockitoMock$456173098$auxiliary$DawL0Ozz |
Web3Impl$MockitoMock$456173098$auxiliary$dcTbEjxK |
Web3Impl$MockitoMock$456173098$auxiliary$DGzR26Kt |
Web3Impl$MockitoMock$456173098$auxiliary$DX8QW5Ad |
Web3Impl$MockitoMock$456173098$auxiliary$E3RBpa5N |
Web3Impl$MockitoMock$456173098$auxiliary$ef8V7qJW |
Web3Impl$MockitoMock$456173098$auxiliary$EmsqzVKB |
Web3Impl$MockitoMock$456173098$auxiliary$ErfZJeci |
Web3Impl$MockitoMock$456173098$auxiliary$eXHg6pvx |
Web3Impl$MockitoMock$456173098$auxiliary$FDBtxE15 |
Web3Impl$MockitoMock$456173098$auxiliary$FFqggf1B |
Web3Impl$MockitoMock$456173098$auxiliary$FjE6376C |
Web3Impl$MockitoMock$456173098$auxiliary$FKlW0hPy |
Web3Impl$MockitoMock$456173098$auxiliary$FNck1fdX |
Web3Impl$MockitoMock$456173098$auxiliary$FU7N2pd2 |
Web3Impl$MockitoMock$456173098$auxiliary$fVO3yWyX |
Web3Impl$MockitoMock$456173098$auxiliary$g5TgNbbb |
Web3Impl$MockitoMock$456173098$auxiliary$G746giIv |
Web3Impl$MockitoMock$456173098$auxiliary$gIzV7wOj |
Web3Impl$MockitoMock$456173098$auxiliary$GMnv7Rat |
Web3Impl$MockitoMock$456173098$auxiliary$GmX4ja63 |
Web3Impl$MockitoMock$456173098$auxiliary$GofRJhOg |
Web3Impl$MockitoMock$456173098$auxiliary$HervTyi7 |
Web3Impl$MockitoMock$456173098$auxiliary$hT2I9o5z |
Web3Impl$MockitoMock$456173098$auxiliary$HT2vUfgK |
Web3Impl$MockitoMock$456173098$auxiliary$iCg7FbDC |
Web3Impl$MockitoMock$456173098$auxiliary$If0mQib3 |
Web3Impl$MockitoMock$456173098$auxiliary$IRBZxJa0 |
Web3Impl$MockitoMock$456173098$auxiliary$IsddgZVY |
Web3Impl$MockitoMock$456173098$auxiliary$ivkFZuMD |
Web3Impl$MockitoMock$456173098$auxiliary$IxDHiTJc |
Web3Impl$MockitoMock$456173098$auxiliary$jDdncnx0 |
Web3Impl$MockitoMock$456173098$auxiliary$JIAGZUmi |
Web3Impl$MockitoMock$456173098$auxiliary$jNxp3frw |
Web3Impl$MockitoMock$456173098$auxiliary$KAGnffPH |
Web3Impl$MockitoMock$456173098$auxiliary$l6HE36cg |
Web3Impl$MockitoMock$456173098$auxiliary$Lkyl8okO |
Web3Impl$MockitoMock$456173098$auxiliary$LMzg3LMr |
Web3Impl$MockitoMock$456173098$auxiliary$ME1OJvJT |
Web3Impl$MockitoMock$456173098$auxiliary$MfvRz1Sc |
Web3Impl$MockitoMock$456173098$auxiliary$MpEiUSY0 |
Web3Impl$MockitoMock$456173098$auxiliary$MSbOWoKF |
Web3Impl$MockitoMock$456173098$auxiliary$NYxS1PZV |
Web3Impl$MockitoMock$456173098$auxiliary$oJDRfYdz |
Web3Impl$MockitoMock$456173098$auxiliary$olJcalI4 |
Web3Impl$MockitoMock$456173098$auxiliary$olRlenOK |
Web3Impl$MockitoMock$456173098$auxiliary$OrjZAfI1 |
Web3Impl$MockitoMock$456173098$auxiliary$pbule2ob |
Web3Impl$MockitoMock$456173098$auxiliary$Po6XgZfV |
Web3Impl$MockitoMock$456173098$auxiliary$ppkCICNM |
Web3Impl$MockitoMock$456173098$auxiliary$PyEVjdBT |
Web3Impl$MockitoMock$456173098$auxiliary$PYICOwfO |
Web3Impl$MockitoMock$456173098$auxiliary$Q7ZxYmob |
Web3Impl$MockitoMock$456173098$auxiliary$qhuvhzxL |
Web3Impl$MockitoMock$456173098$auxiliary$qkadEUUX |
Web3Impl$MockitoMock$456173098$auxiliary$QNx9sdK2 |
Web3Impl$MockitoMock$456173098$auxiliary$QvFGzaxt |
Web3Impl$MockitoMock$456173098$auxiliary$qwMBmfNE |
Web3Impl$MockitoMock$456173098$auxiliary$rj9tkHer |
Web3Impl$MockitoMock$456173098$auxiliary$s3wfDJWv |
Web3Impl$MockitoMock$456173098$auxiliary$sjEjRwGh |
Web3Impl$MockitoMock$456173098$auxiliary$smVj0SUC |
Web3Impl$MockitoMock$456173098$auxiliary$SR2ShZTF |
Web3Impl$MockitoMock$456173098$auxiliary$sRY8qUfT |
Web3Impl$MockitoMock$456173098$auxiliary$t9Zw9PXF |
Web3Impl$MockitoMock$456173098$auxiliary$tFYi6kCI |
Web3Impl$MockitoMock$456173098$auxiliary$Ul0PaUPD |
Web3Impl$MockitoMock$456173098$auxiliary$uMQtdbuf |
Web3Impl$MockitoMock$456173098$auxiliary$vLH9ycHR |
Web3Impl$MockitoMock$456173098$auxiliary$VpViKY97 |
Web3Impl$MockitoMock$456173098$auxiliary$vrtLSG0w |
Web3Impl$MockitoMock$456173098$auxiliary$w4qwJAtX |
Web3Impl$MockitoMock$456173098$auxiliary$wiKhJc8u |
Web3Impl$MockitoMock$456173098$auxiliary$WpG0KOq2 |
Web3Impl$MockitoMock$456173098$auxiliary$wSimNDcM |
Web3Impl$MockitoMock$456173098$auxiliary$wY5fqtcb |
Web3Impl$MockitoMock$456173098$auxiliary$wYtBJM0U |
Web3Impl$MockitoMock$456173098$auxiliary$XBQVnLPl |
Web3Impl$MockitoMock$456173098$auxiliary$xpVto4JB |
Web3Impl$MockitoMock$456173098$auxiliary$xQg9jwKC |
Web3Impl$MockitoMock$456173098$auxiliary$XrudTYQI |
Web3Impl$MockitoMock$456173098$auxiliary$y43Mflnu |
Web3Impl$MockitoMock$456173098$auxiliary$yDuziqmT |
Web3Impl$MockitoMock$456173098$auxiliary$YgaJRrTc |
Web3Impl$MockitoMock$456173098$auxiliary$ylAII31S |
Web3Impl$MockitoMock$456173098$auxiliary$yWXhNQOk |
Web3Impl$MockitoMock$456173098$auxiliary$zgZrmX9K |
Web3Impl$MockitoMock$456173098$auxiliary$zliVR8tw |
Web3Impl$MockitoMock$456173098$auxiliary$zUs1EsYT |
Web3Impl$MockitoMock$456173098$auxiliary$zyAe4Skb |
Total |
60.2%
(56/93)
|
57.9%
(250/432)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 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 org.ethereum.rpc;
20
21 import co.rsk.config.RskSystemProperties;
22 import co.rsk.core.Coin;
23 import co.rsk.core.RskAddress;
24 import co.rsk.core.bc.AccountInformationProvider;
25 import co.rsk.crypto.Keccak256;
26 import co.rsk.logfilter.BlocksBloomStore;
27 import co.rsk.metrics.HashRateCalculator;
28 import co.rsk.mine.MinerClient;
29 import co.rsk.mine.MinerServer;
30 import co.rsk.net.BlockProcessor;
31 import co.rsk.net.Peer;
32 import co.rsk.rpc.ModuleDescription;
33 import co.rsk.rpc.Web3InformationRetriever;
34 import co.rsk.rpc.modules.debug.DebugModule;
35 import co.rsk.rpc.modules.eth.EthModule;
36 import co.rsk.rpc.modules.evm.EvmModule;
37 import co.rsk.rpc.modules.mnr.MnrModule;
38 import co.rsk.rpc.modules.personal.PersonalModule;
39 import co.rsk.rpc.modules.rsk.RskModule;
40 import co.rsk.rpc.modules.trace.TraceModule;
41 import co.rsk.rpc.modules.txpool.TxPoolModule;
42 import co.rsk.scoring.*;
43 import org.ethereum.config.blockchain.upgrades.ConsensusRule;
44 import org.ethereum.core.Block;
45 import org.ethereum.core.BlockHeader;
46 import org.ethereum.core.Blockchain;
47 import org.ethereum.core.Transaction;
48 import org.ethereum.crypto.HashUtil;
49 import org.ethereum.db.BlockInformation;
50 import org.ethereum.db.BlockStore;
51 import org.ethereum.db.ReceiptStore;
52 import org.ethereum.db.TransactionInfo;
53 import org.ethereum.facade.Ethereum;
54 import org.ethereum.net.client.Capability;
55 import org.ethereum.net.client.ConfigCapabilities;
56 import org.ethereum.net.server.ChannelManager;
57 import org.ethereum.net.server.PeerServer;
58 import org.ethereum.rpc.dto.BlockResultDTO;
59 import org.ethereum.rpc.dto.CompilationResultDTO;
60 import org.ethereum.rpc.dto.TransactionReceiptDTO;
61 import org.ethereum.rpc.dto.TransactionResultDTO;
62 import org.ethereum.util.BuildInfo;
63 import org.ethereum.vm.DataWord;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 import java.math.BigInteger;
68 import java.nio.charset.StandardCharsets;
69 import java.time.Duration;
70 import java.util.*;
71 import java.util.function.Function;
72
73 import static java.lang.Math.max;
74 import static org.ethereum.rpc.TypeConverter.*;
75 import static org.ethereum.rpc.exception.RskJsonRpcRequestException.*;
76
77 public class Web3Impl implements Web3 {
78 private static final Logger logger = LoggerFactory.getLogger("web3");
79
80 public Ethereum eth;
81
82 private final String baseClientVersion = "RskJ";
83
84 private long initialBlockNumber;
85
86 private final MinerClient minerClient;
87 protected MinerServer minerServer;
88 private final ChannelManager channelManager;
89 private final PeerScoringManager peerScoringManager;
90 private final PeerServer peerServer;
91
92 private final Blockchain blockchain;
93 private final ReceiptStore receiptStore;
94 private final BlockProcessor nodeBlockProcessor;
95 private final HashRateCalculator hashRateCalculator;
96 private final ConfigCapabilities configCapabilities;
97 private final BlockStore blockStore;
98 private final RskSystemProperties config;
99
100 private final FilterManager filterManager;
101 private final BuildInfo buildInfo;
102
103 private final BlocksBloomStore blocksBloomStore;
104 private final Web3InformationRetriever web3InformationRetriever;
105
106 private final PersonalModule personalModule;
107 private final EthModule ethModule;
108 private final EvmModule evmModule;
109 private final TxPoolModule txPoolModule;
110 private final MnrModule mnrModule;
111 private final DebugModule debugModule;
112 private final TraceModule traceModule;
113 private final RskModule rskModule;
114
115 protected Web3Impl(
116 Ethereum eth,
117 Blockchain blockchain,
118 BlockStore blockStore,
119 ReceiptStore receiptStore,
120 RskSystemProperties config,
121 MinerClient minerClient,
122 MinerServer minerServer,
123 PersonalModule personalModule,
124 EthModule ethModule,
125 EvmModule evmModule,
126 TxPoolModule txPoolModule,
127 MnrModule mnrModule,
128 DebugModule debugModule,
129 TraceModule traceModule,
130 RskModule rskModule,
131 ChannelManager channelManager,
132 PeerScoringManager peerScoringManager,
133 PeerServer peerServer,
134 BlockProcessor nodeBlockProcessor,
135 HashRateCalculator hashRateCalculator,
136 ConfigCapabilities configCapabilities,
137 BuildInfo buildInfo,
138 BlocksBloomStore blocksBloomStore,
139 Web3InformationRetriever web3InformationRetriever) {
140 this.eth = eth;
141 this.blockchain = blockchain;
142 this.blockStore = blockStore;
143 this.receiptStore = receiptStore;
144 this.evmModule = evmModule;
145 this.minerClient = minerClient;
146 this.minerServer = minerServer;
147 this.personalModule = personalModule;
148 this.ethModule = ethModule;
149 this.txPoolModule = txPoolModule;
150 this.mnrModule = mnrModule;
151 this.debugModule = debugModule;
152 this.traceModule = traceModule;
153 this.rskModule = rskModule;
154 this.channelManager = channelManager;
155 this.peerScoringManager = peerScoringManager;
156 this.peerServer = peerServer;
157 this.nodeBlockProcessor = nodeBlockProcessor;
158 this.hashRateCalculator = hashRateCalculator;
159 this.configCapabilities = configCapabilities;
160 this.config = config;
161 this.filterManager = new FilterManager(eth);
162 this.buildInfo = buildInfo;
163 this.blocksBloomStore = blocksBloomStore;
164 this.web3InformationRetriever = web3InformationRetriever;
165 initialBlockNumber = this.blockchain.getBestBlock().getNumber();
166
167 personalModule.init();
168 }
169
170 @Override
171 public void start() {
172 hashRateCalculator.start();
173 }
174
175 @Override
176 public void stop() {
177 hashRateCalculator.stop();
178 }
179
180 private int JSonHexToInt(String x) {
181 if (!x.startsWith("0x")) {
182 throw invalidParamError("Incorrect hex syntax");
183 }
184 x = x.substring(2);
185 return Integer.parseInt(x, 16);
186 }
187
188 @Override
189 public String web3_clientVersion() {
190 String clientVersion = baseClientVersion + "/" + config.projectVersion() + "/" +
191 System.getProperty("os.name") + "/Java1.8/" +
192 config.projectVersionModifier() + "-" + buildInfo.getBuildHash();
193
194 if (logger.isDebugEnabled()) {
195 logger.debug("web3_clientVersion(): {}", clientVersion);
196 }
197
198 return clientVersion;
199 }
200
201 @Override
202 public String web3_sha3(String data) throws Exception {
203 String s = null;
204 try {
205 byte[] result = HashUtil.keccak256(data.getBytes(StandardCharsets.UTF_8));
206 return s = TypeConverter.toJsonHex(result);
207 } finally {
208 if (logger.isDebugEnabled()) {
209 logger.debug("web3_sha3({}): {}", data, s);
210 }
211 }
212 }
213
214 @Override
215 public String net_version() {
216 String s = null;
217 try {
218 byte netVersion = config.getNetworkConstants().getChainId();
219 return s = Byte.toString(netVersion);
220 }
221 finally {
222 if (logger.isDebugEnabled()) {
223 logger.debug("net_version(): {}", s);
224 }
225 }
226 }
227
228 @Override
229 public String net_peerCount() {
230 String s = null;
231 try {
232 int n = channelManager.getActivePeers().size();
233 return s = TypeConverter.toQuantityJsonHex(n);
234 } finally {
235 if (logger.isDebugEnabled()) {
236 logger.debug("net_peerCount(): {}", s);
237 }
238 }
239 }
240
241
242 @Override
243 public boolean net_listening() {
244 Boolean s = null;
245 try {
246 return s = peerServer.isListening();
247 } finally {
248 if (logger.isDebugEnabled()) {
249 logger.debug("net_listening(): {}", s);
250 }
251 }
252 }
253
254 @Override
255 public String rsk_protocolVersion() {
256 String s = null;
257 try {
258 int version = 0;
259
260 for (Capability capability : configCapabilities.getConfigCapabilities()) {
261 if (capability.isRSK()) {
262 version = max(version, capability.getVersion());
263 }
264 }
265
266 return s = Integer.toString(version);
267 } finally {
268 if (logger.isDebugEnabled()) {
269 logger.debug("rsk_protocolVersion(): {}", s);
270 }
271 }
272 }
273
274 @Override
275 public String eth_protocolVersion() {
276 return rsk_protocolVersion();
277 }
278
279 @Override
280 public Object eth_syncing() {
281 long currentBlock = this.blockchain.getBestBlock().getNumber();
282 long highestBlock = this.nodeBlockProcessor.getLastKnownBlockNumber();
283
284 if (highestBlock <= currentBlock){
285 return false;
286 }
287
288 SyncingResult s = new SyncingResult();
289 try {
290 s.startingBlock = TypeConverter.toQuantityJsonHex(initialBlockNumber);
291 s.currentBlock = TypeConverter.toQuantityJsonHex(currentBlock);
292 s.highestBlock = toQuantityJsonHex(highestBlock);
293
294 return s;
295 } finally {
296 logger.debug("eth_syncing(): starting {}, current {}, highest {} ", s.startingBlock, s.currentBlock, s.highestBlock);
297 }
298 }
299
300 @Override
301 public String eth_coinbase() {
302 String s = null;
303 try {
304 s = minerServer.getCoinbaseAddress().toJsonString();
305 return s;
306 } finally {
307 if (logger.isDebugEnabled()) {
308 logger.debug("eth_coinbase(): {}", s);
309 }
310 }
311 }
312
313
314 @Override
315 public boolean eth_mining() {
316 Boolean s = null;
317 try {
318 return s = minerClient.isMining();
319 } finally {
320 if (logger.isDebugEnabled()) {
321 logger.debug("eth_mining(): {}", s);
322 }
323 }
324 }
325
326 @Override
327 public BigInteger eth_hashrate() {
328 BigInteger hashesPerHour = hashRateCalculator.calculateNodeHashRate(Duration.ofHours(1));
329 BigInteger hashesPerSecond = hashesPerHour.divide(BigInteger.valueOf(Duration.ofHours(1).getSeconds()));
330
331 logger.debug("eth_hashrate(): {}", hashesPerSecond);
332
333 return hashesPerSecond;
334 }
335
336 @Override
337 public BigInteger eth_netHashrate() {
338 BigInteger hashesPerHour = hashRateCalculator.calculateNetHashRate(Duration.ofHours(1));
339 BigInteger hashesPerSecond = hashesPerHour.divide(BigInteger.valueOf(Duration.ofHours(1).getSeconds()));
340
341 logger.debug("eth_netHashrate(): {}", hashesPerSecond);
342
343 return hashesPerSecond;
344 }
345
346 @Override
347 public String[] net_peerList() {
348 Collection<Peer> peers = channelManager.getActivePeers();
349 List<String> response = new ArrayList<>();
350 peers.forEach(channel -> response.add(channel.toString()));
351
352 return response.stream().toArray(String[]::new);
353 }
354
355 @Override
356 public String eth_gasPrice() {
357 String gasPrice = null;
358 try {
359 gasPrice = TypeConverter.toQuantityJsonHex(eth.getGasPrice().asBigInteger().longValue());
360 return gasPrice;
361 } finally {
362 if (logger.isDebugEnabled()) {
363 logger.debug("eth_gasPrice(): {}", gasPrice);
364 }
365 }
366 }
367
368 @Override
369 public String eth_blockNumber() {
370 Block bestBlock = blockchain.getBestBlock();
371
372 long b = 0;
373 if (bestBlock != null) {
374 b = bestBlock.getNumber();
375 }
376
377 logger.debug("eth_blockNumber(): {}", b);
378
379 return toQuantityJsonHex(b);
380 }
381
382 @Override
383 public String eth_call(CallArguments args, Map<String, String> inputs) {
384 return invokeByBlockRef(inputs, blockNumber -> this.eth_call(args, blockNumber));
385 }
386
387 @Override
388 public String eth_getCode(String address, Map<String, String> inputs) {
389 return invokeByBlockRef(inputs, blockNumber -> this.eth_getCode(address, blockNumber));
390 }
391
392 @Override
393 public String eth_getBalance(String address, String block) {
394 /* HEX String - an integer block number
395 * String "earliest" for the earliest/genesis block
396 * String "latest" - for the latest mined block
397 * String "pending" - for the pending state/transactions
398 */
399
400 AccountInformationProvider accountInformationProvider = web3InformationRetriever.getInformationProvider(block);
401
402 RskAddress addr = new RskAddress(address);
403 Coin balance = accountInformationProvider.getBalance(addr);
404
405 return toQuantityJsonHex(balance.asBigInteger());
406 }
407
408 @Override
409 public String eth_getBalance(String address, Map<String, String> inputs) {
410 return invokeByBlockRef(inputs, blockNumber -> this.eth_getBalance(address, blockNumber));
411 }
412
413 private Optional<String> applyIfPresent(final Map<String, String> inputs, final String reference, final Function<String, String> function) {
414 return Optional.ofNullable(inputs.get(reference)).map(function);
415 }
416
417 private boolean isInMainChain(Block block) {
418 return this.blockchain.getBlocksInformationByNumber(block.getNumber())
419 .stream().anyMatch(b -> {
420 return b.isInMainChain()
421 && Arrays.equals(b.getHash(), block.getHash().getBytes());
422 });
423 }
424
425 @Override
426 public String eth_getBalance(String address) {
427 return eth_getBalance(address, "latest");
428 }
429
430 @Override
431 public String eth_getStorageAt(String address, String storageIdx, Map<String, String> blockRef) {
432 return invokeByBlockRef(blockRef, blockNumber -> this.eth_getStorageAt(address,storageIdx, blockNumber));
433 }
434
435 @Override
436 public String eth_getStorageAt(String address, String storageIdx, String blockId) {
437 String s = null;
438
439 try {
440 RskAddress addr = new RskAddress(address);
441
442 AccountInformationProvider accountInformationProvider =
443 web3InformationRetriever.getInformationProvider(blockId);
444
445 DataWord sv = accountInformationProvider
446 .getStorageValue(addr, DataWord.valueOf(stringHexToByteArray(storageIdx)));
447
448 if (sv == null) {
449 s = "0x0";
450 } else {
451 s = toUnformattedJsonHex(sv.getData());
452 }
453
454 return s;
455 } finally {
456 if (logger.isDebugEnabled()) {
457 logger.debug("eth_getStorageAt({}, {}, {}): {}", address, storageIdx, blockId, s);
458 }
459 }
460 }
461
462 @Override
463 public String eth_getTransactionCount(String address, Map<String, String> inputs) {
464 return invokeByBlockRef(inputs, blockNumber -> this.eth_getTransactionCount(address, blockNumber));
465 }
466
467 /**
468 * eip-1898 implementations.
469 * It processes inputs maps ex: { "blockNumber": "0x0" },
470 * { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false }
471 * and invoke a function after processing.
472 * @param inputs map
473 * @param toInvokeByBlockNumber a function that returns a string based on the block number
474 * @return function invocation result
475 */
476 protected String invokeByBlockRef(Map<String, String> inputs, Function<String, String> toInvokeByBlockNumber) {
477 Function<String, String> getBalanceByBlockHash = blockHash -> {
478
479 Block block = Optional.ofNullable(this.blockchain.getBlockByHash(stringHexToByteArray(blockHash)))
480 .orElseThrow(() -> blockNotFound(String.format("Block with hash %s not found", blockHash)));
481
482 //check if is canonical required
483 Optional.ofNullable(inputs.get("requireCanonical")).ifPresent((requireCanonical) -> {
484 if (Boolean.parseBoolean(requireCanonical) && !isInMainChain(block)) {
485 throw blockNotFound(String.format("Block with hash %s is not canonical and it is required", blockHash));
486 }
487 });
488
489 return toInvokeByBlockNumber.apply(toQuantityJsonHex(block.getNumber()));
490 };
491
492 return applyIfPresent(inputs, "blockHash", getBalanceByBlockHash)
493 .orElseGet(() -> applyIfPresent(inputs, "blockNumber", toInvokeByBlockNumber)
494 .orElseThrow(() -> invalidParamError("Invalid block input"))
495 );
496 }
497
498 @Override
499 public String eth_getTransactionCount(String address, String blockId) {
500 String s = null;
501 try {
502 RskAddress addr = new RskAddress(address);
503 AccountInformationProvider accountInformationProvider = web3InformationRetriever
504 .getInformationProvider(blockId);
505 BigInteger nonce = accountInformationProvider.getNonce(addr);
506 s = toQuantityJsonHex(nonce);
507 return s;
508 } finally {
509 if (logger.isDebugEnabled()) {
510 logger.debug("eth_getTransactionCount({}, {}): {}", address, blockId, s);
511 }
512 }
513 }
514
515 public Block getBlockByJSonHash(String blockHash) {
516 byte[] bhash = stringHexToByteArray(blockHash);
517 return this.blockchain.getBlockByHash(bhash);
518 }
519
520 @Override
521 public String eth_getBlockTransactionCountByHash(String blockHash) {
522 String s = null;
523 try {
524 Block b = getBlockByJSonHash(blockHash);
525
526 if (b == null) {
527 return null;
528 }
529
530 long n = b.getTransactionsList().size();
531
532 s = TypeConverter.toQuantityJsonHex(n);
533 return s;
534 } finally {
535 if (logger.isDebugEnabled()) {
536 logger.debug("eth_getBlockTransactionCountByHash({}): {}", blockHash, s);
537 }
538 }
539 }
540
541 public static Block getBlockByNumberOrStr(String bnOrId, Blockchain blockchain) {
542 Block b;
543
544 if ("latest".equals(bnOrId)) {
545 b = blockchain.getBestBlock();
546 } else if ("earliest".equals(bnOrId)) {
547 b = blockchain.getBlockByNumber(0);
548 } else if ("pending".equals(bnOrId)) {
549 throw unimplemented("The method don't support 'pending' as a parameter yet");
550 } else {
551 long bn = JSonHexToLong(bnOrId);
552 b = blockchain.getBlockByNumber(bn);
553 }
554
555 return b;
556 }
557
558 @Override
559 public String eth_getBlockTransactionCountByNumber(String bnOrId) {
560 String s = null;
561 try {
562
563 List<Transaction> txs = web3InformationRetriever.getTransactions(bnOrId);
564
565 s = toQuantityJsonHex(txs.size());
566 return s;
567 } finally {
568 if (logger.isDebugEnabled()) {
569 logger.debug("eth_getBlockTransactionCountByNumber({}): {}", bnOrId, s);
570 }
571 }
572 }
573
574 @Override
575 public String eth_getUncleCountByBlockHash(String blockHash) {
576 Block b = getBlockByJSonHash(blockHash);
577 if (b == null) {
578 throw blockNotFound(String.format("Block with hash %s not found", blockHash));
579 }
580
581 long n = b.getUncleList().size();
582 return toQuantityJsonHex(n);
583 }
584
585 @Override
586 public String eth_getUncleCountByBlockNumber(String bnOrId) {
587 return web3InformationRetriever.getBlock(bnOrId)
588 .map(Block::getUncleList)
589 .map(List::size)
590 .map(TypeConverter::toQuantityJsonHex)
591 .orElseThrow(() -> blockNotFound(String.format("Block %s not found", bnOrId)));
592 }
593
594 public BlockInformationResult getBlockInformationResult(BlockInformation blockInformation) {
595 BlockInformationResult bir = new BlockInformationResult();
596 bir.hash = toUnformattedJsonHex(blockInformation.getHash());
597 bir.totalDifficulty = toQuantityJsonHex(blockInformation.getTotalDifficulty().asBigInteger());
598 bir.inMainChain = blockInformation.isInMainChain();
599
600 return bir;
601 }
602
603 public BlockResultDTO getBlockResult(Block b, boolean fullTx) {
604 return BlockResultDTO.fromBlock(b, fullTx, this.blockStore);
605 }
606
607 public BlockInformationResult[] eth_getBlocksByNumber(String number) {
608 long blockNumber;
609
610 try {
611 blockNumber = TypeConverter.stringNumberAsBigInt(number).longValue();
612 } catch (NumberFormatException | StringIndexOutOfBoundsException e) {
613 throw invalidParamError(String.format("invalid blocknumber %s", number));
614 }
615
616 List<BlockInformationResult> result = new ArrayList<>();
617
618 List<BlockInformation> binfos = blockchain.getBlocksInformationByNumber(blockNumber);
619
620 for (BlockInformation binfo : binfos) {
621 result.add(getBlockInformationResult(binfo));
622 }
623
624 return result.toArray(new BlockInformationResult[result.size()]);
625 }
626
627 @Override
628 public BlockResultDTO eth_getBlockByHash(String blockHash, Boolean fullTransactionObjects) {
629 BlockResultDTO s = null;
630 try {
631 Block b = getBlockByJSonHash(blockHash);
632
633 return s = (b == null ? null : getBlockResult(b, fullTransactionObjects));
634 } finally {
635 if (logger.isDebugEnabled()) {
636 logger.debug("eth_getBlockByHash({}, {}): {}", blockHash, fullTransactionObjects, s);
637 }
638 }
639 }
640
641 @Override
642 public BlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactionObjects) {
643 BlockResultDTO s = null;
644 try {
645
646 s = web3InformationRetriever.getBlock(bnOrId)
647 .map(b -> getBlockResult(b, fullTransactionObjects))
648 .orElse(null);
649
650 return s;
651 } finally {
652 if (logger.isDebugEnabled()) {
653 logger.debug("eth_getBlockByNumber({}, {}): {}", bnOrId, fullTransactionObjects, s);
654 }
655 }
656 }
657
658 @Override
659 public TransactionResultDTO eth_getTransactionByHash(String transactionHash) {
660 TransactionResultDTO s = null;
661 try {
662 Keccak256 txHash = new Keccak256(stringHexToByteArray(transactionHash));
663 Block block = null;
664
665 TransactionInfo txInfo = this.receiptStore.getInMainChain(txHash.getBytes(), blockStore);
666
667 if (txInfo == null) {
668 List<Transaction> txs = web3InformationRetriever.getTransactions("pending");
669
670 for (Transaction tx : txs) {
671 if (tx.getHash().equals(txHash)) {
672 return s = new TransactionResultDTO(null, null, tx);
673 }
674 }
675 } else {
676 block = blockchain.getBlockByHash(txInfo.getBlockHash());
677 // need to return txes only from main chain
678 Block mainBlock = blockchain.getBlockByNumber(block.getNumber());
679 if (!block.getHash().equals(mainBlock.getHash())) {
680 return null;
681 }
682 txInfo.setTransaction(block.getTransactionsList().get(txInfo.getIndex()));
683 }
684
685 if (txInfo == null) {
686 return null;
687 }
688
689 return s = new TransactionResultDTO(block, txInfo.getIndex(), txInfo.getReceipt().getTransaction());
690 } finally {
691 logger.debug("eth_getTransactionByHash({}): {}", transactionHash, s);
692 }
693 }
694
695 @Override
696 public TransactionResultDTO eth_getTransactionByBlockHashAndIndex(String blockHash, String index) {
697 TransactionResultDTO s = null;
698 try {
699 Block b = getBlockByJSonHash(blockHash);
700
701 if (b == null) {
702 return null;
703 }
704
705 int idx = JSonHexToInt(index);
706
707 if (idx >= b.getTransactionsList().size()) {
708 return null;
709 }
710
711 Transaction tx = b.getTransactionsList().get(idx);
712
713 return s = new TransactionResultDTO(b, idx, tx);
714 } finally {
715 if (logger.isDebugEnabled()) {
716 logger.debug("eth_getTransactionByBlockHashAndIndex({}, {}): {}", blockHash, index, s);
717 }
718 }
719 }
720
721 @Override
722 public TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrId, String index) {
723 TransactionResultDTO s = null;
724 try {
725 Optional<Block> block = web3InformationRetriever.getBlock(bnOrId);
726 if (!block.isPresent()) {
727 return null;
728 }
729
730 int idx = JSonHexToInt(index);
731 List<Transaction> txs = web3InformationRetriever.getTransactions(bnOrId);
732 if (idx >= txs.size()) {
733 return null;
734 }
735
736 s = new TransactionResultDTO(block.get(), idx, txs.get(idx));
737 return s;
738 } finally {
739 if (logger.isDebugEnabled()) {
740 logger.debug("eth_getTransactionByBlockNumberAndIndex({}, {}): {}", bnOrId, index, s);
741 }
742 }
743 }
744
745 @Override
746 public TransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) {
747 logger.trace("eth_getTransactionReceipt({})", transactionHash);
748
749 byte[] hash = stringHexToByteArray(transactionHash);
750 TransactionInfo txInfo = receiptStore.getInMainChain(hash, blockStore);
751
752 if (txInfo == null) {
753 logger.trace("No transaction info for {}", transactionHash);
754 return null;
755 }
756
757 Block block = blockStore.getBlockByHash(txInfo.getBlockHash());
758 Transaction tx = block.getTransactionsList().get(txInfo.getIndex());
759 txInfo.setTransaction(tx);
760
761 return new TransactionReceiptDTO(block, txInfo);
762 }
763
764 @Override
765 public BlockResultDTO eth_getUncleByBlockHashAndIndex(String blockHash, String uncleIdx) {
766 BlockResultDTO s = null;
767
768 try {
769 Block block = blockchain.getBlockByHash(stringHexToByteArray(blockHash));
770
771 if (block == null) {
772 return null;
773 }
774
775 s = getUncleResultDTO(uncleIdx, block);
776
777 return s;
778 } finally {
779 if (logger.isDebugEnabled()) {
780 logger.debug("eth_getUncleByBlockHashAndIndex({}, {}): {}", blockHash, uncleIdx, s);
781 }
782 }
783 }
784
785 private BlockResultDTO getUncleResultDTO(String uncleIdx, Block block) {
786 int idx = JSonHexToInt(uncleIdx);
787
788 if (idx >= block.getUncleList().size()) {
789 return null;
790 }
791
792 BlockHeader uncleHeader = block.getUncleList().get(idx);
793 Block uncle = blockchain.getBlockByHash(uncleHeader.getHash().getBytes());
794
795 if (uncle == null) {
796 boolean isRskip126Enabled = config.getActivationConfig().isActive(ConsensusRule.RSKIP126, uncleHeader.getNumber());
797 uncle = Block.createBlockFromHeader(uncleHeader, isRskip126Enabled);
798 }
799
800 return getBlockResult(uncle, false);
801 }
802
803 @Override
804 public BlockResultDTO eth_getUncleByBlockNumberAndIndex(String blockId, String uncleIdx) {
805 BlockResultDTO s = null;
806 try {
807 Optional<Block> block = web3InformationRetriever.getBlock(blockId);
808
809 if (!block.isPresent()) {
810 return null;
811 }
812
813 s = getUncleResultDTO(uncleIdx, block.get());
814
815 return s;
816 } finally {
817 if (logger.isDebugEnabled()) {
818 logger.debug("eth_getUncleByBlockNumberAndIndex({}, {}): {}", blockId, uncleIdx, s);
819 }
820 }
821 }
822
823 @Override
824 public String[] eth_getCompilers() {
825 String[] s = null;
826 try {
827 return s = new String[]{"solidity"};
828 } finally {
829 if (logger.isDebugEnabled()) {
830 logger.debug("eth_getCompilers(): {}", Arrays.toString(s));
831 }
832 }
833 }
834
835 @Override
836 public Map<String, CompilationResultDTO> eth_compileLLL(String contract) {
837 throw new UnsupportedOperationException("LLL compiler not supported");
838 }
839
840 @Override
841 public Map<String, CompilationResultDTO> eth_compileSerpent(String contract) {
842 throw new UnsupportedOperationException("Serpent compiler not supported");
843 }
844
845 @Override
846 public Map<String, CompilationResultDTO> eth_compileSolidity(String contract) {
847 throw new UnsupportedOperationException("Solidity compiler not supported");
848 }
849
850 @Override
851 public String eth_newFilter(FilterRequest fr) throws Exception {
852 String str = null;
853
854 try {
855 Filter filter = LogFilter.fromFilterRequest(fr, blockchain, blocksBloomStore);
856 int id = filterManager.registerFilter(filter);
857
858 str = toQuantityJsonHex(id);
859 return str;
860 } finally {
861 if (logger.isDebugEnabled()) {
862 logger.debug("eth_newFilter({}): {}", fr, str);
863 }
864 }
865 }
866
867 @Override
868 public String eth_newBlockFilter() {
869 String s = null;
870 try {
871 int id = filterManager.registerFilter(new NewBlockFilter());
872
873 s = toQuantityJsonHex(id);
874 return s;
875 } finally {
876 if (logger.isDebugEnabled()) {
877 logger.debug("eth_newBlockFilter(): {}", s);
878 }
879 }
880 }
881
882 @Override
883 public String eth_newPendingTransactionFilter() {
884 String s = null;
885 try {
886 int id = filterManager.registerFilter(new PendingTransactionFilter());
887
888 s = toQuantityJsonHex(id);
889 return s;
890 } finally {
891 if (logger.isDebugEnabled()) {
892 logger.debug("eth_newPendingTransactionFilter(): {}", s);
893 }
894 }
895 }
896
897 @Override
898 public boolean eth_uninstallFilter(String id) {
899 Boolean s = null;
900
901 try {
902 if (id == null) {
903 return false;
904 }
905
906 return filterManager.removeFilter(stringHexToBigInteger(id).intValue());
907 } finally {
908 if (logger.isDebugEnabled()) {
909 logger.debug("eth_uninstallFilter({}): {}", id, s);
910 }
911 }
912 }
913
914 @Override
915 public Object[] eth_getFilterChanges(String id) {
916 logger.debug("eth_getFilterChanges ...");
917
918 // TODO(mc): this is a quick solution that seems to work with OpenZeppelin tests, but needs to be reviewed
919 // We do the same as in Ganache: mine a block in each request to getFilterChanges so block filters work
920 if (config.isMinerClientEnabled() && config.minerClientAutoMine()) {
921 minerServer.buildBlockToMine(false);
922 minerClient.mineBlock();
923 }
924
925 Object[] s = null;
926
927 try {
928 s = getFilterEvents(id, true);
929 } finally {
930 if (logger.isDebugEnabled()) {
931 logger.debug("eth_getFilterChanges({}): {}", id, Arrays.toString(s));
932 }
933 }
934
935 return s;
936 }
937
938 @Override
939 public Object[] eth_getFilterLogs(String id) {
940 logger.debug("eth_getFilterLogs ...");
941
942 Object[] s = null;
943
944 try {
945 s = getFilterEvents(id, false);
946 } finally {
947 if (logger.isDebugEnabled()) {
948 logger.debug("eth_getFilterLogs({}): {}", id, Arrays.toString(s));
949 }
950 }
951
952 return s;
953 }
954
955 private Object[] getFilterEvents(String id, boolean newevents) {
956 return this.filterManager.getFilterEvents(stringHexToBigInteger(id).intValue(), newevents);
957 }
958
959 @Override
960 public Object[] eth_getLogs(FilterRequest fr) throws Exception {
961 logger.debug("eth_getLogs ...");
962 String id = eth_newFilter(fr);
963 Object[] ret = eth_getFilterLogs(id);
964 eth_uninstallFilter(id);
965 return ret;
966 }
967
968 @Override
969 public Map<String, String> rpc_modules() {
970 logger.debug("rpc_modules...");
971
972 Map<String, String> map = new HashMap<>();
973
974 for (ModuleDescription module : config.getRpcModules()) {
975 if (module.isEnabled()) {
976 map.put(module.getName(), module.getVersion());
977 }
978 }
979
980 return map;
981 }
982
983 @Override
984 public void db_putString() {
985 }
986
987 @Override
988 public void db_getString() {
989 }
990
991 @Override
992 public boolean eth_submitWork(String nonce, String header, String mince) {
993 throw new UnsupportedOperationException("Not implemeted yet");
994 }
995
996 @Override
997 public boolean eth_submitHashrate(String hashrate, String id) {
998 throw new UnsupportedOperationException("Not implemeted yet");
999 }
1000
1001 @Override
1002 public void db_putHex() {
1003 }
1004
1005 @Override
1006 public void db_getHex() {
1007 }
1008
1009 @Override
1010 public String personal_newAccountWithSeed(String seed) {
1011 return personalModule.newAccountWithSeed(seed);
1012 }
1013
1014 @Override
1015 public String personal_newAccount(String passphrase) {
1016 return personalModule.newAccount(passphrase);
1017 }
1018
1019 @Override
1020 public String personal_importRawKey(String key, String passphrase) {
1021 return personalModule.importRawKey(key, passphrase);
1022 }
1023
1024 @Override
1025 public String personal_dumpRawKey(String address) throws Exception {
1026 return personalModule.dumpRawKey(address);
1027 }
1028
1029 @Override
1030 public String[] personal_listAccounts() {
1031 return personalModule.listAccounts();
1032 }
1033
1034 @Override
1035 public String personal_sendTransaction(CallArguments args, String passphrase) throws Exception {
1036 return personalModule.sendTransaction(args, passphrase);
1037 }
1038
1039 @Override
1040 public boolean personal_unlockAccount(String address, String passphrase, String duration) {
1041 return personalModule.unlockAccount(address, passphrase, duration);
1042 }
1043
1044 @Override
1045 public boolean personal_lockAccount(String address) {
1046 return personalModule.lockAccount(address);
1047 }
1048
1049 @Override
1050 public EthModule getEthModule() {
1051 return ethModule;
1052 }
1053
1054 @Override
1055 public EvmModule getEvmModule() {
1056 return evmModule;
1057 }
1058
1059 @Override
1060 public TxPoolModule getTxPoolModule() {
1061 return txPoolModule;
1062 }
1063
1064 @Override
1065 public MnrModule getMnrModule() {
1066 return mnrModule;
1067 }
1068
1069 @Override
1070 public DebugModule getDebugModule() {
1071 return debugModule;
1072 }
1073
1074 @Override
1075 public TraceModule getTraceModule() {
1076 return traceModule;
1077 }
1078
1079 @Override
1080 public RskModule getRskModule() {
1081 return rskModule;
1082 }
1083
1084 /**
1085 * Adds an address or block to the list of banned addresses
1086 * It supports IPV4 and IPV6 addresses with an optional number of bits to ignore
1087 *
1088 * "192.168.51.1" is a valid address
1089 * "192.168.51.1/16" is a valid block
1090 *
1091 * @param address the address or block to be banned
1092 */
1093 @Override
1094 public void sco_banAddress(String address) {
1095 if (this.peerScoringManager == null) {
1096 return;
1097 }
1098
1099 try {
1100 this.peerScoringManager.banAddress(address);
1101 } catch (InvalidInetAddressException e) {
1102 throw invalidParamError("invalid banned address " + address, e);
1103 }
1104 }
1105
1106 /**
1107 * Removes an address or block to the list of banned addresses
1108 * It supports IPV4 and IPV6 addresses with an optional number of bits to ignore
1109 *
1110 * "192.168.51.1" is a valid address
1111 * "192.168.51.1/16" is a valid block
1112 *
1113 * @param address the address or block to be removed
1114 */
1115 @Override
1116 public void sco_unbanAddress(String address) {
1117 if (this.peerScoringManager == null) {
1118 return;
1119 }
1120
1121 try {
1122 this.peerScoringManager.unbanAddress(address);
1123 } catch (InvalidInetAddressException e) {
1124 throw invalidParamError("invalid banned address " + address, e);
1125 }
1126 }
1127
1128 /**
1129 * Returns the collected peer scoring information
1130 * since the start of the node start
1131 *
1132 * @return the list of scoring information, per node id and address
1133 */
1134 @Override
1135 public PeerScoringInformation[] sco_peerList() {
1136 if (this.peerScoringManager != null) {
1137 return this.peerScoringManager.getPeersInformation().toArray(new PeerScoringInformation[0]);
1138 }
1139
1140 return null;
1141 }
1142
1143 /**
1144 * Returns the list of banned addresses and blocks
1145 *
1146 * @return the list of banned addresses and blocks
1147 */
1148 @Override
1149 public String[] sco_bannedAddresses() {
1150 return this.peerScoringManager.getBannedAddresses().toArray(new String[0]);
1151 }
1152
1153 /**
1154 * Returns a reputation summary of all the peers connected to this node
1155 *
1156 * @return the actual summary
1157 */
1158 public PeerScoringReputationSummary sco_reputationSummary() {
1159 return PeerScoringReporterUtil.buildReputationSummary(peerScoringManager.getPeersInformation());
1160 }
1161 }