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 }