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

Class Method, % Line, %
Bridge 0% (0/76) 0% (0/540)
Bridge$BridgeParsedData 0% (0/1) 0% (0/1)
Total 0% (0/77) 0% (0/541)


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.store.BlockStoreException; 23 import co.rsk.config.BridgeConstants; 24 import co.rsk.core.RskAddress; 25 import co.rsk.crypto.Keccak256; 26 import co.rsk.panic.PanicProcessor; 27 import co.rsk.peg.bitcoin.MerkleBranch; 28 import co.rsk.peg.utils.BtcTransactionFormatUtils; 29 import co.rsk.peg.whitelist.LockWhitelistEntry; 30 import co.rsk.peg.whitelist.OneOffWhiteListEntry; 31 import co.rsk.rpc.modules.trace.ProgramSubtrace; 32 import com.google.common.annotations.VisibleForTesting; 33 import org.ethereum.config.Constants; 34 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 35 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 36 import org.ethereum.core.Block; 37 import org.ethereum.core.CallTransaction; 38 import org.ethereum.core.Repository; 39 import org.ethereum.core.Transaction; 40 import org.ethereum.db.BlockStore; 41 import org.ethereum.db.ReceiptStore; 42 import org.ethereum.util.ByteUtil; 43 import org.ethereum.vm.DataWord; 44 import org.ethereum.vm.LogInfo; 45 import org.ethereum.vm.PrecompiledContracts; 46 import org.ethereum.vm.exception.VMException; 47 import org.ethereum.vm.program.Program; 48 import org.slf4j.Logger; 49 import org.slf4j.LoggerFactory; 50  51 import java.io.IOException; 52 import java.math.BigInteger; 53 import java.time.Instant; 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.List; 57 import java.util.Optional; 58 import java.util.stream.Collectors; 59  60 /** 61  * Precompiled contract that manages the 2 way peg between bitcoin and RSK. 62  * This class is just a wrapper, actual functionality is found in BridgeSupport. 63  * @author Oscar Guindzberg 64  */ 65 public class Bridge extends PrecompiledContracts.PrecompiledContract { 66  67  private static final Logger logger = LoggerFactory.getLogger("bridge"); 68  private static final PanicProcessor panicProcessor = new PanicProcessor(); 69  70  // No parameters 71  public static final CallTransaction.Function UPDATE_COLLECTIONS = BridgeMethods.UPDATE_COLLECTIONS.getFunction(); 72  // Parameters: an array of bitcoin blocks serialized with the bitcoin wire protocol format 73  public static final CallTransaction.Function RECEIVE_HEADERS = BridgeMethods.RECEIVE_HEADERS.getFunction(); 74  // Parameters: a header of bitcoin blocks serialized with the bitcoin wire protocol format 75  public static final CallTransaction.Function RECEIVE_HEADER = BridgeMethods.RECEIVE_HEADER.getFunction(); 76  // Parameters: 77  // - A bitcoin tx, serialized with the bitcoin wire protocol format 78  // - The bitcoin block height that contains the tx 79  // - A merkle tree that shows the tx is included in that block, serialized with the bitcoin wire protocol format. 80  public static final CallTransaction.Function REGISTER_BTC_TRANSACTION = BridgeMethods.REGISTER_BTC_TRANSACTION.getFunction(); 81  // No parameters, the current rsk tx is used as input. 82  public static final CallTransaction.Function RELEASE_BTC = BridgeMethods.RELEASE_BTC.getFunction(); 83  // Parameters: 84  // Federator public key. 85  // Transaction signature array, one for each btc tx input. 86  // Rsk tx hash of the tx that required the release of funds. 87  public static final CallTransaction.Function ADD_SIGNATURE = BridgeMethods.ADD_SIGNATURE.getFunction(); 88  // Returns a StateForFederator encoded in RLP 89  public static final CallTransaction.Function GET_STATE_FOR_BTC_RELEASE_CLIENT = BridgeMethods.GET_STATE_FOR_BTC_RELEASE_CLIENT.getFunction(); 90  // Returns a BridgeState encoded in RLP 91  public static final CallTransaction.Function GET_STATE_FOR_DEBUGGING = BridgeMethods.GET_STATE_FOR_DEBUGGING.getFunction(); 92  // Return the bitcoin blockchain best chain height know by the bridge contract 93  public static final CallTransaction.Function GET_BTC_BLOCKCHAIN_BEST_CHAIN_HEIGHT = BridgeMethods.GET_BTC_BLOCKCHAIN_BEST_CHAIN_HEIGHT.getFunction(); 94  // Returns an array of block hashes known by the bridge contract. Federators can use this to find what is the latest block in the mainchain the bridge has. 95  // The goal of this function is to help synchronize bridge and federators blockchains. 96  // Protocol inspired by bitcoin sync protocol, see block locator in https://en.bitcoin.it/wiki/Protocol_documentation#getheaders 97  public static final CallTransaction.Function GET_BTC_BLOCKCHAIN_BLOCK_LOCATOR = BridgeMethods.GET_BTC_BLOCKCHAIN_BLOCK_LOCATOR.getFunction(); 98  // Return the height of the initial block stored in the bridge's bitcoin blockchain 99  public static final CallTransaction.Function GET_BTC_BLOCKCHAIN_INITIAL_BLOCK_HEIGHT = BridgeMethods.GET_BTC_BLOCKCHAIN_INITIAL_BLOCK_HEIGHT.getFunction(); 100  // Returns the block hash of the bridge contract's best chain at the given depth, meaning depth zero will 101  // yield the best chain head hash and depth one will yield its parent hash, and so on and so forth. 102  // Federators use this to find what is the latest block in the mainchain the bridge has 103  // (replacing the need for getBtcBlockchainBlockLocator). 104  // The goal of this function is to help synchronize bridge and federators blockchains. 105  public static final CallTransaction.Function GET_BTC_BLOCKCHAIN_BLOCK_HASH_AT_DEPTH = BridgeMethods.GET_BTC_BLOCKCHAIN_BLOCK_HASH_AT_DEPTH.getFunction(); 106  // Returns the confirmations number of the block for the given transaction. If its not valid or its not part of the main chain it returns a negative number 107  // The goal of this function is to help contracts can use this to validate BTC transactions 108  public static final CallTransaction.Function GET_BTC_TRANSACTION_CONFIRMATIONS = BridgeMethods.GET_BTC_TRANSACTION_CONFIRMATIONS.getFunction(); 109  // Returns the minimum amount of satoshis a user should send to the federation. 110  public static final CallTransaction.Function GET_MINIMUM_LOCK_TX_VALUE = BridgeMethods.GET_MINIMUM_LOCK_TX_VALUE.getFunction(); 111  112  // Returns whether a given btc tx hash was already processed by the bridge 113  public static final CallTransaction.Function IS_BTC_TX_HASH_ALREADY_PROCESSED = BridgeMethods.IS_BTC_TX_HASH_ALREADY_PROCESSED.getFunction(); 114  // Returns whether a given btc tx hash was already processed by the bridge 115  public static final CallTransaction.Function GET_BTC_TX_HASH_PROCESSED_HEIGHT = BridgeMethods.GET_BTC_TX_HASH_PROCESSED_HEIGHT.getFunction(); 116  117  // Returns the federation bitcoin address 118  public static final CallTransaction.Function GET_FEDERATION_ADDRESS = BridgeMethods.GET_FEDERATION_ADDRESS.getFunction(); 119  // Returns the number of federates in the currently active federation 120  public static final CallTransaction.Function GET_FEDERATION_SIZE = BridgeMethods.GET_FEDERATION_SIZE.getFunction(); 121  // Returns the number of minimum required signatures from the currently active federation 122  public static final CallTransaction.Function GET_FEDERATION_THRESHOLD = BridgeMethods.GET_FEDERATION_THRESHOLD.getFunction(); 123  // Returns the public key of the federator at the specified index 124  public static final CallTransaction.Function GET_FEDERATOR_PUBLIC_KEY = BridgeMethods.GET_FEDERATOR_PUBLIC_KEY.getFunction(); 125  // Returns the public key of given type of the federator at the specified index 126  public static final CallTransaction.Function GET_FEDERATOR_PUBLIC_KEY_OF_TYPE = BridgeMethods.GET_FEDERATOR_PUBLIC_KEY_OF_TYPE.getFunction(); 127  // Returns the creation time of the federation 128  public static final CallTransaction.Function GET_FEDERATION_CREATION_TIME = BridgeMethods.GET_FEDERATION_CREATION_TIME.getFunction(); 129  // Returns the block number of the creation of the federation 130  public static final CallTransaction.Function GET_FEDERATION_CREATION_BLOCK_NUMBER = BridgeMethods.GET_FEDERATION_CREATION_BLOCK_NUMBER.getFunction(); 131  132  // Returns the retiring federation bitcoin address 133  public static final CallTransaction.Function GET_RETIRING_FEDERATION_ADDRESS = BridgeMethods.GET_RETIRING_FEDERATION_ADDRESS.getFunction(); 134  // Returns the number of federates in the retiring federation 135  public static final CallTransaction.Function GET_RETIRING_FEDERATION_SIZE = BridgeMethods.GET_RETIRING_FEDERATION_SIZE.getFunction(); 136  // Returns the number of minimum required signatures from the retiring federation 137  public static final CallTransaction.Function GET_RETIRING_FEDERATION_THRESHOLD = BridgeMethods.GET_RETIRING_FEDERATION_THRESHOLD.getFunction(); 138  // Returns the public key of the retiring federation's federator at the specified index 139  public static final CallTransaction.Function GET_RETIRING_FEDERATOR_PUBLIC_KEY = BridgeMethods.GET_RETIRING_FEDERATOR_PUBLIC_KEY.getFunction(); 140  // Returns the public key of given type of the retiring federation's federator at the specified index 141  public static final CallTransaction.Function GET_RETIRING_FEDERATOR_PUBLIC_KEY_OF_TYPE = BridgeMethods.GET_RETIRING_FEDERATOR_PUBLIC_KEY_OF_TYPE.getFunction(); 142  // Returns the creation time of the retiring federation 143  public static final CallTransaction.Function GET_RETIRING_FEDERATION_CREATION_TIME = BridgeMethods.GET_RETIRING_FEDERATION_CREATION_TIME.getFunction(); 144  // Returns the block number of the creation of the retiring federation 145  public static final CallTransaction.Function GET_RETIRING_FEDERATION_CREATION_BLOCK_NUMBER = BridgeMethods.GET_RETIRING_FEDERATION_CREATION_BLOCK_NUMBER.getFunction(); 146  147  // Creates a new pending federation and returns its id 148  public static final CallTransaction.Function CREATE_FEDERATION = BridgeMethods.CREATE_FEDERATION.getFunction(); 149  // Adds the given key to the current pending federation 150  public static final CallTransaction.Function ADD_FEDERATOR_PUBLIC_KEY = BridgeMethods.ADD_FEDERATOR_PUBLIC_KEY.getFunction(); 151  // Adds the given key to the current pending federation (multiple-key version) 152  public static final CallTransaction.Function ADD_FEDERATOR_PUBLIC_KEY_MULTIKEY = BridgeMethods.ADD_FEDERATOR_PUBLIC_KEY_MULTIKEY.getFunction(); 153  // Commits the currently pending federation 154  public static final CallTransaction.Function COMMIT_FEDERATION = BridgeMethods.COMMIT_FEDERATION.getFunction(); 155  // Rolls back the currently pending federation 156  public static final CallTransaction.Function ROLLBACK_FEDERATION = BridgeMethods.ROLLBACK_FEDERATION.getFunction(); 157  158  // Returns the current pending federation's hash 159  public static final CallTransaction.Function GET_PENDING_FEDERATION_HASH = BridgeMethods.GET_PENDING_FEDERATION_HASH.getFunction(); 160  // Returns the number of federates in the current pending federation 161  public static final CallTransaction.Function GET_PENDING_FEDERATION_SIZE = BridgeMethods.GET_PENDING_FEDERATION_SIZE.getFunction(); 162  // Returns the public key of the federator at the specified index for the current pending federation 163  public static final CallTransaction.Function GET_PENDING_FEDERATOR_PUBLIC_KEY = BridgeMethods.GET_PENDING_FEDERATOR_PUBLIC_KEY.getFunction(); 164  // Returns the public key of given type the federator at the specified index for the current pending federation 165  public static final CallTransaction.Function GET_PENDING_FEDERATOR_PUBLIC_KEY_OF_TYPE = BridgeMethods.GET_PENDING_FEDERATOR_PUBLIC_KEY_OF_TYPE.getFunction(); 166  167  // Returns the lock whitelist size 168  public static final CallTransaction.Function GET_LOCK_WHITELIST_SIZE = BridgeMethods.GET_LOCK_WHITELIST_SIZE.getFunction(); 169  // Returns the lock whitelist address stored at the specified index 170  public static final CallTransaction.Function GET_LOCK_WHITELIST_ADDRESS = BridgeMethods.GET_LOCK_WHITELIST_ADDRESS.getFunction(); 171  // Returns the lock whitelist entry stored at the specified address 172  public static final CallTransaction.Function GET_LOCK_WHITELIST_ENTRY_BY_ADDRESS = BridgeMethods.GET_LOCK_WHITELIST_ENTRY_BY_ADDRESS.getFunction(); 173  // Adds the given address to the lock whitelist 174  public static final CallTransaction.Function ADD_LOCK_WHITELIST_ADDRESS = BridgeMethods.ADD_LOCK_WHITELIST_ADDRESS.getFunction(); 175  // Adds the given address to the lock whitelist in "one-off" mode 176  public static final CallTransaction.Function ADD_ONE_OFF_LOCK_WHITELIST_ADDRESS = BridgeMethods.ADD_ONE_OFF_LOCK_WHITELIST_ADDRESS.getFunction(); 177  // Adds the given address to the lock whitelist in "unlimited" mode 178  public static final CallTransaction.Function ADD_UNLIMITED_LOCK_WHITELIST_ADDRESS = BridgeMethods.ADD_UNLIMITED_LOCK_WHITELIST_ADDRESS.getFunction(); 179  // Adds the given address to the lock whitelist 180  public static final CallTransaction.Function REMOVE_LOCK_WHITELIST_ADDRESS = BridgeMethods.REMOVE_LOCK_WHITELIST_ADDRESS.getFunction(); 181  182  public static final CallTransaction.Function SET_LOCK_WHITELIST_DISABLE_BLOCK_DELAY = BridgeMethods.SET_LOCK_WHITELIST_DISABLE_BLOCK_DELAY.getFunction(); 183  184  // Returns the current fee per kb 185  public static final CallTransaction.Function GET_FEE_PER_KB = BridgeMethods.GET_FEE_PER_KB.getFunction(); 186  // Adds the given key to the current pending federation 187  public static final CallTransaction.Function VOTE_FEE_PER_KB = BridgeMethods.VOTE_FEE_PER_KB.getFunction(); 188  189  // Increases the peg locking cap 190  public static final CallTransaction.Function INCREASE_LOCKING_CAP = BridgeMethods.INCREASE_LOCKING_CAP.getFunction(); 191  // Gets the peg locking cap 192  public static final CallTransaction.Function GET_LOCKING_CAP = BridgeMethods.GET_LOCKING_CAP.getFunction(); 193  public static final CallTransaction.Function REGISTER_BTC_COINBASE_TRANSACTION = BridgeMethods.REGISTER_BTC_COINBASE_TRANSACTION.getFunction(); 194  public static final CallTransaction.Function HAS_BTC_BLOCK_COINBASE_TRANSACTION_INFORMATION = BridgeMethods.HAS_BTC_BLOCK_COINBASE_TRANSACTION_INFORMATION.getFunction(); 195  public static final CallTransaction.Function REGISTER_FAST_BRIDGE_BTC_TRANSACTION = BridgeMethods.REGISTER_FAST_BRIDGE_BTC_TRANSACTION.getFunction(); 196  197  public static final int LOCK_WHITELIST_UNLIMITED_MODE_CODE = 0; 198  public static final int LOCK_WHITELIST_ENTRY_NOT_FOUND_CODE = -1; 199  public static final int LOCK_WHITELIST_INVALID_ADDRESS_FORMAT_ERROR_CODE = -2; 200  201  // Log topics used by Bridge Contract pre RSKIP146 202  public static final DataWord RELEASE_BTC_TOPIC = DataWord.fromString("release_btc_topic"); 203  public static final DataWord UPDATE_COLLECTIONS_TOPIC = DataWord.fromString("update_collections_topic"); 204  public static final DataWord ADD_SIGNATURE_TOPIC = DataWord.fromString("add_signature_topic"); 205  public static final DataWord COMMIT_FEDERATION_TOPIC = DataWord.fromString("commit_federation_topic"); 206  207  private static final Integer RECEIVE_HEADER_ERROR_SIZE_MISTMATCH = -20; 208  209  private final Constants constants; 210  private final BridgeConstants bridgeConstants; 211  private final ActivationConfig activationConfig; 212  213  private ActivationConfig.ForBlock activations; 214  private org.ethereum.core.Transaction rskTx; 215  216  private BridgeSupport bridgeSupport; 217  private BridgeSupportFactory bridgeSupportFactory; 218  219  public Bridge(RskAddress contractAddress, Constants constants, ActivationConfig activationConfig, 220  BridgeSupportFactory bridgeSupportFactory) { 221  this.bridgeSupportFactory = bridgeSupportFactory; 222  this.contractAddress = contractAddress; 223  this.constants = constants; 224  this.bridgeConstants = constants.getBridgeConstants(); 225  this.activationConfig = activationConfig; 226  } 227  228  @Override 229  public long getGasForData(byte[] data) { 230  if (!activations.isActive(ConsensusRule.RSKIP88) && BridgeUtils.isContractTx(rskTx)) { 231  logger.warn("Call from contract before Orchid"); 232  throw new NullPointerException(); 233  } 234  235  if (BridgeUtils.isFreeBridgeTx(rskTx, constants, activations)) { 236  return 0; 237  } 238  239  BridgeParsedData bridgeParsedData = parseData(data); 240  241  Long functionCost; 242  Long totalCost; 243  if (bridgeParsedData == null) { 244  functionCost = BridgeMethods.RELEASE_BTC.getCost(this, activations, new Object[0]); 245  totalCost = functionCost; 246  } else { 247  functionCost = bridgeParsedData.bridgeMethod.getCost(this, activations, bridgeParsedData.args); 248  int dataCost = data == null ? 0 : data.length * 2; 249  250  totalCost = functionCost + dataCost; 251  } 252  253  return totalCost; 254  } 255  256  @VisibleForTesting 257  BridgeParsedData parseData(byte[] data) { 258  BridgeParsedData bridgeParsedData = new BridgeParsedData(); 259  260  if (data != null && (data.length >= 1 && data.length <= 3)) { 261  logger.warn("Invalid function signature {}.", ByteUtil.toHexString(data)); 262  return null; 263  } 264  265  if (data == null || data.length == 0) { 266  bridgeParsedData.bridgeMethod = BridgeMethods.RELEASE_BTC; 267  bridgeParsedData.args = new Object[]{}; 268  } else { 269  byte[] functionSignature = Arrays.copyOfRange(data, 0, 4); 270  Optional<BridgeMethods> invokedMethod = BridgeMethods.findBySignature(functionSignature); 271  if (!invokedMethod.isPresent()) { 272  logger.warn("Invalid function signature {}.", ByteUtil.toHexString(functionSignature)); 273  return null; 274  } 275  bridgeParsedData.bridgeMethod = invokedMethod.get(); 276  try { 277  bridgeParsedData.args = bridgeParsedData.bridgeMethod.getFunction().decode(data); 278  } catch (Exception e) { 279  logger.warn("Invalid function arguments {} for function {}.", ByteUtil.toHexString(data), ByteUtil.toHexString(functionSignature)); 280  return null; 281  } 282  } 283  284  if (!bridgeParsedData.bridgeMethod.isEnabled(activations)) { 285  logger.warn("'{}' is not enabled to run", bridgeParsedData.bridgeMethod.name()); 286  return null; 287  } 288  289  return bridgeParsedData; 290  } 291  292  // Parsed rsk transaction data field 293  private static class BridgeParsedData { 294  public BridgeMethods bridgeMethod; 295  public Object[] args; 296  } 297  298  @Override 299  public void init(Transaction rskTx, Block rskExecutionBlock, Repository repository, BlockStore rskBlockStore, ReceiptStore rskReceiptStore, List<LogInfo> logs) { 300  this.activations = activationConfig.forBlock(rskExecutionBlock.getNumber()); 301  this.rskTx = rskTx; 302  303  this.bridgeSupport = bridgeSupportFactory.newInstance( 304  repository, 305  rskExecutionBlock, 306  contractAddress, 307  logs); 308  } 309  310  @Override 311  public List<ProgramSubtrace> getSubtraces() { 312  return this.bridgeSupport.getSubtraces(); 313  } 314  315  @Override 316  public byte[] execute(byte[] data) throws VMException { 317  try { 318  // Preliminary validation: the transaction on which we execute cannot be null 319  if (rskTx == null) { 320  throw new VMException("Rsk Transaction is null"); 321  } 322  323  BridgeParsedData bridgeParsedData = parseData(data); 324  325  // Function parsing from data returned null => invalid function selected, halt! 326  if (bridgeParsedData == null) { 327  String errorMessage = String.format("Invalid data given: %s.", ByteUtil.toHexString(data)); 328  logger.info(errorMessage); 329  if (activations.isActive(ConsensusRule.RSKIP88)) { 330  throw new BridgeIllegalArgumentException(errorMessage); 331  } 332  333  return null; 334  } 335  336  // If this is not a local call, then first check whether the function 337  // allows for non-local calls 338  if (activations.isActive(ConsensusRule.RSKIP88) && 339  !isLocalCall() && 340  bridgeParsedData.bridgeMethod.onlyAllowsLocalCalls(this, bridgeParsedData.args)) { 341  342  String errorMessage = String.format("Non-local-call to %s. Returning without execution.", bridgeParsedData.bridgeMethod.getFunction().name); 343  logger.info(errorMessage); 344  throw new BridgeIllegalArgumentException(errorMessage); 345  } 346  347  Optional<?> result; 348  try { 349  // bridgeParsedData.function should be one of the CallTransaction.Function declared above. 350  // If the user tries to call an non-existent function, parseData() will return null. 351  result = bridgeParsedData.bridgeMethod.getExecutor().execute(this, bridgeParsedData.args); 352  } catch (BridgeIllegalArgumentException ex) { 353  String errorMessage = String.format("Error executing: %s", bridgeParsedData.bridgeMethod); 354  logger.warn(errorMessage, ex); 355  if (activations.isActive(ConsensusRule.RSKIP88)) { 356  throw new BridgeIllegalArgumentException(errorMessage); 357  } 358  359  return null; 360  } 361  362  teardown(); 363  364  return result.map(bridgeParsedData.bridgeMethod.getFunction()::encodeOutputs).orElse(null); 365  } catch (Exception ex) { 366  logger.error(ex.getMessage(), ex); 367  panicProcessor.panic("bridgeexecute", ex.getMessage()); 368  throw new VMException(String.format("Exception executing bridge: %s", ex.getMessage()), ex); 369  } 370  } 371  372  private void teardown() throws IOException { 373  bridgeSupport.save(); 374  } 375  376  public void updateCollections(Object[] args) throws VMException { 377  logger.trace("updateCollections"); 378  379  try { 380  bridgeSupport.updateCollections(rskTx); 381  } catch (Exception e) { 382  logger.warn("Exception onBlock", e); 383  throw new VMException("Exception onBlock", e); 384  } 385  } 386  387  public boolean receiveHeadersIsPublic() { 388  return (activations.isActive(ConsensusRule.RSKIP124) 389  && (!activations.isActive(ConsensusRule.RSKIP200))); 390  } 391  392  public long receiveHeadersGetCost(Object[] args) { 393  // Old, private method fixed cost. Only applies before the corresponding RSKIP 394  if (!activations.isActive(ConsensusRule.RSKIP124)) { 395  return 22_000L; 396  } 397  398  final long BASE_COST = activations.isActive(ConsensusRule.RSKIP132) ? 25_000L : 66_000L; 399  if (args == null) { 400  return BASE_COST; 401  } 402  403  final int numberOfHeaders = ((Object[]) args[0]).length; 404  405  if (numberOfHeaders == 0) { 406  return BASE_COST; 407  } 408  // Dynamic cost based on the number of headers 409  // We add each additional header times 1650 to the base cost 410  final long COST_PER_ADDITIONAL_HEADER = activations.isActive(ConsensusRule.RSKIP132) ? 3_500 : 1_650; 411  return BASE_COST + (numberOfHeaders - 1) * COST_PER_ADDITIONAL_HEADER; 412  } 413  414  public void receiveHeaders(Object[] args) throws VMException { 415  logger.trace("receiveHeaders"); 416  417  Object[] btcBlockSerializedArray = (Object[]) args[0]; 418  419  // Before going and actually deserializing and calling the underlying function, 420  // check that all block headers passed in are actually block headers doing 421  // a simple size check. If this check fails, just fail. 422  if (Arrays.stream(btcBlockSerializedArray).anyMatch(bytes -> !BtcTransactionFormatUtils.isBlockHeaderSize(((byte[]) bytes).length, activations))) { 423  // This exception type bypasses bridge teardown, signalling no work done 424  // and preventing the overhead of saving bridge storage 425  logger.warn("Unexpected BTC header(s) received (size mismatch). Aborting processing."); 426  throw new BridgeIllegalArgumentException("Unexpected BTC header(s) received (size mismatch). Aborting processing."); 427  } 428  429  BtcBlock[] btcBlockArray = new BtcBlock[btcBlockSerializedArray.length]; 430  for (int i = 0; i < btcBlockSerializedArray.length; i++) { 431  byte[] btcBlockSerialized = (byte[]) btcBlockSerializedArray[i]; 432  try { 433  BtcBlock header = bridgeConstants.getBtcParams().getDefaultSerializer().makeBlock(btcBlockSerialized); 434  btcBlockArray[i] = header; 435  } catch (ProtocolException e) { 436  throw new BridgeIllegalArgumentException("Block " + i + " could not be parsed " + ByteUtil.toHexString(btcBlockSerialized), e); 437  } 438  } 439  try { 440  bridgeSupport.receiveHeaders(btcBlockArray); 441  } catch (Exception e) { 442  logger.warn("Exception adding header", e); 443  throw new VMException("Exception adding header", e); 444  } 445  } 446  447  public boolean registerBtcTransactionIsPublic() { 448  return activations.isActive(ConsensusRule.RSKIP199); 449  } 450  451  public int receiveHeader(Object[] args) throws VMException { 452  logger.trace("receiveHeader"); 453  454  byte[] headerArg = (byte[]) args[0]; 455  456  if (!BtcTransactionFormatUtils.isBlockHeaderSize(headerArg.length, activations)) { 457  logger.warn("Unexpected BTC header received (size mismatch). Aborting processing."); 458  return RECEIVE_HEADER_ERROR_SIZE_MISTMATCH; 459  } 460  461  BtcBlock header = bridgeConstants.getBtcParams().getDefaultSerializer().makeBlock(headerArg); 462  463  try { 464  return bridgeSupport.receiveHeader(header); 465  } catch (Exception e) { 466  String errorMessage = "Exception adding header in receiveHeader"; 467  logger.warn(errorMessage, e); 468  throw new VMException(errorMessage, e); 469  } 470  } 471  472  public void registerBtcTransaction(Object[] args) throws VMException { 473  logger.trace("registerBtcTransaction"); 474  475  byte[] btcTxSerialized = (byte[]) args[0]; 476  int height = ((BigInteger)args[1]).intValue(); 477  478  byte[] pmtSerialized = (byte[]) args[2]; 479  try { 480  bridgeSupport.registerBtcTransaction(rskTx, btcTxSerialized, height, pmtSerialized); 481  } catch (IOException | BlockStoreException e) { 482  logger.warn("Exception in registerBtcTransaction", e); 483  throw new VMException("Exception in registerBtcTransaction", e); 484  } 485  } 486  487  public void releaseBtc(Object[] args) throws VMException { 488  logger.trace("releaseBtc"); 489  490  try { 491  bridgeSupport.releaseBtc(rskTx); 492  } catch (Program.OutOfGasException e) { 493  throw e; 494  } catch (Exception e) { 495  logger.warn("Exception in releaseBtc", e); 496  throw new VMException("Exception in releaseBtc", e); 497  } 498  } 499  500  public void addSignature(Object[] args) throws VMException { 501  logger.trace("addSignature"); 502  503  byte[] federatorPublicKeySerialized = (byte[]) args[0]; 504  BtcECKey federatorPublicKey; 505  try { 506  federatorPublicKey = BtcECKey.fromPublicOnly(federatorPublicKeySerialized); 507  } catch (Exception e) { 508  throw new BridgeIllegalArgumentException("Public key could not be parsed " + ByteUtil.toHexString(federatorPublicKeySerialized), e); 509  } 510  Object[] signaturesObjectArray = (Object[]) args[1]; 511  if (signaturesObjectArray.length == 0) { 512  throw new BridgeIllegalArgumentException("Signatures array is empty"); 513  } 514  List<byte[]> signatures = new ArrayList<>(); 515  for (Object signatureObject : signaturesObjectArray) { 516  byte[] signatureByteArray = (byte[])signatureObject; 517  try { 518  BtcECKey.ECDSASignature.decodeFromDER((byte[])signatureObject); 519  } catch (Exception e) { 520  throw new BridgeIllegalArgumentException("Signature could not be parsed " + ByteUtil.toHexString(signatureByteArray), e); 521  } 522  signatures.add(signatureByteArray); 523  } 524  byte[] rskTxHash = (byte[]) args[2]; 525  if (rskTxHash.length!=32) { 526  throw new BridgeIllegalArgumentException("Invalid rsk tx hash " + ByteUtil.toHexString(rskTxHash)); 527  } 528  try { 529  bridgeSupport.addSignature(federatorPublicKey, signatures, rskTxHash); 530  } catch (BridgeIllegalArgumentException e) { 531  throw e; 532  } catch (Exception e) { 533  logger.warn("Exception in addSignature", e); 534  throw new VMException("Exception in addSignature", e); 535  } 536  } 537  538  public byte[] getStateForBtcReleaseClient(Object[] args) throws VMException { 539  logger.trace("getStateForBtcReleaseClient"); 540  541  try { 542  return bridgeSupport.getStateForBtcReleaseClient(); 543  } catch (Exception e) { 544  logger.warn("Exception in getStateForBtcReleaseClient", e); 545  throw new VMException("Exception in getStateForBtcReleaseClient", e); 546  } 547  } 548  549  public byte[] getStateForDebugging(Object[] args) throws VMException { 550  logger.trace("getStateForDebugging"); 551  552  try { 553  return bridgeSupport.getStateForDebugging(); 554  } catch (Exception e) { 555  logger.warn("Exception in getStateForDebugging", e); 556  throw new VMException("Exception in getStateForDebugging", e); 557  } 558  } 559  560  public Integer getBtcBlockchainBestChainHeight(Object[] args) throws VMException { 561  logger.trace("getBtcBlockchainBestChainHeight"); 562  563  try { 564  return bridgeSupport.getBtcBlockchainBestChainHeight(); 565  } catch (Exception e) { 566  logger.warn("Exception in getBtcBlockchainBestChainHeight", e); 567  throw new VMException("Exception in getBtcBlockchainBestChainHeight", e); 568  } 569  } 570  571  public boolean getBtcBlockchainBestChainHeightOnlyAllowsLocalCalls(Object[] args) { 572  return !activations.isActive(ConsensusRule.RSKIP220); 573  } 574  575  public Integer getBtcBlockchainInitialBlockHeight(Object[] args) throws VMException { 576  logger.trace("getBtcBlockchainInitialBlockHeight"); 577  578  try { 579  return bridgeSupport.getBtcBlockchainInitialBlockHeight(); 580  } catch (Exception e) { 581  logger.warn("Exception in getBtcBlockchainInitialBlockHeight", e); 582  throw new VMException("Exception in getBtcBlockchainInitialBlockHeight", e); 583  } 584  } 585  586  /** 587  * @deprecated 588  * @param args 589  * @return 590  */ 591  @Deprecated 592  public Object[] getBtcBlockchainBlockLocator(Object[] args) throws VMException { 593  logger.trace("getBtcBlockchainBlockLocator"); 594  595  try { 596  List<Sha256Hash> blockLocatorList = bridgeSupport.getBtcBlockchainBlockLocator(); 597  Object[] blockLocatorArray = new Object[blockLocatorList.size()]; 598  int i = 0; 599  for (Sha256Hash blockHash: blockLocatorList) { 600  blockLocatorArray[i] = blockHash.toString(); 601  i++; 602  } 603  return blockLocatorArray; 604  } catch (Exception e) { 605  logger.warn("Exception in getBtcBlockchainBlockLocator", e); 606  throw new VMException("Exception in getBtcBlockchainBlockLocator", e); 607  } 608  } 609  610  public byte[] getBtcBlockchainBlockHashAtDepth(Object[] args) throws VMException { 611  logger.trace("getBtcBlockchainBlockHashAtDepth"); 612  613  int depth = ((BigInteger) args[0]).intValue(); 614  Sha256Hash blockHash = null; 615  try { 616  blockHash = bridgeSupport.getBtcBlockchainBlockHashAtDepth(depth); 617  } catch (Exception e) { 618  logger.warn("Exception in getBtcBlockchainBlockHashAtDepth", e); 619  throw new VMException("Exception in getBtcBlockchainBlockHashAtDepth", e); 620  } 621  622  return blockHash.getBytes(); 623  } 624  625  public long getBtcTransactionConfirmationsGetCost(Object[] args) { 626  return bridgeSupport.getBtcTransactionConfirmationsGetCost(args); 627  } 628  629  public int getBtcTransactionConfirmations(Object[] args) throws VMException { 630  logger.trace("getBtcTransactionConfirmations"); 631  try { 632  Sha256Hash btcTxHash = Sha256Hash.wrap((byte[]) args[0]); 633  Sha256Hash btcBlockHash = Sha256Hash.wrap((byte[]) args[1]); 634  635  int merkleBranchPath = ((BigInteger) args[2]).intValue(); 636  637  Object[] merkleBranchHashesArray = (Object[]) args[3]; 638  List<Sha256Hash> merkleBranchHashes = Arrays.stream(merkleBranchHashesArray) 639  .map(hash -> Sha256Hash.wrap((byte[]) hash)).collect(Collectors.toList()); 640  641  MerkleBranch merkleBranch = new MerkleBranch(merkleBranchHashes, merkleBranchPath); 642  643  return bridgeSupport.getBtcTransactionConfirmations(btcTxHash, btcBlockHash, merkleBranch); 644  } catch (Exception e) { 645  logger.warn("Exception in getBtcTransactionConfirmations", e); 646  throw new VMException("Exception in getBtcTransactionConfirmations", e); 647  } 648  } 649  650  public Long getMinimumLockTxValue(Object[] args) { 651  logger.trace("getMinimumLockTxValue"); 652  return bridgeSupport.getMinimumPeginTxValue().getValue(); 653  } 654  655  public Boolean isBtcTxHashAlreadyProcessed(Object[] args) throws VMException { 656  logger.trace("isBtcTxHashAlreadyProcessed"); 657  658  try { 659  Sha256Hash btcTxHash = Sha256Hash.wrap((String) args[0]); 660  return bridgeSupport.isBtcTxHashAlreadyProcessed(btcTxHash); 661  } catch (Exception e) { 662  logger.warn("Exception in isBtcTxHashAlreadyProcessed", e); 663  throw new VMException("Exception in isBtcTxHashAlreadyProcessed", e); 664  } 665  } 666  667  public Long getBtcTxHashProcessedHeight(Object[] args) throws VMException { 668  logger.trace("getBtcTxHashProcessedHeight"); 669  670  try { 671  Sha256Hash btcTxHash = Sha256Hash.wrap((String) args[0]); 672  return bridgeSupport.getBtcTxHashProcessedHeight(btcTxHash); 673  } catch (Exception e) { 674  logger.warn("Exception in getBtcTxHashProcessedHeight", e); 675  throw new VMException("Exception in getBtcTxHashProcessedHeight", e); 676  } 677  } 678  679  public String getFederationAddress(Object[] args) { 680  logger.trace("getFederationAddress"); 681  682  return bridgeSupport.getFederationAddress().toBase58(); 683  } 684  685  public Integer getFederationSize(Object[] args) { 686  logger.trace("getFederationSize"); 687  688  return bridgeSupport.getFederationSize(); 689  } 690  691  public Integer getFederationThreshold(Object[] args) { 692  logger.trace("getFederationThreshold"); 693  694  return bridgeSupport.getFederationThreshold(); 695  } 696  697  public byte[] getFederatorPublicKey(Object[] args) { 698  logger.trace("getFederatorPublicKey"); 699  700  int index = ((BigInteger) args[0]).intValue(); 701  return bridgeSupport.getFederatorPublicKey(index); 702  } 703  704  public byte[] getFederatorPublicKeyOfType(Object[] args) throws VMException { 705  logger.trace("getFederatorPublicKeyOfType"); 706  707  int index = ((BigInteger) args[0]).intValue(); 708  709  FederationMember.KeyType keyType; 710  try { 711  keyType = FederationMember.KeyType.byValue((String) args[1]); 712  } catch (Exception e) { 713  logger.warn("Exception in getFederatorPublicKeyOfType", e); 714  throw new VMException("Exception in getFederatorPublicKeyOfType", e); 715  } 716  717  return bridgeSupport.getFederatorPublicKeyOfType(index, keyType); 718  } 719  720  public Long getFederationCreationTime(Object[] args) { 721  logger.trace("getFederationCreationTime"); 722  723  // Return the creation time in milliseconds from the epoch 724  return bridgeSupport.getFederationCreationTime().toEpochMilli(); 725  } 726  727  public long getFederationCreationBlockNumber(Object[] args) { 728  logger.trace("getFederationCreationBlockNumber"); 729  return bridgeSupport.getFederationCreationBlockNumber(); 730  } 731  732  public String getRetiringFederationAddress(Object[] args) { 733  logger.trace("getRetiringFederationAddress"); 734  735  Address address = bridgeSupport.getRetiringFederationAddress(); 736  737  if (address == null) { 738  // When there's no address, empty string is returned 739  return ""; 740  } 741  742  return address.toBase58(); 743  } 744  745  public Integer getRetiringFederationSize(Object[] args) { 746  logger.trace("getRetiringFederationSize"); 747  748  return bridgeSupport.getRetiringFederationSize(); 749  } 750  751  public Integer getRetiringFederationThreshold(Object[] args) { 752  logger.trace("getRetiringFederationThreshold"); 753  754  return bridgeSupport.getRetiringFederationThreshold(); 755  } 756  757  public byte[] getRetiringFederatorPublicKey(Object[] args) { 758  logger.trace("getRetiringFederatorPublicKey"); 759  760  int index = ((BigInteger) args[0]).intValue(); 761  byte[] publicKey = bridgeSupport.getRetiringFederatorPublicKey(index); 762  763  if (publicKey == null) { 764  // Empty array is returned when public key is not found or there's no retiring federation 765  return new byte[]{}; 766  } 767  768  return publicKey; 769  } 770  771  public byte[] getRetiringFederatorPublicKeyOfType(Object[] args) throws VMException { 772  logger.trace("getRetiringFederatorPublicKeyOfType"); 773  774  int index = ((BigInteger) args[0]).intValue(); 775  776  FederationMember.KeyType keyType; 777  try { 778  keyType = FederationMember.KeyType.byValue((String) args[1]); 779  } catch (Exception e) { 780  logger.warn("Exception in getRetiringFederatorPublicKeyOfType", e); 781  throw new VMException("Exception in getRetiringFederatorPublicKeyOfType", e); 782  } 783  784  byte[] publicKey = bridgeSupport.getRetiringFederatorPublicKeyOfType(index, keyType); 785  786  if (publicKey == null) { 787  // Empty array is returned when public key is not found or there's no retiring federation 788  return new byte[]{}; 789  } 790  791  return publicKey; 792  } 793  794  public Long getRetiringFederationCreationTime(Object[] args) { 795  logger.trace("getRetiringFederationCreationTime"); 796  797  Instant creationTime = bridgeSupport.getRetiringFederationCreationTime(); 798  799  if (creationTime == null) { 800  // -1 is returned when no retiring federation 801  return -1L; 802  } 803  804  // Return the creation time in milliseconds from the epoch 805  return creationTime.toEpochMilli(); 806  } 807  808  public long getRetiringFederationCreationBlockNumber(Object[] args) { 809  logger.trace("getRetiringFederationCreationBlockNumber"); 810  return bridgeSupport.getRetiringFederationCreationBlockNumber(); 811  } 812  813  public Integer createFederation(Object[] args) throws BridgeIllegalArgumentException { 814  logger.trace("createFederation"); 815  816  return bridgeSupport.voteFederationChange( 817  rskTx, 818  new ABICallSpec("create", new byte[][]{}) 819  ); 820  } 821  822  public Integer addFederatorPublicKey(Object[] args) throws BridgeIllegalArgumentException { 823  logger.trace("addFederatorPublicKey"); 824  825  byte[] publicKeyBytes; 826  try { 827  publicKeyBytes = (byte[]) args[0]; 828  } catch (Exception e) { 829  logger.warn("Exception in addFederatorPublicKey", e); 830  return -10; 831  } 832  833  return bridgeSupport.voteFederationChange( 834  rskTx, 835  new ABICallSpec("add", new byte[][]{ publicKeyBytes }) 836  ); 837  } 838  839  public Integer addFederatorPublicKeyMultikey(Object[] args) throws BridgeIllegalArgumentException { 840  logger.trace("addFederatorPublicKeyMultikey"); 841  842  byte[] btcPublicKeyBytes = (byte[]) args[0]; 843  byte[] rskPublicKeyBytes = (byte[]) args[1]; 844  byte[] mstPublicKeyBytes = (byte[]) args[2]; 845  846  return bridgeSupport.voteFederationChange( 847  rskTx, 848  new ABICallSpec("add-multi", new byte[][]{ btcPublicKeyBytes, rskPublicKeyBytes, mstPublicKeyBytes }) 849  ); 850  } 851  852  public Integer commitFederation(Object[] args) throws BridgeIllegalArgumentException { 853  logger.trace("commitFederation"); 854  855  byte[] hash; 856  try { 857  hash = (byte[]) args[0]; 858  } catch (Exception e) { 859  logger.warn("Exception in commitFederation", e); 860  return -10; 861  } 862  863  return bridgeSupport.voteFederationChange( 864  rskTx, 865  new ABICallSpec("commit", new byte[][]{ hash }) 866  ); 867  } 868  869  public Integer rollbackFederation(Object[] args) throws BridgeIllegalArgumentException { 870  logger.trace("rollbackFederation"); 871  872  return bridgeSupport.voteFederationChange( 873  rskTx, 874  new ABICallSpec("rollback", new byte[][]{}) 875  ); 876  } 877  878  public byte[] getPendingFederationHash(Object[] args) { 879  logger.trace("getPendingFederationHash"); 880  881  byte[] hash = bridgeSupport.getPendingFederationHash(); 882  883  if (hash == null) { 884  // Empty array is returned when pending federation is not present 885  return new byte[]{}; 886  } 887  888  return hash; 889  } 890  891  public Integer getPendingFederationSize(Object[] args) { 892  logger.trace("getPendingFederationSize"); 893  894  return bridgeSupport.getPendingFederationSize(); 895  } 896  897  public byte[] getPendingFederatorPublicKey(Object[] args) { 898  logger.trace("getPendingFederatorPublicKey"); 899  900  int index = ((BigInteger) args[0]).intValue(); 901  byte[] publicKey = bridgeSupport.getPendingFederatorPublicKey(index); 902  903  if (publicKey == null) { 904  // Empty array is returned when public key is not found 905  return new byte[]{}; 906  } 907  908  return publicKey; 909  } 910  911  public byte[] getPendingFederatorPublicKeyOfType(Object[] args) throws VMException { 912  logger.trace("getPendingFederatorPublicKeyOfType"); 913  914  int index = ((BigInteger) args[0]).intValue(); 915  916  FederationMember.KeyType keyType; 917  try { 918  keyType = FederationMember.KeyType.byValue((String) args[1]); 919  } catch (Exception e) { 920  logger.warn("Exception in getPendingFederatorPublicKeyOfType", e); 921  throw new VMException("Exception in getPendingFederatorPublicKeyOfType", e); 922  } 923  924  byte[] publicKey = bridgeSupport.getPendingFederatorPublicKeyOfType(index, keyType); 925  926  if (publicKey == null) { 927  // Empty array is returned when public key is not found 928  return new byte[]{}; 929  } 930  931  return publicKey; 932  } 933  934  public Integer getLockWhitelistSize(Object[] args) { 935  logger.trace("getLockWhitelistSize"); 936  937  return bridgeSupport.getLockWhitelistSize(); 938  } 939  940  public String getLockWhitelistAddress(Object[] args) { 941  logger.trace("getLockWhitelistAddress"); 942  943  int index = ((BigInteger) args[0]).intValue(); 944  LockWhitelistEntry entry = bridgeSupport.getLockWhitelistEntryByIndex(index); 945  946  if (entry == null) { 947  // Empty string is returned when address is not found 948  return ""; 949  } 950  951  return entry.address().toBase58(); 952  } 953  954  public long getLockWhitelistEntryByAddress(Object[] args) { 955  logger.trace("getLockWhitelistEntryByAddress"); 956  957  String addressBase58; 958  try { 959  addressBase58 = (String) args[0]; 960  } catch (Exception e) { 961  logger.warn("Exception in getLockWhitelistEntryByAddress", e); 962  return LOCK_WHITELIST_INVALID_ADDRESS_FORMAT_ERROR_CODE; 963  } 964  965  LockWhitelistEntry entry = bridgeSupport.getLockWhitelistEntryByAddress(addressBase58); 966  967  if (entry == null) { 968  // Empty string is returned when address is not found 969  return LOCK_WHITELIST_ENTRY_NOT_FOUND_CODE; 970  } 971  972  return entry.getClass() == OneOffWhiteListEntry.class ? 973  ((OneOffWhiteListEntry)entry).maxTransferValue().getValue() : 974  LOCK_WHITELIST_UNLIMITED_MODE_CODE; 975  } 976  977  public Integer addOneOffLockWhitelistAddress(Object[] args) { 978  logger.trace("addOneOffLockWhitelistAddress"); 979  980  String addressBase58; 981  BigInteger maxTransferValue; 982  try { 983  addressBase58 = (String) args[0]; 984  maxTransferValue = (BigInteger) args[1]; 985  } catch (Exception e) { 986  logger.warn("Exception in addOneOffLockWhitelistAddress", e); 987  return 0; 988  } 989  990  return bridgeSupport.addOneOffLockWhitelistAddress(rskTx, addressBase58, maxTransferValue); 991  } 992  993  public Integer addUnlimitedLockWhitelistAddress(Object[] args) { 994  logger.trace("addUnlimitedLockWhitelistAddress"); 995  996  String addressBase58; 997  try { 998  addressBase58 = (String) args[0]; 999  } catch (Exception e) { 1000  logger.warn("Exception in addUnlimitedLockWhitelistAddress", e); 1001  return 0; 1002  } 1003  1004  return bridgeSupport.addUnlimitedLockWhitelistAddress(rskTx, addressBase58); 1005  } 1006  1007  public Integer removeLockWhitelistAddress(Object[] args) { 1008  logger.trace("removeLockWhitelistAddress"); 1009  1010  String addressBase58; 1011  try { 1012  addressBase58 = (String) args[0]; 1013  } catch (Exception e) { 1014  logger.warn("Exception in removeLockWhitelistAddress", e); 1015  return 0; 1016  } 1017  1018  return bridgeSupport.removeLockWhitelistAddress(rskTx, addressBase58); 1019  } 1020  1021  public Integer setLockWhitelistDisableBlockDelay(Object[] args) throws IOException, BlockStoreException { 1022  logger.trace("setLockWhitelistDisableBlockDelay"); 1023  BigInteger lockWhitelistDisableBlockDelay = (BigInteger) args[0]; 1024  return bridgeSupport.setLockWhitelistDisableBlockDelay(rskTx, lockWhitelistDisableBlockDelay); 1025  } 1026  1027  public Integer voteFeePerKbChange(Object[] args) { 1028  logger.trace("voteFeePerKbChange"); 1029  1030  Coin feePerKb; 1031  try { 1032  feePerKb = Coin.valueOf(((BigInteger) args[0]).longValueExact()); 1033  } catch (Exception e) { 1034  logger.warn("Exception in voteFeePerKbChange", e); 1035  return -10; 1036  } 1037  1038  return bridgeSupport.voteFeePerKbChange(rskTx, feePerKb); 1039  } 1040  1041  public long getFeePerKb(Object[] args) { 1042  logger.trace("getFeePerKb"); 1043  1044  return bridgeSupport.getFeePerKb().getValue(); 1045  } 1046  1047  public long getLockingCap(Object[] args) { 1048  logger.trace("getLockingCap"); 1049  1050  Coin lockingCap = bridgeSupport.getLockingCap(); 1051  1052  return lockingCap.getValue(); 1053  } 1054  1055  public boolean increaseLockingCap(Object[] args) throws BridgeIllegalArgumentException { 1056  logger.trace("increaseLockingCap"); 1057  1058  Coin newLockingCap = BridgeUtils.getCoinFromBigInteger((BigInteger) args[0]); 1059  if (newLockingCap.getValue() <= 0) { 1060  throw new BridgeIllegalArgumentException("Locking cap must be bigger than zero"); 1061  } 1062  1063  return bridgeSupport.increaseLockingCap(rskTx, newLockingCap); 1064  } 1065  1066  public void registerBtcCoinbaseTransaction(Object[] args) throws VMException { 1067  logger.trace("registerBtcCoinbaseTransaction"); 1068  1069  byte[] btcTxSerialized = (byte[]) args[0]; 1070  Sha256Hash blockHash = Sha256Hash.wrap((byte[]) args[1]); 1071  byte[] pmtSerialized = (byte[]) args[2]; 1072  Sha256Hash witnessMerkleRoot = Sha256Hash.wrap((byte[]) args[3]); 1073  byte[] witnessReservedValue = (byte[]) args[4]; 1074  bridgeSupport.registerBtcCoinbaseTransaction(btcTxSerialized, blockHash, pmtSerialized, witnessMerkleRoot, witnessReservedValue); 1075  } 1076  1077  public boolean hasBtcBlockCoinbaseTransactionInformation(Object[] args) { 1078  logger.trace("hasBtcBlockCoinbaseTransactionInformation"); 1079  Sha256Hash blockHash = Sha256Hash.wrap((byte[]) args[0]); 1080  1081  return bridgeSupport.hasBtcBlockCoinbaseTransactionInformation(blockHash); 1082  } 1083  1084  public long getActiveFederationCreationBlockHeight(Object[] args) { 1085  logger.trace("getActiveFederationCreationBlockHeight"); 1086  1087  return bridgeSupport.getActiveFederationCreationBlockHeight(); 1088  } 1089  1090  public long registerFastBridgeBtcTransaction(Object[] args) { 1091  logger.trace("registerFastBridgeBtcTransaction"); 1092  1093  try { 1094  byte[] btcTxSerialized = (byte[]) args[0]; 1095  int height = ((BigInteger) args[1]).intValue(); 1096  byte[] pmtSerialized = (byte[]) args[2]; 1097  Keccak256 derivationArgumentsHash = new Keccak256((byte[]) args[3]); 1098  // Parse data to create BTC user refund address with version and hash 1099  byte[] refundAddressInfo = (byte[]) args[4]; 1100  Address userRefundAddress = new Address( 1101  bridgeConstants.getBtcParams(), 1102  BridgeUtils.extractAddressVersionFromBytes(refundAddressInfo), 1103  BridgeUtils.extractHash160FromBytes(refundAddressInfo) 1104  ); 1105  // A DataWord cast is used because a SolidityType "address" is decoded using this specific type. 1106  RskAddress lbcAddress = new RskAddress((DataWord) args[5]); 1107  // Parse data to create BTC liquidity provider address with version and hash 1108  byte[] lpAddressInfo = (byte[]) args[6]; 1109  Address lpBtcAddress = new Address( 1110  bridgeConstants.getBtcParams(), 1111  BridgeUtils.extractAddressVersionFromBytes(lpAddressInfo), 1112  BridgeUtils.extractHash160FromBytes(lpAddressInfo) 1113  ); 1114  boolean shouldTransferToContract = ((boolean) args[7]); 1115  1116  return bridgeSupport.registerFastBridgeBtcTransaction( 1117  rskTx, 1118  btcTxSerialized, 1119  height, 1120  pmtSerialized, 1121  derivationArgumentsHash, 1122  userRefundAddress, 1123  lbcAddress, 1124  lpBtcAddress, 1125  shouldTransferToContract 1126  ); 1127  } catch (Exception e) { 1128  logger.warn("Exception in registerFastBridgeBtcTransaction", e); 1129  return BridgeSupport.FAST_BRIDGE_GENERIC_ERROR; 1130  } 1131  } 1132  1133  public byte[] getBtcBlockchainBestBlockHeader(Object[] args) { 1134  logger.trace("getBtcBlockchainBestBlockHeader"); 1135  1136  try { 1137  return this.bridgeSupport.getBtcBlockchainBestBlockHeader(); 1138  } catch (Exception e) { 1139  logger.warn("Exception in getBtcBlockchainBestBlockHeader", e); 1140  return ByteUtil.EMPTY_BYTE_ARRAY; 1141  } 1142  } 1143  1144  public byte[] getBtcBlockchainBlockHeaderByHash(Object[] args) { 1145  logger.trace("getBtcBlockchainBlockHeaderByHash"); 1146  1147  try { 1148  byte[] hashBytes = (byte[])args[0]; 1149  Sha256Hash hash = Sha256Hash.wrap(hashBytes); 1150  1151  return this.bridgeSupport.getBtcBlockchainBlockHeaderByHash(hash); 1152  } catch (Exception e) { 1153  logger.warn("Exception in getBtcBlockchainBlockHeaderByHash", e); 1154  return ByteUtil.EMPTY_BYTE_ARRAY; 1155  } 1156  } 1157  1158  public byte[] getBtcBlockchainBlockHeaderByHeight(Object[] args) { 1159  logger.trace("getBtcBlockchainBlockHeaderByHeight"); 1160  1161  try { 1162  int height = ((BigInteger) args[0]).intValue(); 1163  1164  return this.bridgeSupport.getBtcBlockchainBlockHeaderByHeight(height); 1165  } catch (Exception e) { 1166  logger.warn("Exception in getBtcBlockchainBlockHeaderByHeight", e); 1167  return ByteUtil.EMPTY_BYTE_ARRAY; 1168  } 1169  } 1170  1171  public byte[] getBtcBlockchainParentBlockHeaderByHash(Object[] args) { 1172  logger.trace("getBtcBlockchainParentBlockHeaderByHash"); 1173  1174  try { 1175  byte[] hashBytes = (byte[])args[0]; 1176  Sha256Hash hash = Sha256Hash.wrap(hashBytes); 1177  1178  return this.bridgeSupport.getBtcBlockchainParentBlockHeaderByHash(hash); 1179  } catch (Exception e) { 1180  logger.warn("Exception in getBtcBlockchainParentBlockHeaderByHash", e); 1181  return ByteUtil.EMPTY_BYTE_ARRAY; 1182  } 1183  } 1184  1185  public static BridgeMethods.BridgeMethodExecutor activeAndRetiringFederationOnly(BridgeMethods.BridgeMethodExecutor decoratee, String funcName) { 1186  return (self, args) -> { 1187  Federation retiringFederation = self.bridgeSupport.getRetiringFederation(); 1188  1189  if (!BridgeUtils.isFromFederateMember(self.rskTx, self.bridgeSupport.getActiveFederation()) 1190  && ( retiringFederation == null || (retiringFederation != null && !BridgeUtils.isFromFederateMember(self.rskTx, retiringFederation)))) { 1191  String errorMessage = String.format("Sender is not part of the active or retiring federations, so he is not enabled to call the function '%s'",funcName); 1192  logger.warn(errorMessage); 1193  throw new VMException(errorMessage); 1194  } 1195  return decoratee.execute(self, args); 1196  }; 1197  } 1198  1199  public static BridgeMethods.BridgeMethodExecutor executeIfElse( 1200  BridgeMethods.BridgeCondition condition, 1201  BridgeMethods.BridgeMethodExecutor ifTrue, 1202  BridgeMethods.BridgeMethodExecutor ifFalse) { 1203  1204  return (self, args) -> { 1205  if (condition.isTrue(self)) { 1206  return ifTrue.execute(self, args); 1207  } else { 1208  return ifFalse.execute(self, args); 1209  } 1210  }; 1211  } 1212  1213  private boolean isLocalCall() { 1214  return rskTx.isLocalCallTransaction(); 1215  } 1216 }