Coverage Summary for Class: ReleaseTransactionBuilder (co.rsk.peg)

Class Method, % Line, %
ReleaseTransactionBuilder 0% (0/13) 0% (0/52)
ReleaseTransactionBuilder$BuildResult 0% (0/3) 0% (0/5)
Total 0% (0/16) 0% (0/57)


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.peg; 20  21 import co.rsk.bitcoinj.core.*; 22 import co.rsk.bitcoinj.wallet.SendRequest; 23 import co.rsk.bitcoinj.wallet.Wallet; 24 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 25 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 26 import org.slf4j.Logger; 27 import org.slf4j.LoggerFactory; 28  29 import java.util.*; 30 import java.util.stream.Collectors; 31  32 /** 33  * Given a set of UTXOs, a ReleaseTransactionBuilder 34  * knows how to build a release transaction 35  * of a certain amount to a certain address, 36  * and how to signal the used UTXOs so they 37  * can be invalidated. 38  * 39  * @author Ariel Mendelzon 40  */ 41 public class ReleaseTransactionBuilder { 42  public class BuildResult { 43  private final BtcTransaction btcTx; 44  private final List<UTXO> selectedUTXOs; 45  46  public BuildResult(BtcTransaction btcTx, List<UTXO> selectedUTXOs) { 47  this.btcTx = btcTx; 48  this.selectedUTXOs = selectedUTXOs; 49  } 50  51  public BtcTransaction getBtcTx() { 52  return btcTx; 53  } 54  55  public List<UTXO> getSelectedUTXOs() { 56  return selectedUTXOs; 57  } 58  } 59  60  private interface SendRequestConfigurator { 61  void configure(SendRequest sr); 62  } 63  64  private static final Logger logger = LoggerFactory.getLogger("ReleaseTransactionBuilder"); 65  66  private final NetworkParameters params; 67  private final Wallet wallet; 68  private final Address changeAddress; 69  private final Coin feePerKb; 70  private final ActivationConfig.ForBlock activations; 71  72  public ReleaseTransactionBuilder( 73  NetworkParameters params, 74  Wallet wallet, 75  Address changeAddress, 76  Coin feePerKb, 77  ActivationConfig.ForBlock activations 78  ) { 79  this.params = params; 80  this.wallet = wallet; 81  this.changeAddress = changeAddress; 82  this.feePerKb = feePerKb; 83  this.activations = activations; 84  } 85  86  public Wallet getWallet() { 87  return wallet; 88  } 89  90  public Address getChangeAddress() { 91  return changeAddress; 92  } 93  94  public Coin getFeePerKb() { 95  return feePerKb; 96  } 97  98  public Optional<BuildResult> buildAmountTo(Address to, Coin amount) { 99  return buildWithConfiguration((SendRequest sr) -> { 100  sr.tx.addOutput(amount, to); 101  sr.changeAddress = changeAddress; 102  }, String.format("sending %s to %s", amount, to)); 103  } 104  105  public Optional<BuildResult> buildEmptyWalletTo(Address to) { 106  return buildWithConfiguration((SendRequest sr) -> { 107  sr.tx.addOutput(Coin.ZERO, to); 108  sr.changeAddress = to; 109  sr.emptyWallet = true; 110  }, String.format("emptying wallet to %s", to)); 111  } 112  113  private Optional<BuildResult> buildWithConfiguration( 114  SendRequestConfigurator sendRequestConfigurator, 115  String operationDescription) { 116  117  // Build a tx and send request and configure it 118  BtcTransaction btcTx = new BtcTransaction(params); 119  120  if (activations.isActive(ConsensusRule.RSKIP201)) { 121  btcTx.setVersion(2); 122  } 123  124  SendRequest sr = SendRequest.forTx(btcTx); 125  // Default settings 126  defaultSettingsConfigurator.configure(sr); 127  // Specific settings 128  sendRequestConfigurator.configure(sr); 129  130  try { 131  wallet.completeTx(sr); 132  133  // Disconnect input from output because we don't need the reference and it interferes serialization 134  for (TransactionInput transactionInput : btcTx.getInputs()) { 135  transactionInput.disconnect(); 136  } 137  138  List<UTXO> selectedUTXOs = wallet 139  .getUTXOProvider().getOpenTransactionOutputs(wallet.getWatchedAddresses()).stream() 140  .filter(utxo -> 141  btcTx.getInputs().stream().anyMatch(input -> 142  input.getOutpoint().getHash().equals(utxo.getHash()) && 143  input.getOutpoint().getIndex() == utxo.getIndex() 144  ) 145  ) 146  .collect(Collectors.toList()); 147  148  return Optional.of(new BuildResult(btcTx, selectedUTXOs)); 149  } catch (InsufficientMoneyException e) { 150  logger.warn(String.format("Not enough BTC in the wallet to complete %s", operationDescription), e); 151  // Comment out panic logging for now 152  // panicProcessor.panic("nomoney", "Not enough confirmed BTC in the federation wallet to complete " + rskTxHash + " " + btcTx); 153  return Optional.empty(); 154  } catch (Wallet.CouldNotAdjustDownwards e) { 155  logger.warn(String.format("A user output could not be adjusted downwards to pay tx fees %s", operationDescription), e); 156  // Comment out panic logging for now 157  // panicProcessor.panic("couldnotadjustdownwards", "A user output could not be adjusted downwards to pay tx fees " + rskTxHash + " " + btcTx); 158  return Optional.empty(); 159  } catch (Wallet.ExceededMaxTransactionSize e) { 160  logger.warn(String.format("Tx size too big %s", operationDescription), e); 161  // Comment out panic logging for now 162  // panicProcessor.panic("exceededmaxtransactionsize", "Tx size too big " + rskTxHash + " " + btcTx); 163  return Optional.empty(); 164  } catch (UTXOProviderException e) { 165  logger.warn(String.format("UTXO provider exception sending %s", operationDescription), e); 166  // Comment out panic logging for now 167  // panicProcessor.panic("utxoprovider", "UTXO provider exception " + rskTxHash + " " + btcTx); 168  return Optional.empty(); 169  } 170  } 171  172  private final SendRequestConfigurator defaultSettingsConfigurator = (SendRequest sr) -> { 173  sr.missingSigsMode = Wallet.MissingSigsMode.USE_OP_ZERO; 174  sr.feePerKb = getFeePerKb(); 175  sr.shuffleOutputs = false; 176  sr.recipientsPayFees = true; 177  }; 178 }