Coverage Summary for Class: MinerUtils (co.rsk.mine)

Class Class, % Method, % Line, %
MinerUtils 0% (0/1) 0% (0/12) 0% (0/89)


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 co.rsk.mine; 20  21 import co.rsk.bitcoinj.core.BtcTransaction; 22 import co.rsk.bitcoinj.core.NetworkParameters; 23 import co.rsk.config.RskMiningConstants; 24 import co.rsk.core.Coin; 25 import co.rsk.core.RskAddress; 26 import co.rsk.core.bc.PendingState; 27 import co.rsk.crypto.Keccak256; 28 import co.rsk.db.RepositorySnapshot; 29 import co.rsk.remasc.RemascTransaction; 30 import org.bouncycastle.util.Arrays; 31 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 32 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 33 import org.ethereum.core.Transaction; 34 import org.ethereum.core.TransactionPool; 35 import org.ethereum.rpc.TypeConverter; 36 import org.slf4j.Logger; 37 import org.slf4j.LoggerFactory; 38  39 import java.io.ByteArrayOutputStream; 40 import java.io.IOException; 41 import java.math.BigInteger; 42 import java.security.SecureRandom; 43 import java.util.ArrayList; 44 import java.util.Collections; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.function.Function; 48  49 public class MinerUtils { 50  51  private static final Logger logger = LoggerFactory.getLogger("minerserver"); 52  53  public static co.rsk.bitcoinj.core.BtcTransaction getBitcoinMergedMiningCoinbaseTransaction(co.rsk.bitcoinj.core.NetworkParameters params, MinerWork work) { 54  return getBitcoinMergedMiningCoinbaseTransaction(params, TypeConverter.stringHexToByteArray(work.getBlockHashForMergedMining())); 55  } 56  57  public static co.rsk.bitcoinj.core.BtcTransaction getBitcoinMergedMiningCoinbaseTransaction(co.rsk.bitcoinj.core.NetworkParameters params, byte[] blockHashForMergedMining) { 58  SecureRandom random = new SecureRandom(); 59  byte[] prefix = new byte[random.nextInt(1000)]; 60  random.nextBytes(prefix); 61  byte[] bytes = Arrays.concatenate(prefix, RskMiningConstants.RSK_TAG, blockHashForMergedMining); 62  63  return getBitcoinCoinbaseTransaction(params, bytes); 64  } 65  66  public static co.rsk.bitcoinj.core.BtcTransaction getBitcoinCoinbaseTransaction(co.rsk.bitcoinj.core.NetworkParameters params, byte[] additionalData) { 67  68  co.rsk.bitcoinj.core.BtcTransaction coinbaseTransaction = new co.rsk.bitcoinj.core.BtcTransaction(params); 69  70  // Add the data to the scriptSig of first input 71  co.rsk.bitcoinj.core.TransactionInput ti = new co.rsk.bitcoinj.core.TransactionInput(params, coinbaseTransaction, new byte[0]); 72  coinbaseTransaction.addInput(ti); 73  74  ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream(); 75  co.rsk.bitcoinj.core.BtcECKey key = new co.rsk.bitcoinj.core.BtcECKey(); 76  try { 77  co.rsk.bitcoinj.script.Script.writeBytes(scriptPubKeyBytes, key.getPubKey()); 78  } catch (IOException e) { 79  throw new RuntimeException(e); 80  } 81  scriptPubKeyBytes.write(co.rsk.bitcoinj.script.ScriptOpCodes.OP_CHECKSIG); 82  coinbaseTransaction.addOutput(new co.rsk.bitcoinj.core.TransactionOutput(params, coinbaseTransaction, co.rsk.bitcoinj.core.Coin.valueOf(50, 0), scriptPubKeyBytes.toByteArray())); 83  84  coinbaseTransaction.addOutput(new co.rsk.bitcoinj.core.TransactionOutput(params, coinbaseTransaction, co.rsk.bitcoinj.core.Coin.valueOf(0), additionalData)); 85  86  return coinbaseTransaction; 87  } 88  89  public static co.rsk.bitcoinj.core.BtcTransaction getBitcoinMergedMiningCoinbaseTransactionWithTwoTags( 90  co.rsk.bitcoinj.core.NetworkParameters params, 91  MinerWork work, 92  MinerWork work2) { 93  return getBitcoinMergedMiningCoinbaseTransactionWithTwoTags( 94  params, 95  TypeConverter.stringHexToByteArray(work.getBlockHashForMergedMining()), 96  TypeConverter.stringHexToByteArray(work2.getBlockHashForMergedMining())); 97  } 98  99  public static co.rsk.bitcoinj.core.BtcTransaction getBitcoinMergedMiningCoinbaseTransactionWithTwoTags( 100  co.rsk.bitcoinj.core.NetworkParameters params, 101  byte[] blockHashForMergedMining1, 102  byte[] blockHashForMergedMining2) { 103  co.rsk.bitcoinj.core.BtcTransaction coinbaseTransaction = new co.rsk.bitcoinj.core.BtcTransaction(params); 104  //Add a random number of random bytes before the RSK tag 105  SecureRandom random = new SecureRandom(); 106  byte[] prefix = new byte[random.nextInt(1000)]; 107  random.nextBytes(prefix); 108  109  byte[] bytes0 = Arrays.concatenate(RskMiningConstants.RSK_TAG, blockHashForMergedMining1); 110  // addsecond tag 111  byte[] bytes1 = Arrays.concatenate(bytes0, RskMiningConstants.RSK_TAG, blockHashForMergedMining2); 112  113  co.rsk.bitcoinj.core.TransactionInput ti = new co.rsk.bitcoinj.core.TransactionInput(params, coinbaseTransaction, prefix); 114  coinbaseTransaction.addInput(ti); 115  ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream(); 116  co.rsk.bitcoinj.core.BtcECKey key = new co.rsk.bitcoinj.core.BtcECKey(); 117  try { 118  co.rsk.bitcoinj.script.Script.writeBytes(scriptPubKeyBytes, key.getPubKey()); 119  } catch (IOException e) { 120  throw new RuntimeException(e); 121  } 122  scriptPubKeyBytes.write(co.rsk.bitcoinj.script.ScriptOpCodes.OP_CHECKSIG); 123  coinbaseTransaction.addOutput(new co.rsk.bitcoinj.core.TransactionOutput(params, coinbaseTransaction, co.rsk.bitcoinj.core.Coin.valueOf(50, 0), scriptPubKeyBytes.toByteArray())); 124  // add opreturn output with two tags 125  ByteArrayOutputStream output2Bytes = new ByteArrayOutputStream(); 126  output2Bytes.write(co.rsk.bitcoinj.script.ScriptOpCodes.OP_RETURN); 127  128  try { 129  co.rsk.bitcoinj.script.Script.writeBytes(output2Bytes, bytes1); 130  } catch (IOException e) { 131  throw new RuntimeException(e); 132  } 133  coinbaseTransaction.addOutput( 134  new co.rsk.bitcoinj.core.TransactionOutput(params, coinbaseTransaction, co.rsk.bitcoinj.core.Coin.valueOf(1), output2Bytes.toByteArray())); 135  136  return coinbaseTransaction; 137  } 138  139  public static co.rsk.bitcoinj.core.BtcBlock getBitcoinMergedMiningBlock(co.rsk.bitcoinj.core.NetworkParameters params, BtcTransaction transaction) { 140  return getBitcoinMergedMiningBlock(params, Collections.singletonList(transaction)); 141  } 142  143  public static co.rsk.bitcoinj.core.BtcBlock getBitcoinMergedMiningBlock(co.rsk.bitcoinj.core.NetworkParameters params, List<BtcTransaction> transactions) { 144  co.rsk.bitcoinj.core.Sha256Hash prevBlockHash = co.rsk.bitcoinj.core.Sha256Hash.ZERO_HASH; 145  long time = System.currentTimeMillis() / 1000L; 146  long difficultyTarget = co.rsk.bitcoinj.core.Utils.encodeCompactBits(params.getMaxTarget()); 147  return new co.rsk.bitcoinj.core.BtcBlock(params, params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.CURRENT), prevBlockHash, null, time, difficultyTarget, 0, transactions); 148  } 149  150  /** 151  * Takes in a proofBuilderFunction (e.g. buildFromTxHashes) 152  * and executes it on the builder corresponding to this block number. 153  */ 154  public static byte[] buildMerkleProof( 155  ActivationConfig activationConfig, 156  Function<MerkleProofBuilder, byte[]> proofBuilderFunction, 157  long blockNumber) { 158  if (activationConfig.isActive(ConsensusRule.RSKIP92, blockNumber)) { 159  return proofBuilderFunction.apply(new Rskip92MerkleProofBuilder()); 160  } else { 161  return proofBuilderFunction.apply(new GenesisMerkleProofBuilder()); 162  } 163  } 164  165  public List<org.ethereum.core.Transaction> getAllTransactions(TransactionPool transactionPool) { 166  167  List<Transaction> txs = transactionPool.getPendingTransactions(); 168  169  return PendingState.sortByPriceTakingIntoAccountSenderAndNonce(txs); 170  } 171  172  public List<org.ethereum.core.Transaction> filterTransactions(List<Transaction> txsToRemove, List<Transaction> txs, Map<RskAddress, BigInteger> accountNonces, RepositorySnapshot originalRepo, Coin minGasPrice) { 173  List<org.ethereum.core.Transaction> txsResult = new ArrayList<>(); 174  for (org.ethereum.core.Transaction tx : txs) { 175  try { 176  Keccak256 hash = tx.getHash(); 177  Coin txValue = tx.getValue(); 178  BigInteger txNonce = new BigInteger(1, tx.getNonce()); 179  RskAddress txSender = tx.getSender(); 180  logger.debug("Examining tx={} sender: {} value: {} nonce: {}", hash, txSender, txValue, txNonce); 181  182  BigInteger expectedNonce; 183  184  if (accountNonces.containsKey(txSender)) { 185  expectedNonce = accountNonces.get(txSender).add(BigInteger.ONE); 186  } else { 187  expectedNonce = originalRepo.getNonce(txSender); 188  } 189  190  if (!(tx instanceof RemascTransaction) && tx.getGasPrice().compareTo(minGasPrice) < 0) { 191  logger.warn("Rejected tx={} because of low gas account {}, removing tx from pending state.", hash, txSender); 192  193  txsToRemove.add(tx); 194  continue; 195  } 196  197  if (!expectedNonce.equals(txNonce)) { 198  logger.warn("Invalid nonce, expected {}, found {}, tx={}", expectedNonce, txNonce, hash); 199  continue; 200  } 201  202  accountNonces.put(txSender, txNonce); 203  204  logger.debug("Accepted tx={} sender: {} value: {} nonce: {}", hash, txSender, txValue, txNonce); 205  } catch (Exception e) { 206  // Txs that can't be selected by any reason should be removed from pending state 207  logger.warn(String.format("Error when processing tx=%s", tx.getHash()), e); 208  if (txsToRemove != null) { 209  txsToRemove.add(tx); 210  } else { 211  logger.error("Can't remove invalid txs from pending state."); 212  } 213  continue; 214  } 215  216  txsResult.add(tx); 217  } 218  219  logger.debug("Ending getTransactions {}", txsResult.size()); 220  221  return txsResult; 222  } 223 }