Coverage Summary for Class: ExecutionBlockRetriever (co.rsk.rpc)

Class Class, % Method, % Line, %
ExecutionBlockRetriever 100% (1/1) 75% (3/4) 19.3% (11/57)


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; 20  21 import co.rsk.core.Coin; 22 import co.rsk.core.bc.BlockResult; 23 import co.rsk.core.bc.MiningMainchainView; 24 import co.rsk.mine.BlockToMineBuilder; 25 import co.rsk.mine.MinerServer; 26 import org.ethereum.core.Block; 27 import org.ethereum.core.BlockHeader; 28 import org.ethereum.core.Blockchain; 29 import org.ethereum.util.Utils; 30  31 import javax.annotation.Nullable; 32 import java.util.Collections; 33 import java.util.List; 34 import java.util.Optional; 35  36 import static org.ethereum.rpc.exception.RskJsonRpcRequestException.invalidParamError; 37  38 /** 39  * Encapsulates the logic to retrieve or create an execution block 40  * for Web3 calls. 41  */ 42 public class ExecutionBlockRetriever { 43  private static final String LATEST_ID = "latest"; 44  private static final String PENDING_ID = "pending"; 45  46  private final MiningMainchainView miningMainchainView; 47  private final Blockchain blockchain; 48  private final MinerServer minerServer; 49  private final BlockToMineBuilder builder; 50  51  @Nullable 52  private Block cachedBlock; 53  @Nullable 54  private BlockResult cachedResult; 55  56  public ExecutionBlockRetriever(MiningMainchainView miningMainchainView, 57  Blockchain blockchain, 58  MinerServer minerServer, 59  BlockToMineBuilder builder) { 60  this.miningMainchainView = miningMainchainView; 61  this.blockchain = blockchain; 62  this.minerServer = minerServer; 63  this.builder = builder; 64  } 65  66  @Deprecated 67  public BlockResult getExecutionBlock_workaround(String bnOrId) { 68  if (LATEST_ID.equals(bnOrId)) { 69  return newBlockResult_workaround(blockchain.getBestBlock()); 70  } 71  72  if (PENDING_ID.equals(bnOrId)) { 73  Optional<Block> latestBlock = minerServer.getLatestBlock(); 74  if (latestBlock.isPresent()) { 75  return newBlockResult_workaround(latestBlock.get()); 76  } 77  78  Block bestBlock = blockchain.getBestBlock(); 79  if (cachedBlock == null || !bestBlock.isParentOf(cachedBlock)) { 80  81  // If the miner server is not running there is no one to update the mining mainchain view, 82  // thus breaking eth_call with 'pending' parameter 83  // 84  // This is just a provisional fix not intended to remain in the long run 85  if (!minerServer.isRunning()) { 86  miningMainchainView.addBest(bestBlock.getHeader()); 87  } 88  89  List<BlockHeader> mainchainHeaders = miningMainchainView.get(); 90  cachedResult = builder.build(mainchainHeaders, null); 91  } 92  93  return cachedResult; 94  } 95  96  // Is the block specifier either a hexadecimal or decimal number? 97  Optional<Long> executionBlockNumber = Optional.empty(); 98  99  if (Utils.isHexadecimalString(bnOrId)) { 100  executionBlockNumber = Optional.of(Utils.hexadecimalStringToLong(bnOrId)); 101  } else if (Utils.isDecimalString(bnOrId)) { 102  executionBlockNumber = Optional.of(Utils.decimalStringToLong(bnOrId)); 103  } 104  105  if (executionBlockNumber.isPresent()) { 106  Block executionBlock = blockchain.getBlockByNumber(executionBlockNumber.get()); 107  if (executionBlock == null) { 108  throw invalidParamError(String.format("Invalid block number %d", executionBlockNumber.get())); 109  } 110  return newBlockResult_workaround(executionBlock); 111  } 112  113  // If we got here, the specifier given is unsupported 114  throw invalidParamError(String.format( 115  "Unsupported block specifier '%s'. Can only be either 'latest', " + 116  "'pending' or a specific block number (either hex - prepending '0x' or decimal).", 117  bnOrId)); 118  } 119  120  public Block getExecutionBlock(String bnOrId) { 121  if (LATEST_ID.equals(bnOrId)) { 122  return blockchain.getBestBlock(); 123  } 124  125  if (PENDING_ID.equals(bnOrId)) { 126  Optional<Block> latestBlock = minerServer.getLatestBlock(); 127  if (latestBlock.isPresent()) { 128  return latestBlock.get(); 129  } 130  131  Block bestBlock = blockchain.getBestBlock(); 132  if (cachedBlock == null || !bestBlock.isParentOf(cachedBlock)) { 133  134  // If the miner server is not running there is no one to update the mining mainchain view, 135  // thus breaking eth_call with 'pending' parameter 136  // 137  // This is just a provisional fix not intended to remain in the long run 138  if (!minerServer.isRunning()) { 139  miningMainchainView.addBest(bestBlock.getHeader()); 140  } 141  142  List<BlockHeader> mainchainHeaders = miningMainchainView.get(); 143  cachedBlock = builder.build(mainchainHeaders, null).getBlock(); 144  } 145  146  return cachedBlock; 147  } 148  149  // Is the block specifier either a hexadecimal or decimal number? 150  Optional<Long> executionBlockNumber = Optional.empty(); 151  152  if (Utils.isHexadecimalString(bnOrId)) { 153  executionBlockNumber = Optional.of(Utils.hexadecimalStringToLong(bnOrId)); 154  } else if (Utils.isDecimalString(bnOrId)) { 155  executionBlockNumber = Optional.of(Utils.decimalStringToLong(bnOrId)); 156  } 157  158  if (executionBlockNumber.isPresent()) { 159  Block executionBlock = blockchain.getBlockByNumber(executionBlockNumber.get()); 160  if (executionBlock == null) { 161  throw invalidParamError(String.format("Invalid block number %d", executionBlockNumber.get())); 162  } 163  return executionBlock; 164  } 165  166  // If we got here, the specifier given is unsupported 167  throw invalidParamError(String.format( 168  "Unsupported block specifier '%s'. Can only be either 'latest', " + 169  "'pending' or a specific block number (either hex - prepending '0x' or decimal).", 170  bnOrId)); 171  } 172  173  @Deprecated 174  private static BlockResult newBlockResult_workaround(Block block) { 175  return new BlockResult( 176  block, 177  Collections.emptyList(), 178  Collections.emptyList(), 179  0, 180  Coin.ZERO, 181  null 182  ); 183  } 184 }