diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeEvents.java b/rskj-core/src/main/java/co/rsk/peg/BridgeEvents.java index 4683068e18c..9202aebebfe 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeEvents.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeEvents.java @@ -5,110 +5,80 @@ public enum BridgeEvents { - LOCK_BTC("lock_btc", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.RECEIVER, SolidityType.getType(SolidityType.ADDRESS)), - new CallTransaction.Param(false, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, "senderBtcAddress", SolidityType.getType(SolidityType.STRING)), - new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.INT256)) - } - ), - PEGIN_BTC("pegin_btc", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.RECEIVER, SolidityType.getType(SolidityType.ADDRESS)), - new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.INT256)), - new CallTransaction.Param(false, "protocolVersion", SolidityType.getType(SolidityType.INT256)) - } - ), - REJECTED_PEGIN("rejected_pegin", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, Fields.REASON, SolidityType.getType(SolidityType.INT256)) - } - ), - UNREFUNDABLE_PEGIN("unrefundable_pegin", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, Fields.REASON, SolidityType.getType(SolidityType.INT256)) - } - ), - UPDATE_COLLECTIONS("update_collections", - new CallTransaction.Param[]{ - new CallTransaction.Param(false, Fields.SENDER, SolidityType.getType(SolidityType.ADDRESS)) - } - ), - ADD_SIGNATURE("add_signature", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.RELEASE_RSK_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(true, "federatorRskAddress", SolidityType.getType(SolidityType.ADDRESS)), - new CallTransaction.Param(false, "federatorBtcPublicKey", SolidityType.getType(SolidityType.BYTES)) - } - ), - RELEASE_BTC("release_btc", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.RELEASE_RSK_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, "btcRawTransaction", SolidityType.getType(SolidityType.BYTES)) - } - ), - COMMIT_FEDERATION("commit_federation", - new CallTransaction.Param[]{ - new CallTransaction.Param(false, "oldFederationBtcPublicKeys", SolidityType.getType(SolidityType.BYTES)), - new CallTransaction.Param(false, "oldFederationBtcAddress", SolidityType.getType(SolidityType.STRING)), - new CallTransaction.Param(false, "newFederationBtcPublicKeys", SolidityType.getType(SolidityType.BYTES)), - new CallTransaction.Param(false, "newFederationBtcAddress", SolidityType.getType(SolidityType.STRING)), - new CallTransaction.Param(false, "activationHeight", SolidityType.getType(SolidityType.INT256)) - } - ), - RELEASE_REQUESTED("release_requested", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, "rskTxHash", SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)) - } - ), - RELEASE_REQUEST_RECEIVED_LEGACY("release_request_received", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.SENDER, SolidityType.getType(SolidityType.ADDRESS)), - new CallTransaction.Param(false, "btcDestinationAddress", SolidityType.getType(SolidityType.BYTES)), - new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)) - } - ), - RELEASE_REQUEST_REJECTED("release_request_rejected", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.SENDER, SolidityType.getType(SolidityType.ADDRESS)), - new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)), - new CallTransaction.Param(false, Fields.REASON, SolidityType.getType(SolidityType.INT256)) - } - ), - BATCH_PEGOUT_CREATED("batch_pegout_created", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, Fields.RELEASE_RSK_TX_HASHES, SolidityType.getType(SolidityType.BYTES)) - } - ), - RELEASE_REQUEST_RECEIVED("release_request_received", - new CallTransaction.Param[]{ + LOCK_BTC("lock_btc", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.RECEIVER, SolidityType.getType(SolidityType.ADDRESS)), + new CallTransaction.Param(false, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, "senderBtcAddress", SolidityType.getType(SolidityType.STRING)), + new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.INT256)) + }), + PEGIN_BTC("pegin_btc", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.RECEIVER, SolidityType.getType(SolidityType.ADDRESS)), + new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.INT256)), + new CallTransaction.Param(false, "protocolVersion", SolidityType.getType(SolidityType.INT256)) + }), + REJECTED_PEGIN("rejected_pegin", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, Fields.REASON, SolidityType.getType(SolidityType.INT256)) + }), + UNREFUNDABLE_PEGIN("unrefundable_pegin", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, Fields.REASON, SolidityType.getType(SolidityType.INT256)) + }), + UPDATE_COLLECTIONS("update_collections", new CallTransaction.Param[] { + new CallTransaction.Param(false, Fields.SENDER, SolidityType.getType(SolidityType.ADDRESS)) + }), + ADD_SIGNATURE("add_signature", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.RELEASE_RSK_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(true, "federatorRskAddress", SolidityType.getType(SolidityType.ADDRESS)), + new CallTransaction.Param(false, "federatorBtcPublicKey", SolidityType.getType(SolidityType.BYTES)) + }), + RELEASE_BTC("release_btc", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.RELEASE_RSK_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, "btcRawTransaction", SolidityType.getType(SolidityType.BYTES)) + }), + COMMIT_FEDERATION("commit_federation", new CallTransaction.Param[] { + new CallTransaction.Param(false, "oldFederationBtcPublicKeys", SolidityType.getType(SolidityType.BYTES)), + new CallTransaction.Param(false, "oldFederationBtcAddress", SolidityType.getType(SolidityType.STRING)), + new CallTransaction.Param(false, "newFederationBtcPublicKeys", SolidityType.getType(SolidityType.BYTES)), + new CallTransaction.Param(false, "newFederationBtcAddress", SolidityType.getType(SolidityType.STRING)), + new CallTransaction.Param(false, "activationHeight", SolidityType.getType(SolidityType.INT256)) + }), + RELEASE_REQUESTED("release_requested", new CallTransaction.Param[] { + new CallTransaction.Param(true, "rskTxHash", SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)) + }), + RELEASE_REQUEST_RECEIVED_LEGACY("release_request_received", new CallTransaction.Param[] { new CallTransaction.Param(true, Fields.SENDER, SolidityType.getType(SolidityType.ADDRESS)), - new CallTransaction.Param(false, "btcDestinationAddress", SolidityType.getType(SolidityType.STRING)), - new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)) - } - ), - PEGOUT_CONFIRMED("pegout_confirmed", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, "pegoutCreationRskBlockNumber", SolidityType.getType(SolidityType.UINT256)) - } - ), - PEGOUT_TRANSACTION_CREATED("pegout_transaction_created", - new CallTransaction.Param[]{ - new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), - new CallTransaction.Param(false, Fields.UTXO_OUTPOINT_VALUES, SolidityType.getType(SolidityType.BYTES)) - } - ); + new CallTransaction.Param(false, Fields.BTC_DESTINATION_ADDRESS, SolidityType.getType(SolidityType.BYTES)), + new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)) + }), + RELEASE_REQUEST_REJECTED("release_request_rejected", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.SENDER, SolidityType.getType(SolidityType.ADDRESS)), + new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)), + new CallTransaction.Param(false, Fields.REASON, SolidityType.getType(SolidityType.INT256)) + }), + BATCH_PEGOUT_CREATED("batch_pegout_created", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, Fields.RELEASE_RSK_TX_HASHES, SolidityType.getType(SolidityType.BYTES)) + }), + RELEASE_REQUEST_RECEIVED("release_request_received", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.SENDER, SolidityType.getType(SolidityType.ADDRESS)), + new CallTransaction.Param(false, Fields.BTC_DESTINATION_ADDRESS, SolidityType.getType(SolidityType.STRING)), + new CallTransaction.Param(false, Fields.AMOUNT, SolidityType.getType(SolidityType.UINT256)) + }), + PEGOUT_CONFIRMED("pegout_confirmed", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, "pegoutCreationRskBlockNumber", SolidityType.getType(SolidityType.UINT256)) + }), + PEGOUT_TRANSACTION_CREATED("pegout_transaction_created", new CallTransaction.Param[] { + new CallTransaction.Param(true, Fields.BTC_TX_HASH, SolidityType.getType(SolidityType.BYTES32)), + new CallTransaction.Param(false, Fields.UTXO_OUTPOINT_VALUES, SolidityType.getType(SolidityType.BYTES)) + }); - private String eventName; - private CallTransaction.Param[] params; + private final String eventName; + private final CallTransaction.Param[] params; BridgeEvents(String eventName, CallTransaction.Param[] params) { this.eventName = eventName; @@ -128,5 +98,6 @@ private static class Fields { private static final String RELEASE_RSK_TX_HASH = "releaseRskTxHash"; private static final String RELEASE_RSK_TX_HASHES = "releaseRskTxHashes"; private static final String UTXO_OUTPOINT_VALUES = "utxoOutpointValues"; + private static final String BTC_DESTINATION_ADDRESS = "btcDestinationAddress"; } } diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java index 2bb9323ddf8..342d13cdd43 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -808,7 +808,6 @@ private void saveNewUTXOs(BtcTransaction btcTx) { */ public void releaseBtc(Transaction rskTx) throws IOException { final co.rsk.core.Coin pegoutValueInWeis = rskTx.getValue(); - final Coin pegoutValueInSatoshis = pegoutValueInWeis.toBitcoin(); final RskAddress senderAddress = rskTx.getSender(signatureCache); logger.debug( "[releaseBtc] Releasing {} weis from RSK address {} in tx {}", @@ -824,7 +823,7 @@ public void releaseBtc(Transaction rskTx) throws IOException { senderAddress ); if (activations.isActive(ConsensusRule.RSKIP185)) { - emitRejectEvent(pegoutValueInSatoshis, senderAddress, RejectedPegoutReason.CALLER_CONTRACT); + emitRejectEvent(pegoutValueInWeis, senderAddress, RejectedPegoutReason.CALLER_CONTRACT); return; } else { String message = "Contract calling releaseBTC"; @@ -837,26 +836,37 @@ public void releaseBtc(Transaction rskTx) throws IOException { Address btcDestinationAddress = BridgeUtils.recoverBtcAddressFromEthTransaction(rskTx, networkParameters); logger.debug("[releaseBtc] BTC destination address: {}", btcDestinationAddress); - requestRelease(btcDestinationAddress, pegoutValueInSatoshis, rskTx); + requestRelease(btcDestinationAddress, pegoutValueInWeis, rskTx); } - private void refundAndEmitRejectEvent(Coin value, RskAddress senderAddress, RejectedPegoutReason reason) { + private void refundAndEmitRejectEvent( + co.rsk.core.Coin releaseRequestedValueInWeis, + RskAddress senderAddress, + RejectedPegoutReason reason + ) { logger.trace( - "[refundAndEmitRejectEvent] Executing a refund of {} to {}. Reason: {}", - value, + "[refundAndEmitRejectEvent] Executing a refund of {} weis to {}. Reason: {}", + releaseRequestedValueInWeis, senderAddress, reason ); + + // Prior to RSKIP427, the value was converted to BTC before doing the refund + // This could cause the original value to be rounded down to fit in satoshis value + co.rsk.core.Coin refundValue = activations.isActive(RSKIP427) ? + releaseRequestedValueInWeis : + co.rsk.core.Coin.fromBitcoin(releaseRequestedValueInWeis.toBitcoin()); + rskRepository.transfer( PrecompiledContracts.BRIDGE_ADDR, senderAddress, - co.rsk.core.Coin.fromBitcoin(value) + refundValue ); - emitRejectEvent(value, senderAddress, reason); + emitRejectEvent(releaseRequestedValueInWeis, senderAddress, reason); } - private void emitRejectEvent(Coin value, RskAddress senderAddress, RejectedPegoutReason reason) { - eventLogger.logReleaseBtcRequestRejected(senderAddress.toHexString(), value, reason); + private void emitRejectEvent(co.rsk.core.Coin releaseRequestedValueInWeis, RskAddress senderAddress, RejectedPegoutReason reason) { + eventLogger.logReleaseBtcRequestRejected(senderAddress, releaseRequestedValueInWeis, reason); } /** @@ -865,10 +875,11 @@ private void emitRejectEvent(Coin value, RskAddress senderAddress, RejectedPegou * to be processed later. * * @param destinationAddress the destination BTC address. - * @param value the amount of BTC to release. - * @throws IOException if there's an error while processing the request. + * @param releaseRequestedValueInWeis the amount of RBTC requested to be released, represented in weis + * @throws IOException if there is an error getting the release request queue from storage */ - private void requestRelease(Address destinationAddress, Coin value, Transaction rskTx) throws IOException { + private void requestRelease(Address destinationAddress, co.rsk.core.Coin releaseRequestedValueInWeis, Transaction rskTx) throws IOException { + Coin valueToReleaseInSatoshis = releaseRequestedValueInWeis.toBitcoin(); Optional optionalRejectedPegoutReason = Optional.empty(); if (activations.isActive(RSKIP219)) { int pegoutSize = getRegularPegoutTxSize(activations, getActiveFederation()); @@ -886,11 +897,11 @@ private void requestRelease(Address destinationAddress, Coin value, Transaction .divide(100) ); // add the gap - // The pegout value should be greater or equals than the max of these two values + // The pegout releaseRequestedValueInWeis should be greater or equals than the max of these two values Coin minValue = Coin.valueOf(Math.max(bridgeConstants.getMinimumPegoutTxValue().value, requireFundsForFee.value)); // Since Iris the peg-out the rule is that the minimum is inclusive - if (value.isLessThan(minValue)) { + if (valueToReleaseInSatoshis.isLessThan(minValue)) { optionalRejectedPegoutReason = Optional.of( Objects.equals(minValue, requireFundsForFee) ? RejectedPegoutReason.FEE_ABOVE_VALUE: @@ -899,37 +910,47 @@ private void requestRelease(Address destinationAddress, Coin value, Transaction } } else { // For legacy peg-outs the rule stated that the minimum was exclusive - if (!value.isGreaterThan(bridgeConstants.getLegacyMinimumPegoutTxValue())) { + if (!valueToReleaseInSatoshis.isGreaterThan(bridgeConstants.getLegacyMinimumPegoutTxValue())) { optionalRejectedPegoutReason = Optional.of(RejectedPegoutReason.LOW_AMOUNT); } } if (optionalRejectedPegoutReason.isPresent()) { logger.warn( - "[requestRelease] releaseBtc ignored. To {}. Tx {}. Value {}. Reason: {}", + "[requestRelease] releaseBtc ignored. To {}. Tx {}. Value {} weis. Reason: {}", destinationAddress, rskTx, - value, + releaseRequestedValueInWeis, optionalRejectedPegoutReason.get() ); if (activations.isActive(ConsensusRule.RSKIP185)) { refundAndEmitRejectEvent( - value, + releaseRequestedValueInWeis, rskTx.getSender(signatureCache), optionalRejectedPegoutReason.get() ); } } else { if (activations.isActive(ConsensusRule.RSKIP146)) { - provider.getReleaseRequestQueue().add(destinationAddress, value, rskTx.getHash()); + provider.getReleaseRequestQueue().add(destinationAddress, valueToReleaseInSatoshis, rskTx.getHash()); } else { - provider.getReleaseRequestQueue().add(destinationAddress, value); + provider.getReleaseRequestQueue().add(destinationAddress, valueToReleaseInSatoshis); } + RskAddress sender = rskTx.getSender(signatureCache); if (activations.isActive(ConsensusRule.RSKIP185)) { - eventLogger.logReleaseBtcRequestReceived(rskTx.getSender(signatureCache).toHexString(), destinationAddress, value); + eventLogger.logReleaseBtcRequestReceived( + sender, + destinationAddress, + releaseRequestedValueInWeis + ); } - logger.info("[requestRelease] releaseBtc successful to {}. Tx {}. Value {}.", destinationAddress, rskTx, value); + logger.info( + "[requestRelease] releaseBtc successful to {}. Tx {}. Value {} weis.", + destinationAddress, + rskTx, + releaseRequestedValueInWeis + ); } } diff --git a/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLogger.java b/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLogger.java index 6184db4d756..25fd8f3b16e 100644 --- a/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLogger.java +++ b/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLogger.java @@ -63,11 +63,11 @@ default void logUnrefundablePegin(BtcTransaction btcTx, UnrefundablePeginReason throw new UnsupportedOperationException(); } - default void logReleaseBtcRequestReceived(String sender, Address btcDestinationAddress, Coin amount) { + default void logReleaseBtcRequestReceived(RskAddress sender, Address btcDestinationAddress, co.rsk.core.Coin amountInWeis) { throw new UnsupportedOperationException(); } - default void logReleaseBtcRequestRejected(String sender, Coin amount, RejectedPegoutReason reason) { + default void logReleaseBtcRequestRejected(RskAddress sender, co.rsk.core.Coin amountInWeis, RejectedPegoutReason reason) { throw new UnsupportedOperationException(); } diff --git a/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLoggerImpl.java b/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLoggerImpl.java index b5ead3941e8..6b7242b47f5 100644 --- a/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLoggerImpl.java +++ b/rskj-core/src/main/java/co/rsk/peg/utils/BridgeEventLoggerImpl.java @@ -18,30 +18,24 @@ package co.rsk.peg.utils; import co.rsk.bitcoinj.core.*; -import co.rsk.peg.constants.BridgeConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import co.rsk.peg.BridgeEvents; import co.rsk.peg.bitcoin.UtxoUtils; +import co.rsk.peg.constants.BridgeConstants; import co.rsk.peg.federation.Federation; import co.rsk.peg.federation.FederationMember; import co.rsk.peg.federation.constants.FederationConstants; import co.rsk.peg.pegin.RejectedPeginReason; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; -import org.ethereum.core.Block; -import org.ethereum.core.CallTransaction; -import org.ethereum.core.SignatureCache; -import org.ethereum.core.Transaction; +import org.ethereum.core.*; import org.ethereum.crypto.ECKey; import org.ethereum.util.ByteUtil; -import org.ethereum.vm.DataWord; -import org.ethereum.vm.LogInfo; -import org.ethereum.vm.PrecompiledContracts; - -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; +import org.ethereum.vm.*; /** * Responsible for logging events triggered by BridgeContract. @@ -57,7 +51,12 @@ public class BridgeEventLoggerImpl implements BridgeEventLogger { private final List logs; private final ActivationConfig.ForBlock activations; - public BridgeEventLoggerImpl(BridgeConstants bridgeConstants, ActivationConfig.ForBlock activations, List logs, SignatureCache signatureCache) { + public BridgeEventLoggerImpl( + BridgeConstants bridgeConstants, + ActivationConfig.ForBlock activations, + List logs, + SignatureCache signatureCache) { + this.activations = activations; this.bridgeConstants = bridgeConstants; this.signatureCache = signatureCache; @@ -193,37 +192,45 @@ public void logUnrefundablePegin(BtcTransaction btcTx, UnrefundablePeginReason r } @Override - public void logReleaseBtcRequestReceived(String sender, Address btcDestinationAddress, Coin amount) { + public void logReleaseBtcRequestReceived(RskAddress sender, Address btcDestinationAddress, co.rsk.core.Coin amountInWeis) { if (activations.isActive(ConsensusRule.RSKIP326)) { - logReleaseBtcRequestReceived(sender, btcDestinationAddress.toString(), amount); + logReleaseBtcRequestReceived(sender.toHexString(), btcDestinationAddress.toString(), amountInWeis); } else { - logReleaseBtcRequestReceived(sender, btcDestinationAddress.getHash160(), amount); + logReleaseBtcRequestReceived(sender.toHexString(), btcDestinationAddress.getHash160(), amountInWeis.toBitcoin()); } } - private void logReleaseBtcRequestReceived(String sender, byte[] btcDestinationAddress, Coin amount) { + private void logReleaseBtcRequestReceived(String sender, byte[] btcDestinationAddress, Coin amountInSatoshis) { CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); byte[][] encodedTopicsInBytes = event.encodeEventTopics(sender); List encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); - byte[] encodedData = event.encodeEventData(btcDestinationAddress, amount.getValue()); + + byte[] encodedData = event.encodeEventData(btcDestinationAddress, amountInSatoshis.getValue()); + this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); } - private void logReleaseBtcRequestReceived(String sender, String btcDestinationAddress, Coin amount) { + private void logReleaseBtcRequestReceived(String sender, String btcDestinationAddress, co.rsk.core.Coin amountInWeis) { CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); byte[][] encodedTopicsInBytes = event.encodeEventTopics(sender); List encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); - byte[] encodedData = event.encodeEventData(btcDestinationAddress, amount.getValue()); + + byte[] encodedData = activations.isActive(ConsensusRule.RSKIP427) ? + event.encodeEventData(btcDestinationAddress, amountInWeis.asBigInteger()) : + event.encodeEventData(btcDestinationAddress, amountInWeis.toBitcoin().getValue()); this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); } @Override - public void logReleaseBtcRequestRejected(String sender, Coin amount, RejectedPegoutReason reason) { + public void logReleaseBtcRequestRejected(RskAddress sender, co.rsk.core.Coin amountInWeis, RejectedPegoutReason reason) { CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); - byte[][] encodedTopicsInBytes = event.encodeEventTopics(sender); + byte[][] encodedTopicsInBytes = event.encodeEventTopics(sender.toHexString()); List encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); - byte[] encodedData = event.encodeEventData(amount.getValue(), reason.getValue()); + + byte[] encodedData = activations.isActive(ConsensusRule.RSKIP427) ? + event.encodeEventData(amountInWeis.asBigInteger(), reason.getValue()) : + event.encodeEventData(amountInWeis.toBitcoin().getValue(), reason.getValue()); this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); } diff --git a/rskj-core/src/main/java/co/rsk/peg/utils/BrigeEventLoggerLegacyImpl.java b/rskj-core/src/main/java/co/rsk/peg/utils/BrigeEventLoggerLegacyImpl.java index 7f3b04ab9db..7d367aba716 100644 --- a/rskj-core/src/main/java/co/rsk/peg/utils/BrigeEventLoggerLegacyImpl.java +++ b/rskj-core/src/main/java/co/rsk/peg/utils/BrigeEventLoggerLegacyImpl.java @@ -56,7 +56,12 @@ public class BrigeEventLoggerLegacyImpl implements BridgeEventLogger { private final SignatureCache signatureCache; private final List logs; - public BrigeEventLoggerLegacyImpl(BridgeConstants bridgeConstants, ActivationConfig.ForBlock activations, List logs, SignatureCache signatureCache) { + public BrigeEventLoggerLegacyImpl( + BridgeConstants bridgeConstants, + ActivationConfig.ForBlock activations, + List logs, + SignatureCache signatureCache + ) { this.bridgeConstants = bridgeConstants; this.activations = activations; this.signatureCache = signatureCache; diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java index dae0a171212..014229ac9f4 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java @@ -95,12 +95,13 @@ public enum ConsensusRule { RSKIP412("rskip412"), // From EIP-3198 BASEFEE opcode RSKIP415("rskip415"), RSKIP417("rskip417"), + RSKIP427("rskip427"), RSKIP428("rskip428"), RSKIP434("rskip434"), RSKIP438("rskip438") ; - private String configKey; + private final String configKey; ConsensusRule(String configKey) { this.configKey = configKey; diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 5ed4c5d4d1d..6dc5b16c5c5 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -96,6 +96,7 @@ blockchain = { rskip412 = rskip415 = rskip417 = + rskip427 = rskip428 = rskip434 = rskip438 = diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 9b108e40fc7..a7d71a2b4db 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -81,6 +81,7 @@ blockchain = { rskip412 = arrowhead600 rskip415 = arrowhead600 rskip417 = arrowhead600 + rskip427 = lovell700 rskip428 = lovell700 rskip434 = arrowhead631 rskip438 = lovell700 diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java index 6628e71992d..141a792e5d6 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java @@ -17,32 +17,38 @@ */ package co.rsk.peg; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import co.rsk.RskTestUtils; import co.rsk.bitcoinj.core.*; -import co.rsk.peg.constants.BridgeConstants; -import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import co.rsk.db.MutableTrieCache; import co.rsk.db.MutableTrieImpl; import co.rsk.peg.bitcoin.BitcoinTestUtils; +import co.rsk.peg.constants.BridgeConstants; +import co.rsk.peg.constants.BridgeMainNetConstants; import co.rsk.peg.federation.*; import co.rsk.peg.federation.constants.FederationConstants; import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.peg.feeperkb.FeePerKbSupportImpl; import co.rsk.peg.storage.BridgeStorageAccessorImpl; import co.rsk.peg.storage.StorageAccessor; -import co.rsk.peg.utils.BridgeEventLogger; -import co.rsk.peg.utils.BridgeEventLoggerImpl; -import co.rsk.peg.utils.RejectedPegoutReason; +import co.rsk.peg.utils.*; import co.rsk.test.builders.BridgeSupportBuilder; import co.rsk.test.builders.FederationSupportBuilder; import co.rsk.trie.Trie; +import java.io.IOException; +import java.math.BigInteger; +import java.util.*; +import java.util.stream.Collectors; import org.bouncycastle.util.encoders.Hex; import org.ethereum.TestUtils; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; -import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; import org.ethereum.crypto.ECKey; import org.ethereum.db.MutableRepository; @@ -51,47 +57,25 @@ import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.InternalTransaction; import org.ethereum.vm.program.Program; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.fail; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.io.IOException; -import java.math.BigInteger; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - class BridgeSupportReleaseBtcTest { - - private static final String TO_ADDRESS = "0000000000000000000000000000000000000006"; - private static final BigInteger DUST_AMOUNT = new BigInteger("1"); private static final BigInteger NONCE = new BigInteger("0"); private static final BigInteger GAS_PRICE = new BigInteger("100"); private static final BigInteger GAS_LIMIT = new BigInteger("1000"); private static final String DATA = "80af2871"; private static final ECKey SENDER = new ECKey(); + private static final RskAddress BRIDGE_ADDRESS = PrecompiledContracts.BRIDGE_ADDR; + private static final BridgeConstants BRIDGE_CONSTANTS = BridgeMainNetConstants.getInstance(); + private static final FederationConstants FEDERATION_CONSTANTS = BRIDGE_CONSTANTS.getFederationConstants(); + private static final NetworkParameters NETWORK_PARAMETERS = BRIDGE_CONSTANTS.getBtcParams(); + private static final ActivationConfig.ForBlock ACTIVATIONS_ALL = ActivationConfigsForTest.all().forBlock(0L); - private BridgeConstants bridgeConstants; - private FederationConstants federationConstants; - private NetworkParameters networkParameters; - private ActivationConfig.ForBlock activationsBeforeForks; - private final ActivationConfig.ForBlock activationMock = mock(ActivationConfig.ForBlock.class); private Federation activeFederation; private Repository repository; private BridgeEventLogger eventLogger; - private UTXO utxo; private BridgeStorageProvider provider; private FederationStorageProvider federationStorageProvider; private BridgeSupport bridgeSupport; @@ -103,28 +87,23 @@ class BridgeSupportReleaseBtcTest { @BeforeEach void setUpOnEachTest() { signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); - bridgeConstants = new BridgeRegTestConstants(); - federationConstants = bridgeConstants.getFederationConstants(); - networkParameters = bridgeConstants.getBtcParams(); - activationsBeforeForks = ActivationConfigsForTest.genesis().forBlock(0); - activeFederation = getFederation(); + activeFederation = P2shErpFederationBuilder.builder().build(); repository = spy(createRepository()); eventLogger = mock(BridgeEventLogger.class); - utxo = buildUTXO(); - provider = initProvider(repository, activationMock); - federationStorageProvider = initFederationStorageProvider(repository, activationMock); + provider = initProvider(); + federationStorageProvider = initFederationStorageProvider(); bridgeSupportBuilder = BridgeSupportBuilder.builder(); feePerKbSupport = mock(FeePerKbSupportImpl.class); - when(feePerKbSupport.getFeePerKb()).thenReturn(bridgeConstants.getFeePerKbConstants().getGenesisFeePerKb()); - bridgeSupport = spy(initBridgeSupport(eventLogger, activationMock)); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.valueOf(5_000L)); + bridgeSupport = spy(initBridgeSupport(eventLogger, ACTIVATIONS_ALL)); releaseTx = buildReleaseRskTx(); } @Test - void noLogEvents_before_rskip_146_185() throws IOException { - provider = initProvider(repository, activationsBeforeForks); - bridgeSupport = initBridgeSupport(eventLogger, activationsBeforeForks); + void noLogEvents_before_papyrus() throws IOException { + ActivationConfig.ForBlock wasabiActivation = ActivationConfigsForTest.wasabi100().forBlock(0L); + bridgeSupport = initBridgeSupport(eventLogger, wasabiActivation); bridgeSupport.releaseBtc(releaseTx); Transaction rskTx = buildUpdateTx(); @@ -137,9 +116,10 @@ void noLogEvents_before_rskip_146_185() throws IOException { } @Test - void eventLogger_logReleaseBtcRequested_after_rskip_146() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); + void eventLogger_logReleaseBtcRequested_after_papyrus_before_iris() throws IOException { + ActivationConfig.ForBlock papyrusActivations = ActivationConfigsForTest.papyrus200().forBlock(0L); + bridgeSupport = initBridgeSupport(eventLogger, papyrusActivations); bridgeSupport.releaseBtc(releaseTx); Transaction rskTx = buildUpdateTx(); @@ -152,10 +132,7 @@ void eventLogger_logReleaseBtcRequested_after_rskip_146() throws IOException { } @Test - void eventLogger_logReleaseBtcRequested_after_rskip_146_185() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - + void eventLogger_logReleaseBtcRequested_after_iris() throws IOException { bridgeSupport.releaseBtc(releaseTx); Transaction rskTx = buildUpdateTx(); @@ -164,52 +141,52 @@ void eventLogger_logReleaseBtcRequested_after_rskip_146_185() throws IOException verify(repository, never()).transfer(any(), any(), any()); verify(eventLogger, times(1)).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); verify(eventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); - verify(eventLogger, times(0)).logReleaseBtcRequestRejected(any(), any(), any()); + verify(eventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); } @Test - void eventLogger_logReleaseBtcRequested_after_rskip_146_185_326() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP326)).thenReturn(true); + void eventLogger_logReleaseBtcRequested_release_before_papyrus_and_updateCollections_after_papyrus() throws IOException { + ActivationConfig.ForBlock wasabiActivations = ActivationConfigsForTest.wasabi100().forBlock(0L); + ActivationConfig.ForBlock papyrusActivations = ActivationConfigsForTest.papyrus200().forBlock(0L); + bridgeSupport = initBridgeSupport(eventLogger, wasabiActivations); bridgeSupport.releaseBtc(releaseTx); + bridgeSupport = initBridgeSupport(eventLogger, papyrusActivations); Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); verify(repository, never()).transfer(any(), any(), any()); - verify(eventLogger, times(1)).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); - verify(eventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); - verify(eventLogger, times(0)).logReleaseBtcRequestRejected(any(), any(), any()); + verify(eventLogger, never()).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); } @Test - void eventLogger_logReleaseBtcRequested_release_before_activation_and_updateCollections_after_activation() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(false); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(false); + void release_before_papyrus_no_events_emitted() throws IOException { + ActivationConfig.ForBlock wasabiActivations = ActivationConfigsForTest.wasabi100().forBlock(0L); + bridgeSupport = initBridgeSupport(eventLogger, wasabiActivations); bridgeSupport.releaseBtc(releaseTx); - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - - bridgeSupport = initBridgeSupport(eventLogger, activationMock); - Transaction rskTx = buildUpdateTx(); + rskTx.sign(new ECKey().getPrivKeyBytes()); bridgeSupport.updateCollections(rskTx); verify(repository, never()).transfer(any(), any(), any()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + verify(eventLogger, never()).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); verify(eventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); } @Test - void handmade_release_before_rskip_146_185() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(false); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(false); + void release_after_papyrus_before_iris() throws IOException { + ActivationConfig.ForBlock papyrusActivations = ActivationConfigsForTest.papyrus200().forBlock(0L); + bridgeSupport = initBridgeSupport(eventLogger, papyrusActivations); bridgeSupport.releaseBtc(releaseTx); Transaction rskTx = buildUpdateTx(); @@ -219,48 +196,76 @@ void handmade_release_before_rskip_146_185() throws IOException { verify(repository, never()).transfer(any(), any(), any()); assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - - verify(eventLogger, never()).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); - verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); - verify(eventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequested( + any(byte[].class), + any(BtcTransaction.class), + any(Coin.class) + ); } @Test - void handmade_release_after_rskip_146() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(false); + void release_after_iris_before_fingerroot() throws IOException { + ActivationConfig.ForBlock hopActivations = ActivationConfigsForTest.hop400().forBlock(0L); List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + hopActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, hopActivations); - bridgeSupport.releaseBtc(releaseTx); + // Get a value between old and new minimum pegout values + Coin middle = BRIDGE_CONSTANTS.getLegacyMinimumPegoutTxValue().subtract(BRIDGE_CONSTANTS.getMinimumPegoutTxValue()).div(2); + Coin value = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().add(middle); + assertTrue(value.isLessThan(BRIDGE_CONSTANTS.getLegacyMinimumPegoutTxValue())); + assertTrue(value.isGreaterThan(BRIDGE_CONSTANTS.getMinimumPegoutTxValue())); + bridgeSupport.releaseBtc(buildReleaseRskTx(co.rsk.core.Coin.fromBitcoin(value))); + + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); Transaction rskTx = buildUpdateTx(); - rskTx.sign(new ECKey().getPrivKeyBytes()); + rskTx.sign(SENDER.getPrivKeyBytes()); bridgeSupport.updateCollections(rskTx); verify(repository, never()).transfer(any(), any(), any()); assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(4, logInfo.size()); verify(bridgeEventLogger, times(1)).logReleaseBtcRequested( any(byte[].class), any(BtcTransaction.class), any(Coin.class) ); + verify(bridgeEventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); + verify(bridgeEventLogger, times(1)).logUpdateCollections(any()); + verify(bridgeEventLogger, times(1)).logBatchPegoutCreated(any(), any()); + + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + + Object btcDestinationAddress = event.decodeEventData(firstLog.getData())[0]; + assertInstanceOf(byte[].class, btcDestinationAddress); } @Test - void handmade_release_after_rskip_146_185() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP326)).thenReturn(false); + void logReleaseBtcRequestReceived_after_fingerroot_before_lovell_shouldLogValueInSatoshis() throws IOException { + ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead600().forBlock(0L); List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + arrowheadActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, arrowheadActivations); - bridgeSupport.releaseBtc(releaseTx); + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(BRIDGE_CONSTANTS.getMinimumPegoutTxValue()); + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); @@ -271,7 +276,7 @@ void handmade_release_after_rskip_146_185() throws IOException { assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - assertEquals(3, logInfo.size()); + assertEquals(4, logInfo.size()); verify(bridgeEventLogger, times(1)).logReleaseBtcRequested( any(byte[].class), any(BtcTransaction.class), @@ -279,25 +284,30 @@ void handmade_release_after_rskip_146_185() throws IOException { ); verify(bridgeEventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); verify(bridgeEventLogger, times(1)).logUpdateCollections(any()); + verify(bridgeEventLogger, times(1)).logBatchPegoutCreated(any(), any()); - LogInfo logInfo1 = logInfo.get(0); - CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); - Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - assertInstanceOf(byte[].class, btcDestinationAddress); + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); + Object btcDestinationAddress = event.decodeEventData(firstLog.getData())[0]; + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[1]; + + assertInstanceOf(String.class, btcDestinationAddress); + assertEquals(pegoutRequestValue.toBitcoin().longValue(), amount.longValue()); } @Test - void handmade_release_after_rskip_146_185_326() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP326)).thenReturn(true); - + void release_after_lovell_logPegoutTransactionCreated_use_value_in_weis() throws IOException { List logInfo = new ArrayList<>(); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, ACTIVATIONS_ALL); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); - - bridgeSupport.releaseBtc(releaseTx); + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(BRIDGE_CONSTANTS.getMinimumPegoutTxValue()); + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); @@ -308,33 +318,40 @@ void handmade_release_after_rskip_146_185_326() throws IOException { assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - assertEquals(3, logInfo.size()); + assertEquals(5, logInfo.size()); verify(bridgeEventLogger, times(1)).logReleaseBtcRequested( any(byte[].class), any(BtcTransaction.class), any(Coin.class) ); - verify(bridgeEventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); verify(bridgeEventLogger, times(1)).logUpdateCollections(any()); + verify(bridgeEventLogger, times(1)).logBatchPegoutCreated(any(), any()); + verify(bridgeEventLogger, times(1)).logPegoutTransactionCreated(any(), any()); - LogInfo logInfo1 = logInfo.get(0); + LogInfo firstLog = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); - Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; + Object btcDestinationAddress = event.decodeEventData(firstLog.getData())[0]; + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[1]; + assertInstanceOf(String.class, btcDestinationAddress); + assertEquals(pegoutRequestValue.asBigInteger(), amount); } @Test - void handmade_release_after_rskip_146_rejected_lowAmount() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(false); - + void release_after_papyrus_before_iris_rejected_lowAmount() throws IOException { + ActivationConfig.ForBlock papyrusActivations = ActivationConfigsForTest.papyrus200().forBlock(0L); List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + papyrusActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, papyrusActivations); - releaseTx = buildReleaseRskTx(Coin.ZERO); + releaseTx = buildReleaseRskTx(co.rsk.core.Coin.ZERO); bridgeSupport.releaseBtc(releaseTx); Transaction rskTx = buildUpdateTx(); @@ -348,20 +365,21 @@ void handmade_release_after_rskip_146_rejected_lowAmount() throws IOException { verify(bridgeEventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); assertEquals(1, logInfo.size()); - verify(bridgeEventLogger, times(1)).logUpdateCollections(any()); } @Test - void handmade_release_after_rskip_146_185_rejected_lowAmount() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - + void release_after_iris_rejected_lowAmount() throws IOException { List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, ACTIVATIONS_ALL); - releaseTx = buildReleaseRskTx(Coin.ZERO); + releaseTx = buildReleaseRskTx(co.rsk.core.Coin.ZERO); bridgeSupport.releaseBtc(releaseTx); Transaction rskTx = buildUpdateTx(); @@ -369,7 +387,7 @@ void handmade_release_after_rskip_146_185_rejected_lowAmount() throws IOExceptio bridgeSupport.updateCollections(rskTx); verify(repository, times(1)).transfer( - argThat(a -> a.equals(PrecompiledContracts.BRIDGE_ADDR)), + argThat(a -> a.equals(BRIDGE_ADDRESS)), argThat(a -> a.equals(new RskAddress(SENDER.getAddress()))), argThat(a -> a.equals(co.rsk.core.Coin.fromBitcoin(Coin.ZERO))) ); @@ -383,21 +401,30 @@ void handmade_release_after_rskip_146_185_rejected_lowAmount() throws IOExceptio verify(bridgeEventLogger, times(1)).logUpdateCollections(any()); } - @Test - void handmade_release_after_rskip_146_185_rejected_contractCaller() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); + void release_after_papyrus_before_iris_rejected_contractCaller_throws_exception() { + ActivationConfig.ForBlock papyrusActivations = ActivationConfigsForTest.papyrus200().forBlock(0L); + bridgeSupport = initBridgeSupport(eventLogger, papyrusActivations); + releaseTx = buildReleaseRskTx_fromContract(co.rsk.core.Coin.fromBitcoin(Coin.COIN)); + assertThrows(Program.OutOfGasException.class, () -> bridgeSupport.releaseBtc(releaseTx)); + } + + @Test + void release_after_iris_rejected_contractCaller_emits_rejection_event() throws IOException { List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, ACTIVATIONS_ALL); - releaseTx = buildReleaseRskTx_fromContract(Coin.COIN); + releaseTx = buildReleaseRskTx_fromContract(co.rsk.core.Coin.fromBitcoin(Coin.COIN)); bridgeSupport.releaseBtc(releaseTx); - // Create Contract transaction Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); bridgeSupport.updateCollections(rskTx); @@ -416,74 +443,22 @@ void handmade_release_after_rskip_146_185_rejected_contractCaller() throws IOExc } @Test - void handmade_release_after_rskip_146_rejected_contractCaller() throws IOException { - - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(false); - - List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); - - releaseTx = buildReleaseRskTx_fromContract(Coin.COIN); - try { - bridgeSupport.releaseBtc(releaseTx); - fail(); - } catch (Program.OutOfGasException e) { - assertTrue(e.getMessage().contains("Contract calling releaseBTC")); - } - } - - @Test - void release_after_rskip_219() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); - + void release_after_fingerroot() throws IOException { List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); - - // Get a value between old and new minimum pegout values - Coin middle = bridgeConstants.getLegacyMinimumPegoutTxValue().subtract(bridgeConstants.getMinimumPegoutTxValue()).div(2); - Coin value = bridgeConstants.getMinimumPegoutTxValue().add(middle); - assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); - assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); - - Transaction rskTx = buildUpdateTx(); - rskTx.sign(SENDER.getPrivKeyBytes()); - - verify(repository, never()).transfer(any(), any(), any()); - - assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); - - assertEquals(1, logInfo.size()); - verify(bridgeEventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); - - LogInfo logInfo1 = logInfo.get(0); - CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); - Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - assertInstanceOf(byte[].class, btcDestinationAddress); - } - - @Test - void release_after_rskip_219_326() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP326)).thenReturn(true); - - List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, ACTIVATIONS_ALL); // Get a value between old and new minimum pegout values - Coin middle = bridgeConstants.getLegacyMinimumPegoutTxValue().subtract(bridgeConstants.getMinimumPegoutTxValue()).div(2); - Coin value = bridgeConstants.getMinimumPegoutTxValue().add(middle); - assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); - assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + Coin middle = BRIDGE_CONSTANTS.getLegacyMinimumPegoutTxValue().subtract(BRIDGE_CONSTANTS.getMinimumPegoutTxValue()).div(2); + Coin value = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().add(middle); + assertTrue(value.isLessThan(BRIDGE_CONSTANTS.getLegacyMinimumPegoutTxValue())); + assertTrue(value.isGreaterThan(BRIDGE_CONSTANTS.getMinimumPegoutTxValue())); + bridgeSupport.releaseBtc(buildReleaseRskTx(co.rsk.core.Coin.fromBitcoin(value))); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); @@ -495,76 +470,87 @@ void release_after_rskip_219_326() throws IOException { assertEquals(1, logInfo.size()); verify(bridgeEventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); - LogInfo logInfo1 = logInfo.get(0); + LogInfo firstLog = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); - Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + + Object btcDestinationAddress = event.decodeEventData(firstLog.getData())[0]; assertInstanceOf(String.class, btcDestinationAddress); } @Test - void release_before_rskip_219() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(false); + void release_before_iris() throws IOException { + ActivationConfig.ForBlock papyrusActivations = ActivationConfigsForTest.papyrus200().forBlock(0L); List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + papyrusActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, papyrusActivations); // Get a value between old and new minimum pegout values - Coin middle = bridgeConstants.getLegacyMinimumPegoutTxValue().subtract(bridgeConstants.getMinimumPegoutTxValue()).div(2); - Coin value = bridgeConstants.getMinimumPegoutTxValue().add(middle); - assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); - assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + Coin middle = BRIDGE_CONSTANTS.getLegacyMinimumPegoutTxValue().subtract(BRIDGE_CONSTANTS.getMinimumPegoutTxValue()).div(2); + Coin value = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().add(middle); + assertTrue(value.isLessThan(BRIDGE_CONSTANTS.getLegacyMinimumPegoutTxValue())); + assertTrue(value.isGreaterThan(BRIDGE_CONSTANTS.getMinimumPegoutTxValue())); + bridgeSupport.releaseBtc(buildReleaseRskTx(co.rsk.core.Coin.fromBitcoin(value))); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - assertEquals(1, logInfo.size()); + assertEquals(0, logInfo.size()); verify(bridgeEventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); - verify(bridgeEventLogger, times(1)).logReleaseBtcRequestRejected(any(), any(), any()); + verify(bridgeEventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); } @Test - void release_before_rskip_219_minimum_exclusive() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(false); + void release_before_iris_minimum_exclusive() throws IOException { + ActivationConfig.ForBlock papyrusActivations = ActivationConfigsForTest.papyrus200().forBlock(0L); List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + papyrusActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, papyrusActivations); // Get a value exactly to legacy minimum - Coin value = bridgeConstants.getLegacyMinimumPegoutTxValue(); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + Coin value = BRIDGE_CONSTANTS.getLegacyMinimumPegoutTxValue(); + bridgeSupport.releaseBtc(buildReleaseRskTx(co.rsk.core.Coin.fromBitcoin(value))); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - assertEquals(1, logInfo.size()); + assertEquals(0, logInfo.size()); verify(bridgeEventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); - verify(bridgeEventLogger, times(1)).logReleaseBtcRequestRejected(any(), any(), any()); + verify(bridgeEventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); } @Test - void release_after_rskip_219_minimum_inclusive() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); + void release_after_iris_before_fingerroot_minimum_inclusive() throws IOException { + ActivationConfig.ForBlock irisActivations = ActivationConfigsForTest.iris300().forBlock(0L); List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + irisActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, irisActivations); // Get a value exactly to current minimum - Coin value = bridgeConstants.getMinimumPegoutTxValue(); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + Coin value = BRIDGE_CONSTANTS.getMinimumPegoutTxValue(); + bridgeSupport.releaseBtc(buildReleaseRskTx(co.rsk.core.Coin.fromBitcoin(value))); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); @@ -576,26 +562,28 @@ void release_after_rskip_219_minimum_inclusive() throws IOException { assertEquals(1, logInfo.size()); verify(bridgeEventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); - LogInfo logInfo1 = logInfo.get(0); + LogInfo firstLog = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); - Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + + Object btcDestinationAddress = event.decodeEventData(firstLog.getData())[0]; assertInstanceOf(byte[].class, btcDestinationAddress); } @Test - void release_after_rskip_219_326_minimum_inclusive() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP326)).thenReturn(true); - + void release_after_fingerroot_minimum_inclusive() throws IOException { List logInfo = new ArrayList<>(); - BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(bridgeEventLogger, activationMock); + BridgeEventLoggerImpl bridgeEventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(bridgeEventLogger, ACTIVATIONS_ALL); // Get a value exactly to current minimum - Coin value = bridgeConstants.getMinimumPegoutTxValue(); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + Coin value = BRIDGE_CONSTANTS.getMinimumPegoutTxValue(); + bridgeSupport.releaseBtc(buildReleaseRskTx(co.rsk.core.Coin.fromBitcoin(value))); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); @@ -607,74 +595,80 @@ void release_after_rskip_219_326_minimum_inclusive() throws IOException { assertEquals(1, logInfo.size()); verify(bridgeEventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); - LogInfo logInfo1 = logInfo.get(0); + LogInfo firstLog = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); - Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - assertInstanceOf(String.class, btcDestinationAddress); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + Object btcDestinationAddress = event.decodeEventData(firstLog.getData())[0]; + assertInstanceOf(String.class, btcDestinationAddress); } @Test void release_verify_fee_below_fee_is_rejected() throws IOException { - Coin value = bridgeConstants.getMinimumPegoutTxValue().add(Coin.SATOSHI); - testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(Coin.COIN, value); + Coin value = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().add(Coin.SATOSHI); + testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(Coin.COIN, co.rsk.core.Coin.fromBitcoin(value)); } @Test - void release_verify_fee_above_fee_but_below_gap_is_rejected_before_rskip_271() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(false); + void release_verify_fee_above_fee_but_below_gap_is_rejected_before_hop() throws IOException { + ActivationConfig.ForBlock irisActivations = ActivationConfigsForTest.iris300().forBlock(0L); Coin feePerKB = Coin.COIN; - int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, federationStorageProvider.getNewFederation(federationConstants, activationMock)); + int pegoutSize = BridgeUtils.getRegularPegoutTxSize( + irisActivations, + federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, irisActivations) + ); Coin value = feePerKB.div(1000).times(pegoutSize); - testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(feePerKB, value); + testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(feePerKB, co.rsk.core.Coin.fromBitcoin(value)); } @Test - void release_verify_fee_above_fee_but_below_gap_is_rejected_after_rskip_271() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); + void release_verify_fee_above_fee_but_below_gap_is_rejected_after_hop() throws IOException { Coin feePerKB = Coin.COIN; - int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, federationStorageProvider.getNewFederation(federationConstants, activationMock)); + int pegoutSize = BridgeUtils.getRegularPegoutTxSize( + ACTIVATIONS_ALL, + federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, ACTIVATIONS_ALL) + ); Coin value = feePerKB.div(1000).times(pegoutSize); - testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(feePerKB, value); + testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(feePerKB, co.rsk.core.Coin.fromBitcoin(value)); } @Test void release_verify_fee_above_fee_but_below_minimum_is_rejected() throws IOException { + Coin valueBelowMinimum = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().minus(Coin.SATOSHI); testPegoutMinimumWithFeeVerificationRejectedByLowAmount( Coin.MILLICOIN, - bridgeConstants.getMinimumPegoutTxValue().minus(Coin.SATOSHI) + co.rsk.core.Coin.fromBitcoin(valueBelowMinimum) ); } @Test void release_verify_fee_above_fee_and_minimum_is_accepted() throws IOException { - testPegoutMinimumWithFeeVerificationPass(Coin.COIN, Coin.FIFTY_COINS); + testPegoutMinimumWithFeeVerificationPass(Coin.COIN, co.rsk.core.Coin.fromBitcoin(Coin.FIFTY_COINS)); } @Test - void test_processPegoutsIndividually_before_RSKIP271_activation() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(false); + void processPegoutsIndividually_before_hop() throws IOException { + ActivationConfig.ForBlock irisActivations = ActivationConfigsForTest.iris300().forBlock(0L); - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(3), genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(3), activeFederation.getAddress())); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, irisActivations)).thenReturn(utxos); BridgeStorageProvider bridgeStorageProvider = mock(BridgeStorageProvider.class); when(bridgeStorageProvider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.COIN)) )); when(bridgeStorageProvider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(bridgeStorageProvider) - .withActivations(activationMock) + .withActivations(irisActivations) .build(); Transaction rskTx = buildUpdateTx(); @@ -689,22 +683,18 @@ void test_processPegoutsIndividually_before_RSKIP271_activation() throws IOExcep } @Test - void test_processPegoutsInBatch_after_RSKIP271() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); + void processPegoutsInBatch_after_hop() throws IOException { List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(4), genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(4), activeFederation.getAddress())); ReleaseRequestQueue pegoutRequests = new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.MILLICOIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.MILLICOIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.MILLICOIN) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.MILLICOIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.MILLICOIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "three"), Coin.MILLICOIN) )); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(pegoutRequests); @@ -721,8 +711,8 @@ void test_processPegoutsInBatch_after_RSKIP271() throws IOException { .collect(Collectors.toList()); bridgeSupport = bridgeSupportBuilder - .withActivations(activationMock) - .withBridgeConstants(bridgeConstants) + .withActivations(ACTIVATIONS_ALL) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .withEventLogger(eventLogger) .build(); @@ -743,28 +733,25 @@ void test_processPegoutsInBatch_after_RSKIP271() throws IOException { } @Test - void test_processPegoutsInBatch_after_RSKIP271_activation_next_pegout_height_not_reached() throws IOException { - - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - + void processPegoutsInBatch_after_hop_next_pegout_height_not_reached() throws IOException { Block executionBlock = mock(Block.class); when(executionBlock.getNumber()).thenReturn(100L); long executionBlockNumber = executionBlock.getNumber(); provider = mock(BridgeStorageProvider.class); - when(provider.getNextPegoutHeight()).thenReturn(Optional.of(executionBlockNumber + bridgeConstants.getNumberOfBlocksBetweenPegouts() - 1)); + when(provider.getNextPegoutHeight()).thenReturn(Optional.of(executionBlockNumber + BRIDGE_CONSTANTS.getNumberOfBlocksBetweenPegouts() - 1)); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.MILLICOIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.MILLICOIN) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.MILLICOIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.MILLICOIN) ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .withExecutionBlock(executionBlock) - .withActivations(activationMock) + .withActivations(ACTIVATIONS_ALL) .build(); Transaction rskTx = buildUpdateTx(); @@ -778,9 +765,7 @@ void test_processPegoutsInBatch_after_RSKIP271_activation_next_pegout_height_not } @Test - void test_processPegoutsInBatch_after_RSKIP271_activation_no_requests_in_queue_updates_next_pegout_height() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - + void processPegoutsInBatch_hop_activation_no_requests_in_queue_updates_next_pegout_height() throws IOException { provider = mock(BridgeStorageProvider.class); when(provider.getNextPegoutHeight()).thenReturn(Optional.of(100L)); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); @@ -790,8 +775,8 @@ void test_processPegoutsInBatch_after_RSKIP271_activation_no_requests_in_queue_u when(executionBlock.getNumber()).thenReturn(100L); bridgeSupport = bridgeSupportBuilder - .withActivations(activationMock) - .withBridgeConstants(bridgeConstants) + .withActivations(ACTIVATIONS_ALL) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .withExecutionBlock(executionBlock) .build(); @@ -799,37 +784,34 @@ void test_processPegoutsInBatch_after_RSKIP271_activation_no_requests_in_queue_u Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - long nextPegoutHeight = executionBlock.getNumber() + bridgeConstants.getNumberOfBlocksBetweenPegouts(); + long nextPegoutHeight = executionBlock.getNumber() + BRIDGE_CONSTANTS.getNumberOfBlocksBetweenPegouts(); verify(provider, times(1)).getNextPegoutHeight(); verify(provider, times(1)).setNextPegoutHeight(nextPegoutHeight); } @Test - void test_processPegoutsInBatch_after_rskip_271_Insufficient_Money() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); + void processPegoutsInBatch_after_hop_Insufficient_Money() throws IOException { List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(2, 0, Coin.COIN.multiply(4), genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(2, 0, Coin.COIN.multiply(4), activeFederation.getAddress())); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "four"), Coin.COIN), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "five"), Coin.COIN) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "three"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "four"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "five"), Coin.COIN) ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withActivations(activationMock) - .withBridgeConstants(bridgeConstants) + .withActivations(ACTIVATIONS_ALL) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .build(); @@ -843,27 +825,25 @@ void test_processPegoutsInBatch_after_rskip_271_Insufficient_Money() throws IOEx } @Test - void test_processPegoutsInBatch_after_rskip_271_divide_transaction_when_max_size_exceeded() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); - List utxos = PegTestUtils.createUTXOs(610, genesisFederation.getAddress()); + void processPegoutsInBatch_after_hop_divide_transaction_when_max_size_exceeded() throws IOException { + List utxos = PegTestUtils.createUTXOs(310, activeFederation.getAddress()); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); + when(federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, ACTIVATIONS_ALL)).thenReturn(activeFederation); FederationSupport federationSupport = FederationSupportBuilder.builder() - .withFederationConstants(federationConstants) + .withFederationConstants(FEDERATION_CONSTANTS) .withFederationStorageProvider(federationStorageProvider) - .withActivations(activationMock) + .withActivations(ACTIVATIONS_ALL) .build(); provider = mock(BridgeStorageProvider.class); - when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(PegTestUtils.createReleaseRequestQueueEntries(600))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(PegTestUtils.createReleaseRequestQueueEntries(300))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withActivations(activationMock) - .withBridgeConstants(bridgeConstants) + .withActivations(ACTIVATIONS_ALL) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .withFederationSupport(federationSupport) .build(); @@ -871,37 +851,34 @@ void test_processPegoutsInBatch_after_rskip_271_divide_transaction_when_max_size Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - // First Half of the PegoutRequests 600 / 2 = 300 Is Batched For The First Time - assertEquals(300, provider.getReleaseRequestQueue().getEntries().size()); + // First Half of the PegoutRequests 300 / 2 = 150 Is Batched For The First Time + assertEquals(150, provider.getReleaseRequestQueue().getEntries().size()); assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - // The Rest PegoutRequests 600 / 2 = 300 Is Batched The 2nd Time updateCollections Is Called + // The Rest PegoutRequests 300 / 2 = 150 Is Batched The 2nd Time updateCollections Is Called assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); assertEquals(2, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test - void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_one_pegout() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); - List utxos = PegTestUtils.createUTXOs(700, genesisFederation.getAddress()); + void processPegoutsInBatch_after_hop_when_max_size_exceeded_for_one_pegout() throws IOException { + List utxos = PegTestUtils.createUTXOs(700, activeFederation.getAddress()); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.singletonList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(700)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN.multiply(700)) ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withActivations(activationMock) - .withBridgeConstants(bridgeConstants) + .withActivations(ACTIVATIONS_ALL) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .build(); @@ -913,25 +890,22 @@ void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_one_p } @Test - void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_two_pegout() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); - List utxos = PegTestUtils.createUTXOs(1400, genesisFederation.getAddress()); + void processPegoutsInBatch_after_hop_when_max_size_exceeded_for_two_pegout() throws IOException { + List utxos = PegTestUtils.createUTXOs(1400, activeFederation.getAddress()); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(700)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(700)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN.multiply(700)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.COIN.multiply(700)) ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withActivations(activationMock) - .withBridgeConstants(bridgeConstants) + .withActivations(ACTIVATIONS_ALL) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .build(); @@ -943,34 +917,33 @@ void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_two_p } @Test - void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_requests() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(false); + void processPegoutsIndividually_before_hop_no_funds_to_process_any_requests() throws IOException { + ActivationConfig.ForBlock irisActivations = ActivationConfigsForTest.iris300().forBlock(0L); - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN, genesisFederation.getAddress())); - utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN, genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN, activeFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN, activeFederation.getAddress())); List entries = Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(5)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(3)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN.multiply(5)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "three"), Coin.COIN.multiply(3)) ); ReleaseRequestQueue originalPegoutRequests = new ReleaseRequestQueue(entries); ReleaseRequestQueue pegoutRequests = new ReleaseRequestQueue(entries); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, irisActivations)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(pegoutRequests); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) - .withActivations(activationMock) + .withActivations(irisActivations) .build(); Transaction rskTx = buildUpdateTx(); @@ -981,20 +954,19 @@ void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_re } @Test - void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_requests_order_changes_in_queue() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(false); + void processPegoutsIndividually_before_hop_no_funds_to_process_any_requests_order_changes_in_queue() throws IOException { + ActivationConfig.ForBlock irisActivations = ActivationConfigsForTest.iris300().forBlock(0L); - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN, genesisFederation.getAddress())); - utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN, genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN, activeFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN, activeFederation.getAddress())); List entries = new ArrayList<>(); int entriesSizeAboveMaxIterations = BridgeSupport.MAX_RELEASE_ITERATIONS + 10; for (int i = 0; i < entriesSizeAboveMaxIterations; i++) { entries.add( new ReleaseRequestQueue.Entry( - BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), String.valueOf(i)), + BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), String.valueOf(i)), Coin.COIN.multiply(5) ) ); @@ -1009,16 +981,16 @@ void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_re ReleaseRequestQueue pegoutRequests = new ReleaseRequestQueue(entries); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, irisActivations)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(pegoutRequests); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) - .withActivations(activationMock) + .withActivations(irisActivations) .build(); Transaction rskTx = buildUpdateTx(); @@ -1030,28 +1002,27 @@ void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_re } @Test - void test_check_wallet_balance_before_rskip_271_process_at_least_one_request() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(false); + void check_wallet_balance_before_hop_process_at_least_one_request() throws IOException { + ActivationConfig.ForBlock irisActivations = ActivationConfigsForTest.iris300().forBlock(0L); - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(2), genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(2), activeFederation.getAddress())); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, irisActivations)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(3)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(2)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.COIN.multiply(3)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "three"), Coin.COIN.multiply(2)) ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) - .withActivations(activationMock) + .withActivations(irisActivations) .build(); Transaction rskTx = buildUpdateTx(); @@ -1063,30 +1034,27 @@ void test_check_wallet_balance_before_rskip_271_process_at_least_one_request() t } @Test - void test_check_wallet_balance_after_rskip_271_process_no_requests() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); + void check_wallet_balance_after_hop_process_no_requests() throws IOException { List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(4), genesisFederation.getAddress())); - utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN.multiply(4), genesisFederation.getAddress())); - utxos.add(PegTestUtils.createUTXO(3, 2, Coin.COIN.multiply(3), genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(4), activeFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN.multiply(4), activeFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(3, 2, Coin.COIN.multiply(3), activeFederation.getAddress())); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(5)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(3)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN.multiply(5)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "three"), Coin.COIN.multiply(3)) ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) - .withActivations(activationMock) + .withActivations(ACTIVATIONS_ALL) .withEventLogger(eventLogger) .build(); @@ -1101,30 +1069,28 @@ void test_check_wallet_balance_after_rskip_271_process_no_requests() throws IOEx } @Test - void test_check_wallet_balance_after_rskip_271_process_all_requests_when_utxos_available() throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP271)).thenReturn(true); - - Federation genesisFederation = FederationTestUtils.getGenesisFederation(federationConstants); + void check_wallet_balance_after_hop_process_all_requests_when_utxos_available() throws IOException { List utxos = new ArrayList<>(); - utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(4), genesisFederation.getAddress())); - utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN.multiply(4), genesisFederation.getAddress())); - utxos.add(PegTestUtils.createUTXO(3, 2, Coin.COIN.multiply(3), genesisFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(4), activeFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN.multiply(4), activeFederation.getAddress())); + utxos.add(PegTestUtils.createUTXO(3, 2, Coin.COIN.multiply(3), activeFederation.getAddress())); federationStorageProvider = mock(FederationStorageProvider.class); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); + when(federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, ACTIVATIONS_ALL)).thenReturn(activeFederation); provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(5)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(3)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "one"), Coin.COIN.multiply(5)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "two"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(BRIDGE_CONSTANTS.getBtcParams(), "three"), Coin.COIN.multiply(3)) ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) - .withActivations(activationMock) + .withActivations(ACTIVATIONS_ALL) .withEventLogger(eventLogger) .build(); @@ -1138,18 +1104,18 @@ void test_check_wallet_balance_after_rskip_271_process_all_requests_when_utxos_a verify(eventLogger, never()).logBatchPegoutCreated(any(), any()); verify(provider, never()).setNextPegoutHeight(any(Long.class)); - utxos.add(PegTestUtils.createUTXO(4, 3, Coin.COIN.multiply(1), genesisFederation.getAddress())); - when(federationStorageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock)).thenReturn(utxos); + utxos.add(PegTestUtils.createUTXO(4, 3, Coin.COIN.multiply(1), activeFederation.getAddress())); + when(federationStorageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL)).thenReturn(utxos); FederationSupport federationSupport = FederationSupportBuilder.builder() - .withFederationConstants(federationConstants) + .withFederationConstants(FEDERATION_CONSTANTS) .withFederationStorageProvider(federationStorageProvider) - .withActivations(activationMock) + .withActivations(ACTIVATIONS_ALL) .build(); bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) - .withActivations(activationMock) + .withActivations(ACTIVATIONS_ALL) .withEventLogger(eventLogger) .withFederationSupport(federationSupport) .build(); @@ -1165,25 +1131,30 @@ void test_check_wallet_balance_after_rskip_271_process_all_requests_when_utxos_a verify(provider, times(1)).setNextPegoutHeight(any(Long.class)); } - private void testPegoutMinimumWithFeeVerificationPass(Coin feePerKB, Coin value) - throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); - + private void testPegoutMinimumWithFeeVerificationPass(Coin feePerKB, co.rsk.core.Coin pegoutRequestedValue) throws IOException { List logInfo = new ArrayList<>(); - eventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(eventLogger, activationMock); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, ACTIVATIONS_ALL); when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKB); - int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, federationStorageProvider.getNewFederation(federationConstants, activationMock)); + int pegoutSize = BridgeUtils.getRegularPegoutTxSize( + ACTIVATIONS_ALL, + federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, ACTIVATIONS_ALL) + ); Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); - Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times(bridgeConstants.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); + Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times( + BRIDGE_CONSTANTS.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); - assertFalse(value.isLessThan(minValueWithGapAboveFee) || - value.isLessThan(bridgeConstants.getMinimumPegoutTxValue())); + Coin valueToRelease = pegoutRequestedValue.toBitcoin(); + assertFalse(valueToRelease.isLessThan(minValueWithGapAboveFee) || + valueToRelease.isLessThan(BRIDGE_CONSTANTS.getMinimumPegoutTxValue())); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestedValue)); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); @@ -1197,88 +1168,415 @@ private void testPegoutMinimumWithFeeVerificationPass(Coin feePerKB, Coin value) verify(eventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); } - private void testPegoutMinimumWithFeeVerificationRejectedByLowAmount(Coin feePerKB, Coin value) - throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); - - RskAddress bridgeAddress = PrecompiledContracts.BRIDGE_ADDR; - + private void testPegoutMinimumWithFeeVerificationRejectedByLowAmount( + Coin feePerKB, + co.rsk.core.Coin pegoutRequestValue + ) throws IOException { List logInfo = new ArrayList<>(); - eventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(eventLogger, activationMock); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, ACTIVATIONS_ALL); when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKB); - int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, federationStorageProvider.getNewFederation(federationConstants, activationMock)); + int pegoutSize = BridgeUtils.getRegularPegoutTxSize( + ACTIVATIONS_ALL, + federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, ACTIVATIONS_ALL) + ); Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); - Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times(bridgeConstants.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); + Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times( + BRIDGE_CONSTANTS.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); - assertTrue(value.isGreaterThan(minValueWithGapAboveFee)); + Coin valueToRelease = pegoutRequestValue.toBitcoin(); + assertTrue(valueToRelease.isGreaterThan(minValueWithGapAboveFee)); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); RskAddress senderAddress = new RskAddress(SENDER.getAddress()); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); - co.rsk.core.Coin coin = co.rsk.core.Coin.fromBitcoin(value); + verify(repository, times(1)).transfer(BRIDGE_ADDRESS, senderAddress, pegoutRequestValue); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, logInfo.size()); + + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress, + pegoutRequestValue, + RejectedPegoutReason.LOW_AMOUNT + ); + } + + private void testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue( + Coin feePerKB, + co.rsk.core.Coin pegoutRequestValue + ) throws IOException { + List logInfo = new ArrayList<>(); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, ACTIVATIONS_ALL); + when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKB); + + int pegoutSize = BridgeUtils.getRegularPegoutTxSize( + ACTIVATIONS_ALL, + federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, ACTIVATIONS_ALL) + ); + Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); + Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times( + BRIDGE_CONSTANTS.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); + + Coin valueToRelease = pegoutRequestValue.toBitcoin(); + assertTrue(valueToRelease.isLessThan(minValueWithGapAboveFee)); + + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); + + Transaction rskTx = buildUpdateTx(); + rskTx.sign(SENDER.getPrivKeyBytes()); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); - verify(repository, times(1)).transfer(bridgeAddress, senderAddress, coin); + verify(repository, times(1)).transfer( + BRIDGE_ADDRESS, + senderAddress, + pegoutRequestValue + ); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, logInfo.size()); + + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress, + pegoutRequestValue, + RejectedPegoutReason.FEE_ABOVE_VALUE + ); + } + + @Test + @DisplayName("A rejected pegout due to low amount. Pre lovell, the value is rounded down to the nearest satoshi. Both in the emitted event and the value refunded.") + void low_amount_release_request_rejected_before_lovell() throws IOException { + ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0L); + + List logInfo = new ArrayList<>(); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + arrowheadActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, arrowheadActivations); + + Coin belowPegoutMinimumValue = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().minus(Coin.SATOSHI); + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(belowPegoutMinimumValue); + // Add some extra weis to the value, but less than 1 satoshi. + // To ensure that the pegout value is rounded down to fit in satoshis. + co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.fromBitcoin(Coin.SATOSHI); + co.rsk.core.Coin oneWei = co.rsk.core.Coin.valueOf(Denomination.WEI.longValue()); + co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(oneWei); + pegoutRequestValue = pegoutRequestValue.add(extraWeis); + + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); + + // Pre lovell, the refund should be rounded down to the nearest satoshi. + co.rsk.core.Coin expectedRefundValue = pegoutRequestValue.subtract(extraWeis); + verify(repository, times(1)).transfer( + BRIDGE_ADDRESS, + senderAddress, + expectedRefundValue + ); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); assertEquals(1, logInfo.size()); + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress, + pegoutRequestValue, + RejectedPegoutReason.LOW_AMOUNT + ); + + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + // Same case in the log, the value should be rounded down to the nearest satoshi. + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0]; + long expectedAmountLogged = expectedRefundValue.toBitcoin().longValue(); + assertEquals(expectedAmountLogged, amount.longValue()); + } + + @Test + @DisplayName("A rejected pegout due to low amount. Post lovell, the pegout value is preserved in weis. Both in the emitted event and the value refunded.") + void low_amount_release_request_rejected_after_lovell() throws IOException { + List logInfo = new ArrayList<>(); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, ACTIVATIONS_ALL); + + Coin belowPegoutMinimumValue = BRIDGE_CONSTANTS.getMinimumPegoutTxValue().minus(Coin.SATOSHI); + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(belowPegoutMinimumValue); + + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); + + verify(repository, times(1)).transfer( + BRIDGE_ADDRESS, + senderAddress, + pegoutRequestValue + ); + + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(1, logInfo.size()); verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress, + pegoutRequestValue, + RejectedPegoutReason.LOW_AMOUNT + ); - verify(eventLogger, times(1)) - .logReleaseBtcRequestRejected(senderAddress.toHexString(), value, RejectedPegoutReason.LOW_AMOUNT); + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0]; + assertEquals(pegoutRequestValue.asBigInteger(), amount); } - private void testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(Coin feePerKB, Coin value) - throws IOException { - when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); - when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); + @Test + @DisplayName("A pegout from a contract is rejected. Pre lovell, the pegout value is rounded down to the nearest satoshi. Both in the emitted event and the value refunded.") + void contract_caller_release_request_rejected_before_lovell() throws IOException { + ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0L); - RskAddress bridgeAddress = PrecompiledContracts.BRIDGE_ADDR; + List logInfo = new ArrayList<>(); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + arrowheadActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, arrowheadActivations); + + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(BRIDGE_CONSTANTS.getMinimumPegoutTxValue()); + // Add some extra weis to the value, but less than 1 satoshi. + // To ensure that the pegout value is rounded down to fit in satoshis. + co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.fromBitcoin(Coin.SATOSHI); + co.rsk.core.Coin oneWei = co.rsk.core.Coin.valueOf(Denomination.WEI.longValue()); + co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(oneWei); + pegoutRequestValue = pegoutRequestValue.add(extraWeis); + + bridgeSupport.releaseBtc(buildReleaseRskTx_fromContract(pegoutRequestValue)); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); + + // No refund is made to a contract + verify(repository, never()).transfer(any(), any(), any()); + + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(1, logInfo.size()); + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress, + pegoutRequestValue, + RejectedPegoutReason.CALLER_CONTRACT + ); + + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0]; + // Pre lovell, the logged value should be rounded down to the nearest satoshi. + co.rsk.core.Coin expectedLoggedValue = pegoutRequestValue.subtract(extraWeis); + long expectedAmountLogged = expectedLoggedValue.toBitcoin().longValue(); + assertEquals(expectedAmountLogged, amount.longValue()); + } + @Test + @DisplayName("A pegout from a contract is rejected. Post lovell, the pegout value is preserved in weis. Both in the emitted event and the value refunded.") + void contract_caller_release_request_rejected_after_lovell() throws IOException { List logInfo = new ArrayList<>(); - eventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); - bridgeSupport = initBridgeSupport(eventLogger, activationMock); - when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKB); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, ACTIVATIONS_ALL); + + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(BRIDGE_CONSTANTS.getMinimumPegoutTxValue()); + // Add some extra weis to the value, but less than 1 satoshi. + // To ensure that the pegout value is rounded down to fit in satoshis. + co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.fromBitcoin(Coin.SATOSHI); + co.rsk.core.Coin oneWei = co.rsk.core.Coin.valueOf(Denomination.WEI.longValue()); + co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(oneWei); + pegoutRequestValue = pegoutRequestValue.add(extraWeis); + + bridgeSupport.releaseBtc(buildReleaseRskTx_fromContract(pegoutRequestValue)); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); + + // No refund is made to a contract + verify(repository, never()).transfer(any(), any(), any()); + + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(1, logInfo.size()); + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress, + pegoutRequestValue, + RejectedPegoutReason.CALLER_CONTRACT + ); + + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0]; + assertEquals(pegoutRequestValue.asBigInteger(), amount); + } - int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, federationStorageProvider.getNewFederation(federationConstants, activationMock)); + @Test + @DisplayName("A pegout rejected due to high fees. Pre lovell, the pegout value is rounded down to the nearest satoshi. Both in the emitted event and the value refunded.") + void fee_above_value_release_request_rejected_before_lovell() throws IOException { + ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0L); + + List logInfo = new ArrayList<>(); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + arrowheadActivations, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, arrowheadActivations); + // Set a high fee per kb to ensure the resulting pegout is above the min pegout value + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.COIN); + + int pegoutSize = BridgeUtils.getRegularPegoutTxSize( + ACTIVATIONS_ALL, + federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, arrowheadActivations) + ); Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); - Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times(bridgeConstants.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); + Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times( + BRIDGE_CONSTANTS.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100) + ); - assertTrue(value.isLessThan(minValueWithGapAboveFee)); + Coin pegoutRequestValueWithGapAboveFee = minValueWithGapAboveFee.minus(Coin.SATOSHI); + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(pegoutRequestValueWithGapAboveFee); + // Add some extra weis to the value, but less than 1 satoshi. + // To ensure that the pegout value is rounded down to fit in satoshis. + co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.fromBitcoin(Coin.SATOSHI); + co.rsk.core.Coin oneWei = co.rsk.core.Coin.valueOf(Denomination.WEI.longValue()); + co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(oneWei); + pegoutRequestValue = pegoutRequestValue.add(extraWeis); - bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); RskAddress senderAddress = new RskAddress(SENDER.getAddress()); - Transaction rskTx = buildUpdateTx(); - rskTx.sign(SENDER.getPrivKeyBytes()); + // Pre lovell, the refund should be rounded down to the nearest satoshi. + co.rsk.core.Coin expectedRefundValue = pegoutRequestValue.subtract(extraWeis); + verify(repository, times(1)).transfer( + BRIDGE_ADDRESS, + senderAddress, + expectedRefundValue + ); - co.rsk.core.Coin coin = co.rsk.core.Coin.fromBitcoin(value); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(1, logInfo.size()); + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress, + pegoutRequestValue, + RejectedPegoutReason.FEE_ABOVE_VALUE + ); - verify(repository, times(1)).transfer(bridgeAddress, senderAddress, coin); + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + + // Same case in the log, the value should be rounded down to the nearest satoshi. + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0]; + long expectedAmountLogged = expectedRefundValue.toBitcoin().longValue(); + assertEquals(expectedAmountLogged, amount.longValue()); + } + + @Test + @DisplayName("A pegout rejected due to high fees. Post lovell, the pegout value is preserved in weis. Both in the emitted event and the value refunded.") + void fee_above_value_release_request_rejected_after_lovell() throws IOException { + List logInfo = new ArrayList<>(); + eventLogger = spy(new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + ACTIVATIONS_ALL, + logInfo, + signatureCache + )); + bridgeSupport = initBridgeSupport(eventLogger, ACTIVATIONS_ALL); + // Set a high fee per kb to ensure the resulting pegout is above the min pegout value + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.COIN); + + int pegoutSize = BridgeUtils.getRegularPegoutTxSize( + ACTIVATIONS_ALL, + federationStorageProvider.getNewFederation(FEDERATION_CONSTANTS, ACTIVATIONS_ALL) + ); + Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); + Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times( + BRIDGE_CONSTANTS.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100) + ); + + Coin pegoutRequestValueWithGapAboveFee = minValueWithGapAboveFee.minus(Coin.SATOSHI); + co.rsk.core.Coin pegoutRequestValue = co.rsk.core.Coin.fromBitcoin(pegoutRequestValueWithGapAboveFee); + // Add some extra weis to the value, but less than 1 satoshi. + // To ensure that the pegout value is rounded down to fit in satoshis. + co.rsk.core.Coin oneSatoshiInWeis = co.rsk.core.Coin.fromBitcoin(Coin.SATOSHI); + co.rsk.core.Coin oneWei = co.rsk.core.Coin.valueOf(Denomination.WEI.longValue()); + co.rsk.core.Coin extraWeis = oneSatoshiInWeis.subtract(oneWei); + pegoutRequestValue = pegoutRequestValue.add(extraWeis); + + bridgeSupport.releaseBtc(buildReleaseRskTx(pegoutRequestValue)); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); + + verify(repository, times(1)).transfer( + BRIDGE_ADDRESS, + senderAddress, + pegoutRequestValue + ); assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); assertEquals(1, logInfo.size()); - verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); - verify(eventLogger, times(1)).logReleaseBtcRequestRejected( - senderAddress.toHexString(), - value, + senderAddress, + pegoutRequestValue, RejectedPegoutReason.FEE_ABOVE_VALUE ); + + LogInfo firstLog = logInfo.get(0); + CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); + assertArrayEquals(event.encodeSignatureLong(), firstLog.getTopics().get(0).getData()); + + BigInteger amount = (BigInteger) event.decodeEventData(firstLog.getData())[0]; + assertEquals(pegoutRequestValue.asBigInteger(), amount); } /********************************** @@ -1286,85 +1584,100 @@ private void testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(Coin fe *********************************/ private UTXO buildUTXO() { - return new UTXO(Sha256Hash.wrap(TestUtils.generateBytes("utxo",32)), 0, Coin.COIN.multiply(2), 1, false, activeFederation.getP2SHScript()); + return new UTXO( + Sha256Hash.wrap(TestUtils.generateBytes("utxo",32)), + 0, + Coin.COIN.multiply(2), + 1, + false, + activeFederation.getP2SHScript() + ); } private Transaction buildReleaseRskTx() { - return buildReleaseRskTx(Coin.COIN); + return buildReleaseRskTx(co.rsk.core.Coin.fromBitcoin(Coin.COIN)); } - private Transaction buildReleaseRskTx(Coin coin) { + private Transaction buildReleaseRskTx(co.rsk.core.Coin coin) { Transaction releaseTransaction = Transaction .builder() .nonce(NONCE) .gasPrice(GAS_PRICE) .gasLimit(GAS_LIMIT) - .destination(PrecompiledContracts.BRIDGE_ADDR.toHexString()) + .destination(BRIDGE_ADDRESS) .data(Hex.decode(DATA)) - .chainId(Constants.REGTEST_CHAIN_ID) - .value(co.rsk.core.Coin.fromBitcoin(coin).asBigInteger()) + .chainId(Constants.MAINNET_CHAIN_ID) + .value(coin) .build(); releaseTransaction.sign(SENDER.getPrivKeyBytes()); + return releaseTransaction; } - private Transaction buildReleaseRskTx_fromContract(Coin coin) { - Transaction releaseTransaction = Transaction - .builder() - .nonce(NONCE) - .gasPrice(GAS_PRICE) - .gasLimit(GAS_LIMIT) - .destination(PrecompiledContracts.BRIDGE_ADDR.toHexString()) - .data(Hex.decode(DATA)) - .chainId(Constants.REGTEST_CHAIN_ID) - .value(co.rsk.core.Coin.fromBitcoin(coin).asBigInteger()) - .build(); - releaseTransaction.sign(SENDER.getPrivKeyBytes()); - return new InternalTransaction(releaseTransaction.getHash().getBytes(), 400, 0, NONCE.toByteArray(), - DataWord.valueOf(GAS_PRICE.intValue()), DataWord.valueOf(GAS_LIMIT.intValue()), SENDER.getAddress(), - PrecompiledContracts.BRIDGE_ADDR.getBytes(), co.rsk.core.Coin.fromBitcoin(Coin.COIN).getBytes(), - Hex.decode(DATA), "", new BlockTxSignatureCache(new ReceivedTxSignatureCache())); + private Transaction buildReleaseRskTx_fromContract(co.rsk.core.Coin pegoutRequestValue) { + return new InternalTransaction( + RskTestUtils.createHash(4).getBytes(), + 400, + 0, + NONCE.toByteArray(), + DataWord.valueOf(GAS_PRICE.longValue()), + DataWord.valueOf(GAS_LIMIT.longValue()), + SENDER.getAddress(), + BRIDGE_ADDRESS.getBytes(), + pegoutRequestValue.getBytes(), + Hex.decode(DATA), + "", + new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + ); } private Transaction buildUpdateTx() { + final BigInteger value = new BigInteger("1"); + return Transaction .builder() .nonce(NONCE) .gasPrice(GAS_PRICE) .gasLimit(GAS_LIMIT) - .destination(Hex.decode(TO_ADDRESS)) + .destination(BRIDGE_ADDRESS) .data(Hex.decode(DATA)) - .chainId(Constants.REGTEST_CHAIN_ID) - .value(DUST_AMOUNT) + .chainId(Constants.MAINNET_CHAIN_ID) + .value(value) .build(); } - private BridgeSupport initBridgeSupport(BridgeEventLogger eventLogger, ActivationConfig.ForBlock activationMock) { + private BridgeSupport initBridgeSupport(BridgeEventLogger eventLogger, ActivationConfig.ForBlock activations) { FederationSupport federationSupport = FederationSupportBuilder.builder() - .withFederationConstants(federationConstants) + .withFederationConstants(FEDERATION_CONSTANTS) .withFederationStorageProvider(federationStorageProvider) .build(); return bridgeSupportBuilder - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(BRIDGE_CONSTANTS) .withProvider(provider) .withRepository(repository) .withEventLogger(eventLogger) - .withActivations(activationMock) + .withActivations(activations) .withSignatureCache(signatureCache) .withFederationSupport(federationSupport) .withFeePerKbSupport(feePerKbSupport) .build(); } - private BridgeStorageProvider initProvider(Repository repository, ActivationConfig.ForBlock activationMock) { - return new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, networkParameters, activationMock); + private BridgeStorageProvider initProvider() { + return new BridgeStorageProvider( + repository, + BRIDGE_ADDRESS, + NETWORK_PARAMETERS, + ACTIVATIONS_ALL + ); } - private FederationStorageProvider initFederationStorageProvider(Repository repository, ActivationConfig.ForBlock activationMock) { + private FederationStorageProvider initFederationStorageProvider() { + UTXO utxo = buildUTXO(); StorageAccessor bridgeStorageAccessor = new BridgeStorageAccessorImpl(repository); FederationStorageProvider storageProvider = new FederationStorageProviderImpl(bridgeStorageAccessor); - storageProvider.getNewFederationBtcUTXOs(networkParameters, activationMock).add(utxo); + storageProvider.getNewFederationBtcUTXOs(NETWORK_PARAMETERS, ACTIVATIONS_ALL).add(utxo); storageProvider.setNewFederation(activeFederation); return storageProvider; @@ -1373,12 +1686,4 @@ private FederationStorageProvider initFederationStorageProvider(Repository repos private static Repository createRepository() { return new MutableRepository(new MutableTrieCache(new MutableTrieImpl(null, new Trie()))); } - - private static Federation getFederation() { - FederationArgs federationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(3), - Instant.ofEpochMilli(1000), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); - return FederationFactory.buildStandardMultiSigFederation(federationArgs); - } } diff --git a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java index bff03605651..5330ddeb65c 100644 --- a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java @@ -62,7 +62,7 @@ class BridgeEventLoggerImplTest { private static final FederationConstants FEDERATION_CONSTANTS = BRIDGE_CONSTANTS.getFederationConstants(); private static final NetworkParameters NETWORK_PARAMETERS = BRIDGE_CONSTANTS.getBtcParams(); private static final BtcTransaction BTC_TRANSACTION = new BtcTransaction(NETWORK_PARAMETERS); - private static final RskAddress RSK_ADDRESS = new RskAddress("0x0000000000000000000000000000000000000000"); + private static final RskAddress RSK_ADDRESS = new RskAddress("0x0000000000000000000000000000000000000101"); private static final Keccak256 RSK_TX_HASH = RskTestUtils.createHash(1); private List eventLogs; @@ -75,7 +75,12 @@ void setup() { signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); eventLogs = new LinkedList<>(); - eventLogger = new BridgeEventLoggerImpl(BRIDGE_CONSTANTS, activations, eventLogs, signatureCache); + eventLogger = new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + activations, + eventLogs, + signatureCache + ); } @Test @@ -411,18 +416,23 @@ void logUnrefundablePegin() { } @Test - void testLogReleaseBtcRequestReceivedBeforeRSKIP326HardFork() { - ActivationConfig.ForBlock hopActivations = ActivationConfigsForTest.hop400().forBlock(0); - eventLogger = new BridgeEventLoggerImpl(BRIDGE_CONSTANTS, hopActivations, eventLogs, signatureCache); + void logReleaseBtcRequestReceived_preRSKIP326_destinationAddressAsHash160() { + ActivationConfig.ForBlock hopActivations = ActivationConfigsForTest.hop400().forBlock(0L); + eventLogger = new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + hopActivations, + eventLogs, + signatureCache + ); Address btcRecipientAddress = new Address( NETWORK_PARAMETERS, NETWORK_PARAMETERS.getP2SHHeader(), Hex.decode("6bf06473af5f595cf97702229b007e50d6cfba83") ); - Coin amount = Coin.COIN; + co.rsk.core.Coin amount = co.rsk.core.Coin.fromBitcoin(Coin.COIN); - eventLogger.logReleaseBtcRequestReceived(RSK_ADDRESS.toString(), btcRecipientAddress, amount); + eventLogger.logReleaseBtcRequestReceived(RSK_ADDRESS, btcRecipientAddress, amount); commonAssertLogs(eventLogs); assertTopics(2, eventLogs); @@ -430,21 +440,29 @@ void testLogReleaseBtcRequestReceivedBeforeRSKIP326HardFork() { eventLogs, 0, BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(), - new Object[]{RSK_ADDRESS.toString()}, - new Object[]{btcRecipientAddress.getHash160(), amount.value} + new Object[]{RSK_ADDRESS.toHexString()}, + new Object[]{btcRecipientAddress.getHash160(), amount.toBitcoin().getValue()} ); } @Test - void testLogReleaseBtcRequestReceivedAfterRSKIP326HardFork() { + void logReleaseBtcRequestReceived_postRSKIP326_destinationAddressAsBase58() { + ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0L); + eventLogger = new BridgeEventLoggerImpl( + BRIDGE_CONSTANTS, + arrowheadActivations, + eventLogs, + signatureCache + ); + Address btcRecipientAddress = new Address( NETWORK_PARAMETERS, NETWORK_PARAMETERS.getP2SHHeader(), Hex.decode("6bf06473af5f595cf97702229b007e50d6cfba83") ); - Coin amount = Coin.COIN; + co.rsk.core.Coin amount = co.rsk.core.Coin.fromBitcoin(Coin.COIN); - eventLogger.logReleaseBtcRequestReceived(RSK_ADDRESS.toString(), btcRecipientAddress, amount); + eventLogger.logReleaseBtcRequestReceived(RSK_ADDRESS, btcRecipientAddress, amount); commonAssertLogs(eventLogs); assertTopics(2, eventLogs); @@ -452,17 +470,42 @@ void testLogReleaseBtcRequestReceivedAfterRSKIP326HardFork() { eventLogs, 0, BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(), - new Object[]{RSK_ADDRESS.toString()}, - new Object[]{btcRecipientAddress.toString(), amount.value} + new Object[]{RSK_ADDRESS.toHexString()}, + new Object[]{btcRecipientAddress.toString(), amount.toBitcoin().getValue()} ); } @Test - void testLogReleaseBtcRequestRejected() { - Coin amount = Coin.COIN; + void logReleaseBtcRequestReceived_postRSKIP427_amountAsWeis() { + Address btcRecipientAddress = new Address( + NETWORK_PARAMETERS, + NETWORK_PARAMETERS.getP2SHHeader(), + Hex.decode("6bf06473af5f595cf97702229b007e50d6cfba83") + ); + co.rsk.core.Coin amount = co.rsk.core.Coin.fromBitcoin(Coin.COIN); + + eventLogger.logReleaseBtcRequestReceived(RSK_ADDRESS, btcRecipientAddress, amount); + + commonAssertLogs(eventLogs); + assertTopics(2, eventLogs); + assertEvent( + eventLogs, + 0, + BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(), + new Object[]{RSK_ADDRESS.toHexString()}, + new Object[]{btcRecipientAddress.toString(), amount.asBigInteger()} + ); + } + + @Test + void logReleaseBtcRequestRejected_preRSKIP427_logAmountAsSatoshis() { + ActivationConfig.ForBlock arrowheadActivations = ActivationConfigsForTest.arrowhead631().forBlock(0); + eventLogger = new BridgeEventLoggerImpl(BRIDGE_CONSTANTS, arrowheadActivations, eventLogs, signatureCache); + + co.rsk.core.Coin amount = co.rsk.core.Coin.valueOf(100_000_000_000_000_000L); RejectedPegoutReason reason = RejectedPegoutReason.LOW_AMOUNT; - eventLogger.logReleaseBtcRequestRejected(RSK_ADDRESS.toString(), amount, reason); + eventLogger.logReleaseBtcRequestRejected(RSK_ADDRESS, amount, reason); commonAssertLogs(eventLogs); assertTopics(2, eventLogs); @@ -470,8 +513,26 @@ void testLogReleaseBtcRequestRejected() { eventLogs, 0, BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(), - new Object[]{RSK_ADDRESS.toString()}, - new Object[]{amount.value, reason.getValue()} + new Object[]{RSK_ADDRESS.toHexString()}, + new Object[]{amount.toBitcoin().getValue(), reason.getValue()} + ); + } + + @Test + void logReleaseBtcRequestRejected_postRSKIP427_logAmountAsWeis() { + co.rsk.core.Coin amount = co.rsk.core.Coin.valueOf(100_000_000_000_000_000L); + RejectedPegoutReason reason = RejectedPegoutReason.LOW_AMOUNT; + + eventLogger.logReleaseBtcRequestRejected(RSK_ADDRESS, amount, reason); + + commonAssertLogs(eventLogs); + assertTopics(2, eventLogs); + assertEvent( + eventLogs, + 0, + BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(), + new Object[]{RSK_ADDRESS.toHexString()}, + new Object[]{amount.asBigInteger(), reason.getValue()} ); } diff --git a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java index fa0e9d175ae..822f232f1ac 100644 --- a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java @@ -18,49 +18,39 @@ package co.rsk.peg.utils; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import co.rsk.RskTestUtils; import co.rsk.bitcoinj.core.*; -import co.rsk.peg.constants.BridgeConstants; -import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; -import co.rsk.peg.*; +import co.rsk.peg.Bridge; +import co.rsk.peg.DeprecatedMethodCallException; +import co.rsk.peg.constants.BridgeConstants; +import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.peg.federation.*; -import co.rsk.peg.PegTestUtils; import co.rsk.peg.federation.constants.FederationConstants; -import org.bouncycastle.util.encoders.Hex; -import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.config.blockchain.upgrades.ConsensusRule; -import org.ethereum.core.*; -import org.ethereum.util.RLP; -import org.ethereum.util.RLPElement; -import org.ethereum.util.RLPList; -import org.ethereum.vm.DataWord; -import org.ethereum.vm.LogInfo; -import org.ethereum.vm.PrecompiledContracts; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.*; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.*; +import org.ethereum.util.*; +import org.ethereum.vm.*; +import org.junit.jupiter.api.*; /** * Test class for BridgeEventLoggerLegacyImpl. * * @author kelvin.isievwore */ - class BridgeEventLoggerLegacyImplTest { - private ActivationConfig.ForBlock activations; private List eventLogs; private BridgeEventLogger eventLogger; @@ -73,9 +63,14 @@ void setup() { activations = mock(ActivationConfig.ForBlock.class); eventLogs = new LinkedList<>(); constantsMock = mock(BridgeConstants.class); - eventLogger = new BrigeEventLoggerLegacyImpl(constantsMock, activations, eventLogs, new BlockTxSignatureCache(new ReceivedTxSignatureCache())); + eventLogger = new BrigeEventLoggerLegacyImpl( + constantsMock, + activations, + eventLogs, + new BlockTxSignatureCache(new ReceivedTxSignatureCache()) + ); btcTxMock = mock(BtcTransaction.class); - rskTxHash = PegTestUtils.createHash3(1); + rskTxHash = RskTestUtils.createHash(1); } @Test @@ -84,8 +79,7 @@ void testLogUpdateCollectionsBeforeRskip146() { // Setup Rsk transaction Transaction tx = mock(Transaction.class); - RskAddress sender = mock(RskAddress.class); - when(sender.toString()).thenReturn("0x0000000000000000000000000000000000000001"); + RskAddress sender = new RskAddress("0x0000000000000000000000000000000000000001"); when(tx.getSender(any(SignatureCache.class))).thenReturn(sender); // Act @@ -97,12 +91,12 @@ void testLogUpdateCollectionsBeforeRskip146() { LogInfo logResult = eventLogs.get(0); List topics = Collections.singletonList(Bridge.UPDATE_COLLECTIONS_TOPIC); for (int i = 0; i < topics.size(); i++) { - Assertions.assertEquals(topics.get(i), logResult.getTopics().get(i)); + assertEquals(topics.get(i), logResult.getTopics().get(i)); } // Assert log data byte[] encodedData = RLP.encodeElement(tx.getSender(new BlockTxSignatureCache(new ReceivedTxSignatureCache())).getBytes()); - Assertions.assertArrayEquals(encodedData, logResult.getData()); + assertArrayEquals(encodedData, logResult.getData()); } @Test @@ -130,21 +124,21 @@ void testLogAddSignatureBeforeRskip146() { LogInfo logResult = eventLogs.get(0); // Assert address that made the log - Assertions.assertEquals(PrecompiledContracts.BRIDGE_ADDR, new RskAddress(logResult.getAddress())); + assertEquals(PrecompiledContracts.BRIDGE_ADDR, new RskAddress(logResult.getAddress())); // Assert log topics - Assertions.assertEquals(1, logResult.getTopics().size()); - Assertions.assertEquals(Bridge.ADD_SIGNATURE_TOPIC, logResult.getTopics().get(0)); + assertEquals(1, logResult.getTopics().size()); + assertEquals(Bridge.ADD_SIGNATURE_TOPIC, logResult.getTopics().get(0)); // Assert log data - Assertions.assertNotNull(logResult.getData()); + assertNotNull(logResult.getData()); List rlpData = RLP.decode2(logResult.getData()); Assertions.assertEquals(1, rlpData.size()); RLPList dataList = (RLPList) rlpData.get(0); - Assertions.assertEquals(3, dataList.size()); - Assertions.assertArrayEquals(btcTxMock.getHashAsString().getBytes(), dataList.get(0).getRLPData()); - Assertions.assertArrayEquals(federatorPubKey.getPubKeyHash(), dataList.get(1).getRLPData()); - Assertions.assertArrayEquals(rskTxHash.getBytes(), dataList.get(2).getRLPData()); + assertEquals(3, dataList.size()); + assertArrayEquals(btcTxMock.getHashAsString().getBytes(), dataList.get(0).getRLPData()); + assertArrayEquals(federatorPubKey.getPubKeyHash(), dataList.get(1).getRLPData()); + assertArrayEquals(rskTxHash.getBytes(), dataList.get(2).getRLPData()); } @Test @@ -172,18 +166,18 @@ void testLogReleaseBtcBeforeRskip146() { LogInfo logResult = eventLogs.get(0); // Assert address that made the log - Assertions.assertEquals(PrecompiledContracts.BRIDGE_ADDR, new RskAddress(logResult.getAddress())); + assertEquals(PrecompiledContracts.BRIDGE_ADDR, new RskAddress(logResult.getAddress())); // Assert log topics - Assertions.assertEquals(1, logResult.getTopics().size()); + assertEquals(1, logResult.getTopics().size()); List topics = Collections.singletonList(Bridge.RELEASE_BTC_TOPIC); for (int i = 0; i < topics.size(); i++) { - Assertions.assertEquals(topics.get(i), logResult.getTopics().get(i)); + assertEquals(topics.get(i), logResult.getTopics().get(i)); } // Assert log data byte[] encodedData = RLP.encodeList(RLP.encodeString(btcTx.getHashAsString()), RLP.encodeElement(btcTx.bitcoinSerialize())); - Assertions.assertArrayEquals(encodedData, logResult.getData()); + assertArrayEquals(encodedData, logResult.getData()); } @Test @@ -233,49 +227,55 @@ void testLogCommitFederationBeforeRskip146() { eventLogger.logCommitFederation(executionBlock, oldFederation, newFederation); // Assert log size - Assertions.assertEquals(1, eventLogs.size()); + assertEquals(1, eventLogs.size()); LogInfo logResult = eventLogs.get(0); // Assert address that made the log - Assertions.assertEquals(PrecompiledContracts.BRIDGE_ADDR, new RskAddress(logResult.getAddress())); + assertEquals(PrecompiledContracts.BRIDGE_ADDR, new RskAddress(logResult.getAddress())); // Assert log topics - Assertions.assertEquals(1, logResult.getTopics().size()); - Assertions.assertEquals(Bridge.COMMIT_FEDERATION_TOPIC, logResult.getTopics().get(0)); + assertEquals(1, logResult.getTopics().size()); + assertEquals(Bridge.COMMIT_FEDERATION_TOPIC, logResult.getTopics().get(0)); // Assert log data - Assertions.assertNotNull(logResult.getData()); + assertNotNull(logResult.getData()); List rlpData = RLP.decode2(logResult.getData()); - Assertions.assertEquals(1, rlpData.size()); + assertEquals(1, rlpData.size()); RLPList dataList = (RLPList) rlpData.get(0); - Assertions.assertEquals(3, dataList.size()); + assertEquals(3, dataList.size()); // Assert old federation data RLPList oldFedData = (RLPList) dataList.get(0); - Assertions.assertEquals(2, oldFedData.size()); - Assertions.assertArrayEquals(oldFederation.getAddress().getHash160(), oldFedData.get(0).getRLPData()); + assertEquals(2, oldFedData.size()); + assertArrayEquals(oldFederation.getAddress().getHash160(), oldFedData.get(0).getRLPData()); RLPList oldFedPubKeys = (RLPList) oldFedData.get(1); - Assertions.assertEquals(4, oldFedPubKeys.size()); + assertEquals(4, oldFedPubKeys.size()); for (int i = 0; i < 4; i++) { - Assertions.assertEquals(oldFederation.getBtcPublicKeys().get(i), BtcECKey.fromPublicOnly(oldFedPubKeys.get(i).getRLPData())); + assertEquals(oldFederation.getBtcPublicKeys().get(i), BtcECKey.fromPublicOnly(oldFedPubKeys.get(i).getRLPData())); } // Assert new federation data RLPList newFedData = (RLPList) dataList.get(1); - Assertions.assertEquals(2, newFedData.size()); - Assertions.assertArrayEquals(newFederation.getAddress().getHash160(), newFedData.get(0).getRLPData()); + assertEquals(2, newFedData.size()); + assertArrayEquals(newFederation.getAddress().getHash160(), newFedData.get(0).getRLPData()); RLPList newFedPubKeys = (RLPList) newFedData.get(1); - Assertions.assertEquals(3, newFedPubKeys.size()); + assertEquals(3, newFedPubKeys.size()); for (int i = 0; i < 3; i++) { - Assertions.assertEquals(newFederation.getBtcPublicKeys().get(i), BtcECKey.fromPublicOnly(newFedPubKeys.get(i).getRLPData())); + assertEquals( + newFederation.getBtcPublicKeys().get(i), + BtcECKey.fromPublicOnly(newFedPubKeys.get(i).getRLPData()) + ); } // Assert new federation activation block number FederationConstants federationConstants = constantsMock.getFederationConstants(); - Assertions.assertEquals(15L + federationConstants.getFederationActivationAge(activations), Long.valueOf(new String(dataList.get(2).getRLPData(), StandardCharsets.UTF_8)).longValue()); + assertEquals( + 15L + federationConstants.getFederationActivationAge(activations), + Long.valueOf(new String(dataList.get(2).getRLPData(), StandardCharsets.UTF_8)).longValue() + ); } @Test @@ -284,7 +284,10 @@ void testLogCommitFederationAfterRskip146() { when(activations.isActive(ConsensusRule.RSKIP146)).thenReturn(true); // Act - assertThrows(DeprecatedMethodCallException.class, () -> eventLogger.logCommitFederation(mock(Block.class), mock(Federation.class), mock(Federation.class))); + assertThrows( + DeprecatedMethodCallException.class, + () -> eventLogger.logCommitFederation(mock(Block.class), mock(Federation.class), mock(Federation.class)) + ); } /********************************** diff --git a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerTest.java b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerTest.java index 4fdc3281252..598d233c48c 100644 --- a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerTest.java @@ -1,25 +1,19 @@ package co.rsk.peg.utils; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +import co.rsk.RskTestUtils; import co.rsk.bitcoinj.core.*; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; -import co.rsk.peg.PegTestUtils; - -import static org.junit.jupiter.api.Assertions.*; - import co.rsk.peg.pegin.RejectedPeginReason; -import java.util.Arrays; +import java.util.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; - class BridgeEventLoggerTest { - private BridgeEventLogger eventLogger; private BtcTransaction btcTxMock; private Keccak256 rskTxHash; @@ -28,91 +22,109 @@ class BridgeEventLoggerTest { void setup() { eventLogger = spy(BridgeEventLogger.class); btcTxMock = mock(BtcTransaction.class); - rskTxHash = PegTestUtils.createHash3(1); + rskTxHash = RskTestUtils.createHash(1); } @Test - void testLogLockBtc() { - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logLockBtc(mock(RskAddress.class), btcTxMock, mock(Address.class), - Coin.SATOSHI); - }); + void logLockBtc() { + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logLockBtc( + mock(RskAddress.class), + btcTxMock, + mock(Address.class), + Coin.SATOSHI + )); } @Test - void testLogPeginBtc() { - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logPeginBtc(mock(RskAddress.class), btcTxMock, Coin.SATOSHI, 1); - }); + void logPeginBtc() { + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logPeginBtc( + mock(RskAddress.class), + btcTxMock, + Coin.SATOSHI, + 1 + )); } @Test - void testLogReleaseBtcRequested() { + void logReleaseBtcRequested() { byte[] rskTxHashBytes = rskTxHash.getBytes(); - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logReleaseBtcRequested(rskTxHashBytes, btcTxMock, Coin.SATOSHI); - }); + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logReleaseBtcRequested( + rskTxHashBytes, + btcTxMock, + Coin.SATOSHI + )); } @Test - void testLogRejectedPegin() { - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logRejectedPegin(btcTxMock, RejectedPeginReason.PEGIN_CAP_SURPASSED); - }); + void logRejectedPegin() { + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logRejectedPegin( + btcTxMock, + RejectedPeginReason.PEGIN_CAP_SURPASSED + )); } @Test - void testLogUnrefundablePegin() { - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logUnrefundablePegin(btcTxMock, - UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); - }); + void logUnrefundablePegin() { + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logUnrefundablePegin( + btcTxMock, + UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER + )); } @Test - void testLogReleaseBtcRequestReceived() { - String sender = "0x00000000000000000000000000000000000000"; - String base58Address = "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn"; + void logReleaseBtcRequestReceived() { + RskAddress sender = new RskAddress("0x0000000000000000000000000000000000001101"); + String base58Address = "16SL1Qsw1eyYWM58MFh9KwKYoxYmm3fM1Z"; Address btcDestinationAddress = Address.fromBase58( - NetworkParameters.fromID(NetworkParameters.ID_REGTEST), base58Address); - Coin amount = Coin.COIN; - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logReleaseBtcRequestReceived(sender, btcDestinationAddress, amount); - }); + NetworkParameters.fromID(NetworkParameters.ID_MAINNET), + base58Address + ); + co.rsk.core.Coin amount = co.rsk.core.Coin.fromBitcoin(Coin.COIN); + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logReleaseBtcRequestReceived( + sender, + btcDestinationAddress, + amount + )); } @Test - void testLogReleaseBtcRequestRejected() { - String sender = "0x00000000000000000000000000000000000000"; - Coin amount = Coin.COIN; - RejectedPegoutReason reason = RejectedPegoutReason.LOW_AMOUNT; - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logReleaseBtcRequestRejected(sender, amount, reason); - }); + void logReleaseBtcRequestRejected() { + RskAddress sender = new RskAddress("0x0000000000000000000000000000000000020002"); + co.rsk.core.Coin amount = co.rsk.core.Coin.fromBitcoin(Coin.COIN); + RejectedPegoutReason reason = RejectedPegoutReason.LOW_AMOUNT; // Any reason, just testing the call to the method + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logReleaseBtcRequestRejected( + sender, + amount, + reason + )); } @Test void logBatchPegoutCreated() { Sha256Hash btcTxHash = btcTxMock.getHash(); List rskTxHashes = new ArrayList<>(); - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logBatchPegoutCreated(btcTxHash, rskTxHashes); - }); + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logBatchPegoutCreated( + btcTxHash, + rskTxHashes + )); } @Test void logPegoutConfirmed() { Sha256Hash btcTxHash = btcTxMock.getHash(); - assertThrows(UnsupportedOperationException.class, () -> { - eventLogger.logPegoutConfirmed(btcTxHash, 5); - }); + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logPegoutConfirmed( + btcTxHash, + 5 + )); } @Test void logPegoutTransactionCreated() { Sha256Hash btcTxHash = btcTxMock.getHash(); List outpointValues = Arrays.asList(Coin.COIN, Coin.SATOSHI, Coin.FIFTY_COINS); - assertThrows(UnsupportedOperationException.class, - () -> eventLogger.logPegoutTransactionCreated(btcTxHash, outpointValues)); + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logPegoutTransactionCreated( + btcTxHash, + outpointValues + )); } } diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java index 167d30f3f8b..d94e90569ce 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java @@ -18,115 +18,115 @@ package org.ethereum.config.blockchain.upgrades; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; -import com.typesafe.config.ConfigValueFactory; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.typesafe.config.*; import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.hamcrest.Matchers.is; - class ActivationConfigTest { private static final Config BASE_CONFIG = ConfigFactory.parseString(String.join("\n", - "hardforkActivationHeights: {", - " genesis: 0", - " bahamas: 0", - " afterBridgeSync: 0,", - " orchid: 0,", - " orchid060: 0,", - " wasabi100: 0", - " papyrus200: 0", - " twoToThree: 0", - " iris300: 0", - " hop400: 0", - " hop401: 0", - " fingerroot500: 0", - " arrowhead600: 0", - " arrowhead631: 0", - " lovell700: 0", - "},", - "consensusRules: {", - " areBridgeTxsPaid: afterBridgeSync,", - " rskip85: orchid,", - " rskip87: orchid,", - " rskip88: orchid,", - " rskip89: orchid,", - " rskip90: orchid,", - " rskip91: orchid,", - " rskip92: orchid,", - " rskip97: orchid,", - " rskip98: orchid,", - " rskip103: orchid060,", - " rskip106: wasabi100,", - " rskip110: wasabi100,", - " rskip119: wasabi100,", - " rskip120: wasabi100,", - " rskip122: wasabi100,", - " rskip123: wasabi100,", - " rskip124: wasabi100,", - " rskip125: wasabi100", - " rskip126: wasabi100", - " rskip132: wasabi100", - " rskip134: papyrus200", - " rskip136: bahamas", - " rskip137: papyrus200", - " rskip140: papyrus200,", - " rskip143: papyrus200", - " rskip146: papyrus200", - " rskip150: twoToThree", - " rskip151: papyrus200", - " rskip152: papyrus200", - " rskip156: papyrus200", - " rskipUMM: papyrus200", - " rskip153: iris300", - " rskip169: iris300", - " rskip170: iris300", - " rskip171: iris300", - " rskip174: iris300", - " rskip176: iris300", - " rskip179: iris300", - " rskip180: iris300", - " rskip181: iris300", - " rskip185: iris300", - " rskip186: iris300", - " rskip191: iris300", - " rskip197: iris300", - " rskip199: iris300", - " rskip200: iris300", - " rskip201: iris300", - " rskip203: arrowhead600", - " rskip218: iris300", - " rskip219: iris300", - " rskip220: iris300", - " rskip252: fingerroot500", - " rskip271: hop400", - " rskip284: hop400", - " rskip290: hop400", - " rskip293: hop400", - " rskip294: hop400", - " rskip144: arrowhead600", - " rskip297: hop400", - " rskip351: arrowhead600", - " rskip326: fingerroot500", - " rskip353: hop401", - " rskip357: hop401", - " rskip374: fingerroot500", - " rskip375: fingerroot500", - " rskip376: arrowhead600", - " rskip377: fingerroot500", - " rskip379: arrowhead600", - " rskip383: fingerroot500", - " rskip385: fingerroot500", - " rskip398: arrowhead600", - " rskip400: arrowhead600", - " rskip412: arrowhead600", - " rskip415: arrowhead600", - " rskip417: arrowhead600", - " rskip434: arrowhead631", - " rskip428: lovell700", - " rskip438: lovell700", - "}" + "hardforkActivationHeights: {", + " genesis: 0", + " bahamas: 0", + " afterBridgeSync: 0,", + " orchid: 0,", + " orchid060: 0,", + " wasabi100: 0", + " papyrus200: 0", + " twoToThree: 0", + " iris300: 0", + " hop400: 0", + " hop401: 0", + " fingerroot500: 0", + " arrowhead600: 0", + " arrowhead631: 0", + " lovell700: 0", + "},", + "consensusRules: {", + " areBridgeTxsPaid: afterBridgeSync,", + " rskip85: orchid,", + " rskip87: orchid,", + " rskip88: orchid,", + " rskip89: orchid,", + " rskip90: orchid,", + " rskip91: orchid,", + " rskip92: orchid,", + " rskip97: orchid,", + " rskip98: orchid,", + " rskip103: orchid060,", + " rskip106: wasabi100,", + " rskip110: wasabi100,", + " rskip119: wasabi100,", + " rskip120: wasabi100,", + " rskip122: wasabi100,", + " rskip123: wasabi100,", + " rskip124: wasabi100,", + " rskip125: wasabi100", + " rskip126: wasabi100", + " rskip132: wasabi100", + " rskip134: papyrus200", + " rskip136: bahamas", + " rskip137: papyrus200", + " rskip140: papyrus200,", + " rskip143: papyrus200", + " rskip144: arrowhead600", + " rskip146: papyrus200", + " rskip150: twoToThree", + " rskip151: papyrus200", + " rskip152: papyrus200", + " rskip156: papyrus200", + " rskipUMM: papyrus200", + " rskip153: iris300", + " rskip169: iris300", + " rskip170: iris300", + " rskip171: iris300", + " rskip174: iris300", + " rskip176: iris300", + " rskip179: iris300", + " rskip180: iris300", + " rskip181: iris300", + " rskip185: iris300", + " rskip186: iris300", + " rskip191: iris300", + " rskip197: iris300", + " rskip199: iris300", + " rskip200: iris300", + " rskip201: iris300", + " rskip203: arrowhead600", + " rskip218: iris300", + " rskip219: iris300", + " rskip220: iris300", + " rskip252: fingerroot500", + " rskip271: hop400", + " rskip284: hop400", + " rskip290: hop400", + " rskip293: hop400", + " rskip294: hop400", + " rskip297: hop400", + " rskip326: fingerroot500", + " rskip351: arrowhead600", + " rskip353: hop401", + " rskip357: hop401", + " rskip374: fingerroot500", + " rskip375: fingerroot500", + " rskip376: arrowhead600", + " rskip377: fingerroot500", + " rskip379: arrowhead600", + " rskip383: fingerroot500", + " rskip385: fingerroot500", + " rskip398: arrowhead600", + " rskip400: arrowhead600", + " rskip412: arrowhead600", + " rskip415: arrowhead600", + " rskip417: arrowhead600", + " rskip427: lovell700", + " rskip428: lovell700", + " rskip434: arrowhead631", + " rskip438: lovell700", + "}" )); @Test @@ -172,36 +172,36 @@ void readWithOneHardcodedActivationNumber() { @Test void failsReadingWithMissingNetworkUpgrade() { Config config = BASE_CONFIG.withoutPath("consensusRules.rskip85"); - Assertions.assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); + assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); } @Test void failsReadingWithMissingHardFork() { Config config = BASE_CONFIG.withoutPath("hardforkActivationHeights.orchid"); - Assertions.assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); + assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); } @Test void failsReadingWithUnknownForkConfiguration() { Config config = BASE_CONFIG.withValue("hardforkActivationHeights.orkid", ConfigValueFactory.fromAnyRef(200)); - Assertions.assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); + assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); } @Test void failsReadingWithUnknownUpgradeConfiguration() { Config config = BASE_CONFIG.withValue("consensusRules.rskip420", ConfigValueFactory.fromAnyRef("orchid")); - Assertions.assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); + assertThrows(IllegalArgumentException.class, () -> ActivationConfig.read(config)); } @Test void headerVersion0() { ActivationConfig config = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP351); - Assertions.assertEquals((byte) 0x0, config.getHeaderVersion(10)); + assertEquals((byte) 0x0, config.getHeaderVersion(10)); } @Test void headerVersion1() { ActivationConfig config = ActivationConfigsForTest.all(); - Assertions.assertEquals((byte) 0x1, config.getHeaderVersion(10)); + assertEquals((byte) 0x1, config.getHeaderVersion(10)); } } diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java index 889f5db90cf..4aab321e760 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java @@ -19,12 +19,11 @@ package org.ethereum.config.blockchain.upgrades; import com.typesafe.config.ConfigFactory; -import org.ethereum.config.SystemProperties; - -import javax.annotation.Nullable; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import javax.annotation.Nullable; +import org.ethereum.config.SystemProperties; @SuppressWarnings({"squid:S2187"}) // used from another class public class ActivationConfigsForTest { @@ -32,12 +31,11 @@ public class ActivationConfigsForTest { private static final ActivationConfig REGTEST = read("config/regtest"); private static List getPaidBridgeTxsRskip() { - return Arrays.asList(ConsensusRule.ARE_BRIDGE_TXS_PAID); + return Collections.singletonList(ConsensusRule.ARE_BRIDGE_TXS_PAID); } private static List getOrchidRskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP85, ConsensusRule.RSKIP87, ConsensusRule.RSKIP88, @@ -48,8 +46,6 @@ private static List getOrchidRskips() { ConsensusRule.RSKIP97, ConsensusRule.RSKIP98 )); - - return rskips; } private static List getOrchid060Rskips() { @@ -60,8 +56,7 @@ private static List getOrchid060Rskips() { } private static List getWasabi100Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP103, ConsensusRule.RSKIP106, ConsensusRule.RSKIP110, @@ -74,8 +69,6 @@ private static List getWasabi100Rskips() { ConsensusRule.RSKIP126, ConsensusRule.RSKIP132 )); - - return rskips; } private static List getBahamasRskips() { @@ -93,8 +86,7 @@ private static List getTwoToThreeRskips() { } private static List getPapyrus200Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP134, ConsensusRule.RSKIP137, ConsensusRule.RSKIP140, @@ -106,13 +98,10 @@ private static List getPapyrus200Rskips() { ConsensusRule.RSKIP156, ConsensusRule.RSKIPUMM )); - - return rskips; } private static List getIris300Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP153, ConsensusRule.RSKIP169, ConsensusRule.RSKIP170, @@ -133,13 +122,10 @@ private static List getIris300Rskips() { ConsensusRule.RSKIP219, ConsensusRule.RSKIP220 )); - - return rskips; } private static List getHop400Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP271, ConsensusRule.RSKIP284, ConsensusRule.RSKIP290, @@ -147,23 +133,17 @@ private static List getHop400Rskips() { ConsensusRule.RSKIP294, ConsensusRule.RSKIP297 )); - - return rskips; } private static List getHop401Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP353, ConsensusRule.RSKIP357 )); - - return rskips; } private static List getFingerroot500Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP252, ConsensusRule.RSKIP326, ConsensusRule.RSKIP374, @@ -172,13 +152,10 @@ private static List getFingerroot500Rskips() { ConsensusRule.RSKIP383, ConsensusRule.RSKIP385 )); - - return rskips; } private static List getArrowhead600Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( ConsensusRule.RSKIP203, ConsensusRule.RSKIP376, ConsensusRule.RSKIP379, @@ -189,25 +166,19 @@ private static List getArrowhead600Rskips() { ConsensusRule.RSKIP144, ConsensusRule.RSKIP351 )); - - return rskips; } private static List getArrowhead631Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Collections.singletonList( + return new ArrayList<>(Collections.singletonList( ConsensusRule.RSKIP434 )); - - return rskips; } private static List getLovell700Rskips() { - List rskips = new ArrayList<>(); - rskips.addAll(Arrays.asList( + return new ArrayList<>(Arrays.asList( + ConsensusRule.RSKIP427, ConsensusRule.RSKIP428 )); - return rskips; } public static ActivationConfig genesis() {