From 4037ab7b9957cfc635035599b9327935d73e4cc4 Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Tue, 31 Dec 2024 10:53:27 -0400 Subject: [PATCH] - Rename CANNOT_BE_PROCESSED entry to CANNOT_BE_REFUNDED since now rejected pegin should be marked as processed - Update BridgeSupportRegisterBtcTransactionTest to assert rejected pegin are marked as processed since RSKIP459 - Add tests asserting rejected pegin are marked as processed once RSKIP459 is active --- .../main/java/co/rsk/peg/BridgeSupport.java | 49 +- .../src/main/java/co/rsk/peg/PegUtils.java | 6 +- .../co/rsk/peg/pegin/PeginProcessAction.java | 2 +- ...idgeSupportRegisterBtcTransactionTest.java | 41 +- .../peg/BridgeSupportRejectedPeginTest.java | 615 ++++++++++++++++++ .../java/co/rsk/peg/BridgeSupportSvpTest.java | 36 +- .../co/rsk/peg/PegUtilsEvaluatePeginTest.java | 6 +- 7 files changed, 708 insertions(+), 47 deletions(-) create mode 100644 rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java 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 21e84e932d6..0597978faf5 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -503,42 +503,45 @@ protected void registerPegIn( ); PeginProcessAction peginProcessAction = peginEvaluationResult.getPeginProcessAction(); + + if (peginProcessAction == PeginProcessAction.CAN_BE_REGISTERED){ + logger.debug("[{}] Peg-in is valid, going to register", METHOD_NAME); + executePegIn(btcTx, peginInformation, totalAmount); + return; + } + + // If the peg-in cannot be registered means it should be rejected + Optional rejectedPeginReasonOptional = peginEvaluationResult.getRejectedPeginReason(); + if (rejectedPeginReasonOptional.isEmpty()) { + // This flow should never be reached. There should always be a rejected pegin reason. + String message = "Invalid state. No rejected reason was returned for an invalid pegin."; + logger.error("[{}] {}", METHOD_NAME, message); + throw new IllegalStateException(message); + } + RejectedPeginReason rejectedPeginReason = rejectedPeginReasonOptional.get(); + logger.debug("[{}] Rejected peg-in, reason {}", METHOD_NAME, rejectedPeginReason); + eventLogger.logRejectedPegin(btcTx, rejectedPeginReason); + switch (peginProcessAction) { - case CAN_BE_REGISTERED -> { - logger.debug("[{}] Peg-in is valid, going to register", METHOD_NAME); - executePegIn(btcTx, peginInformation, totalAmount); - } - case CAN_BE_REFUNDED -> { + case CAN_BE_REFUNDED: logger.debug("[{}] Refunding to address {} ", METHOD_NAME, peginInformation.getBtcRefundAddress()); generateRejectionRelease(btcTx, peginInformation.getBtcRefundAddress(), rskTxHash, totalAmount); markTxAsProcessed(btcTx); - } - default -> { - Optional rejectedPeginReasonOptional = peginEvaluationResult.getRejectedPeginReason(); - if (rejectedPeginReasonOptional.isEmpty()) { - // This flow should never be reached. There should always be a rejected pegin reason. - String message = "Invalid state. No rejected reason was returned from evaluatePegin method"; - logger.error("[{}] {}", METHOD_NAME, message); - throw new IllegalStateException(message); - } - RejectedPeginReason rejectedPeginReason = rejectedPeginReasonOptional.get(); - logger.debug("[{}] Rejected peg-in, reason {}", METHOD_NAME, rejectedPeginReason); - eventLogger.logRejectedPegin(btcTx, rejectedPeginReason); - logger.debug("[{}] Unprocessable transaction {}.", METHOD_NAME, btcTx.getHash()); - handleUnprocessableBtcTx(btcTx, peginInformation.getProtocolVersion(), - rejectedPeginReason); - + break; + case CANNOT_BE_REFUNDED: + logger.debug("[{}] Nonrefundable transaction {}.", METHOD_NAME, btcTx.getHash()); + handleNonRefundablePegin(btcTx, peginInformation.getProtocolVersion(), rejectedPeginReason); // Since RSKIP459, rejected peg-ins should be marked as processed if (activations.isActive(RSKIP459)) { markTxAsProcessed(btcTx); } - } + break; } } - private void handleUnprocessableBtcTx( + private void handleNonRefundablePegin( BtcTransaction btcTx, int protocolVersion, RejectedPeginReason rejectedPeginReason diff --git a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java index 6e25ba8051f..afe6ef68625 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java @@ -182,7 +182,7 @@ static PeginEvaluationResult evaluatePegin( if(!allUTXOsToFedAreAboveMinimumPeginValue(btcTx, fedWallet, minimumPeginTxValue, activations)) { logger.debug("[evaluatePegin] Peg-in contains at least one utxo below the minimum value"); - return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_PROCESSED, INVALID_AMOUNT); + return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_REFUNDED, INVALID_AMOUNT); } try { @@ -197,7 +197,7 @@ static PeginEvaluationResult evaluatePegin( PeginProcessAction peginProcessAction = hasRefundAddress ? PeginProcessAction.CAN_BE_REFUNDED : - PeginProcessAction.CANNOT_BE_PROCESSED; + PeginProcessAction.CANNOT_BE_REFUNDED; return new PeginEvaluationResult(peginProcessAction, PEGIN_V1_INVALID_PAYLOAD); } @@ -225,7 +225,7 @@ private static PeginEvaluationResult evaluateLegacyPeginSender(TxSenderAddressTy case P2SHP2WSH: return new PeginEvaluationResult(PeginProcessAction.CAN_BE_REFUNDED, LEGACY_PEGIN_MULTISIG_SENDER); default: - return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_PROCESSED, LEGACY_PEGIN_UNDETERMINED_SENDER); + return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_REFUNDED, LEGACY_PEGIN_UNDETERMINED_SENDER); } } diff --git a/rskj-core/src/main/java/co/rsk/peg/pegin/PeginProcessAction.java b/rskj-core/src/main/java/co/rsk/peg/pegin/PeginProcessAction.java index 57d451076df..5fc6708c079 100644 --- a/rskj-core/src/main/java/co/rsk/peg/pegin/PeginProcessAction.java +++ b/rskj-core/src/main/java/co/rsk/peg/pegin/PeginProcessAction.java @@ -3,5 +3,5 @@ public enum PeginProcessAction { CAN_BE_REGISTERED, CAN_BE_REFUNDED, - CANNOT_BE_PROCESSED + CANNOT_BE_REFUNDED } diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java index aecb7505444..d7d551fb881 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -44,6 +44,7 @@ import java.util.stream.Stream; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.*; +import org.ethereum.config.blockchain.upgrades.ActivationConfig.ForBlock; import org.ethereum.core.*; import org.ethereum.crypto.ECKey; import org.ethereum.vm.PrecompiledContracts; @@ -108,11 +109,13 @@ private void assertInvalidPeginIsIgnored() throws IOException { } // After peg-out tx index gets in use - private void assertInvalidPeginIsRejectedWithInvalidAmountReason(BtcTransaction btcTransaction) throws IOException { + private void assertInvalidPeginIsRejectedWithInvalidAmountReason(BtcTransaction btcTransaction, ActivationConfig.ForBlock activations) throws IOException { verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, INVALID_AMOUNT); verify(bridgeEventLogger, times(1)).logUnrefundablePegin(btcTransaction, UnrefundablePeginReason.INVALID_AMOUNT); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); - verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + + var shouldMarkTxAsProcessed = activations == lovell700Activations? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); assertTrue(activeFederationUtxos.isEmpty()); assertTrue(retiringFederationUtxos.isEmpty()); } @@ -194,7 +197,13 @@ private void assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloa } // After arrowhead600Activations is activated - private void assertLegacyUndeterminedSenderPeginIsRejected(BtcTransaction btcTransaction) throws IOException { + private void assertLegacyUndeterminedSenderPeginIsRejected(BtcTransaction btcTransaction, + ForBlock activations) throws IOException { + + // tx should be marked as processed since RSKIP459 is active + var shouldMarkTxAsProcessed = activations == lovell700Activations? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER ); @@ -205,14 +214,18 @@ private void assertLegacyUndeterminedSenderPeginIsRejected(BtcTransaction btcTra verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); - verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); Assertions.assertTrue(activeFederationUtxos.isEmpty()); Assertions.assertTrue(retiringFederationUtxos.isEmpty()); Assertions.assertTrue(pegoutsWaitingForConfirmations.getEntries().isEmpty()); } - private void assertInvalidPeginV1UndeterminedSenderIsRejected(BtcTransaction btcTransaction) throws IOException { + private void assertInvalidPeginV1UndeterminedSenderIsRejected(BtcTransaction btcTransaction, + ForBlock activations) throws IOException { + + var shouldMarkTxAsProcessed = activations == lovell700Activations? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, PEGIN_V1_INVALID_PAYLOAD ); @@ -224,7 +237,6 @@ private void assertInvalidPeginV1UndeterminedSenderIsRejected(BtcTransaction btc verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); verify(bridgeEventLogger, never()).logPegoutTransactionCreated(any(), any()); - verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); assertTrue(activeFederationUtxos.isEmpty()); assertTrue(retiringFederationUtxos.isEmpty()); @@ -932,7 +944,7 @@ void pegin_to_active_fed_below_minimum( // assert if (shouldUsePegoutTxIndex) { - assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction); + assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction, activations); } else { assertInvalidPeginIsIgnored(); } @@ -970,7 +982,7 @@ void pegin_to_active_fed_below_and_above_minimum( // assert if (shouldUsePegoutTxIndex) { - assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction); + assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction, activations); } else { assertInvalidPeginIsIgnored(); } @@ -1012,7 +1024,7 @@ void pegin_multiple_outputs_to_active_fed_sum_amount_equal_to_minimum_pegin( // assert if (shouldUsePegoutTxIndex) { - assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction); + assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction, activations); } else { assertInvalidPeginIsIgnored(); } @@ -1085,7 +1097,7 @@ void pegin_to_active_fed_below_minimum_and_retiring_above_minimum( // assert if (shouldUsePegoutTxIndex) { - assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction); + assertInvalidPeginIsRejectedWithInvalidAmountReason(btcTransaction, activations); } else { assertInvalidPeginIsIgnored(); } @@ -1405,7 +1417,7 @@ void pegin_v1_to_active_fed_with_invalid_payload_and_unknown_sender_cannot_be_pr if (activations == fingerrootActivations){ assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloadBeforeRSKIP379(btcTransaction); } else { - assertInvalidPeginV1UndeterminedSenderIsRejected(btcTransaction); + assertInvalidPeginV1UndeterminedSenderIsRejected(btcTransaction, activations); } } @@ -1494,7 +1506,7 @@ void pegin_to_retiring_fed_cannot_be_processed( if (activations == fingerrootActivations){ assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloadBeforeRSKIP379(btcTransaction); } else { - assertLegacyUndeterminedSenderPeginIsRejected(btcTransaction); + assertLegacyUndeterminedSenderPeginIsRejected(btcTransaction, activations); } } @@ -1543,12 +1555,11 @@ void pegin_legacy_from_segwit_to_active_fed_cannot_be_processed( ); // assert - - // SINCE RSKIP379 ONLY TRANSACTIONS THAT REALLY ARE PROCESSED, REFUNDS OR REGISTER WILL BE MARK AS PROCESSED. if (activations == fingerrootActivations){ + // BEFORE RSKIP379 REJECTED PEGIN WERE MARKED AS PROCESSED. assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloadBeforeRSKIP379(btcTransaction); } else { - assertLegacyUndeterminedSenderPeginIsRejected(btcTransaction); + assertLegacyUndeterminedSenderPeginIsRejected(btcTransaction, activations); } } diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java new file mode 100644 index 00000000000..e4c3a6905ee --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java @@ -0,0 +1,615 @@ +package co.rsk.peg; + +import static co.rsk.peg.BridgeSupportTestUtil.mockChainOfStoredBlocks; +import static co.rsk.peg.pegin.RejectedPeginReason.INVALID_AMOUNT; +import static co.rsk.peg.pegin.RejectedPeginReason.PEGIN_V1_INVALID_PAYLOAD; +import static co.rsk.peg.utils.UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import co.rsk.bitcoinj.core.Address; +import co.rsk.bitcoinj.core.BtcECKey; +import co.rsk.bitcoinj.core.BtcTransaction; +import co.rsk.bitcoinj.core.Coin; +import co.rsk.bitcoinj.core.NetworkParameters; +import co.rsk.bitcoinj.core.PartialMerkleTree; +import co.rsk.bitcoinj.core.Sha256Hash; +import co.rsk.bitcoinj.core.StoredBlock; +import co.rsk.bitcoinj.core.UTXO; +import co.rsk.bitcoinj.script.Script; +import co.rsk.bitcoinj.store.BlockStoreException; +import co.rsk.core.RskAddress; +import co.rsk.crypto.Keccak256; +import co.rsk.peg.bitcoin.BitcoinTestUtils; +import co.rsk.peg.btcLockSender.BtcLockSenderProvider; +import co.rsk.peg.constants.BridgeConstants; +import co.rsk.peg.constants.BridgeMainNetConstants; +import co.rsk.peg.federation.Federation; +import co.rsk.peg.federation.FederationArgs; +import co.rsk.peg.federation.FederationFactory; +import co.rsk.peg.federation.FederationMember; +import co.rsk.peg.federation.FederationStorageProvider; +import co.rsk.peg.federation.FederationSupport; +import co.rsk.peg.federation.FederationTestUtils; +import co.rsk.peg.federation.constants.FederationConstants; +import co.rsk.peg.lockingcap.LockingCapSupport; +import co.rsk.peg.pegin.PeginProcessAction; +import co.rsk.peg.pegin.RejectedPeginReason; +import co.rsk.peg.pegininstructions.PeginInstructionsProvider; +import co.rsk.peg.utils.BridgeEventLogger; +import co.rsk.peg.utils.UnrefundablePeginReason; +import co.rsk.test.builders.BridgeSupportBuilder; +import co.rsk.test.builders.FederationSupportBuilder; +import java.io.IOException; +import java.math.BigInteger; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; +import org.ethereum.core.Block; +import org.ethereum.core.Repository; +import org.ethereum.core.Transaction; +import org.ethereum.vm.PrecompiledContracts; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class BridgeSupportRejectedPeginTest { + + private static final BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); + private static final FederationConstants federationMainnetConstants = bridgeMainnetConstants.getFederationConstants(); + private static final NetworkParameters btcMainnetParams = bridgeMainnetConstants.getBtcParams(); + private static final ActivationConfig.ForBlock arrowHeadActivations = ActivationConfigsForTest.arrowhead600().forBlock(0); + private static final ActivationConfig.ForBlock lovellActivations = ActivationConfigsForTest.lovell700().forBlock(0); + /*private static final ActivationConfig.ForBlock activations = ActivationConfigsForTest.all().forBlock(0);*/ + + private static final Coin minimumPeginTxValue = bridgeMainnetConstants.getMinimumPeginTxValue( + ActivationConfigsForTest.all().forBlock(0)); + private static final Coin belowMinimumPeginTxValue = minimumPeginTxValue.minus(Coin.SATOSHI); + + private static final int FIRST_OUTPUT_INDEX = 0; + + private Repository repository; + private BridgeStorageProvider provider; + private FederationStorageProvider federationStorageProvider; + + private Address userAddress; + + private Federation activeFederation; + private Federation retiringFederation; + + private BtcBlockStoreWithCache.Factory mockFactory; + private BridgeEventLogger bridgeEventLogger; + private BtcLockSenderProvider btcLockSenderProvider; + private PeginInstructionsProvider peginInstructionsProvider; + + private final List retiringFederationUtxos = new ArrayList<>(); + private final List activeFederationUtxos = new ArrayList<>(); + private PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations; + private Block rskExecutionBlock; + private Transaction rskTx; + + private int heightAtWhichToStartUsingPegoutIndex; + + private co.rsk.bitcoinj.core.BtcBlock registerHeader; + + public static Stream activationsProvider() { + return Stream.of( + Arguments.of(lovellActivations), + Arguments.of(arrowHeadActivations) + ); + } + + @BeforeEach + void init() throws IOException { + registerHeader = null; + + userAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userAddress"); + NetworkParameters btcParams = bridgeMainnetConstants.getBtcParams(); + + + List erpPubKeys = federationMainnetConstants.getErpFedPubKeysList(); + long activationDelay = federationMainnetConstants.getErpFedActivationDelay(); + + List retiringFedSigners = BitcoinTestUtils.getBtcEcKeysFromSeeds( + new String[]{"fa04", "fa05", "fa06"}, true + ); + retiringFedSigners.sort(BtcECKey.PUBKEY_COMPARATOR); + List retiringFedMembers = FederationTestUtils.getFederationMembersWithBtcKeys(retiringFedSigners); + Instant retiringCreationTime = Instant.ofEpochMilli(1000L); + long retiringFedCreationBlockNumber = 1; + + FederationArgs retiringFedArgs = + new FederationArgs(retiringFedMembers, retiringCreationTime, retiringFedCreationBlockNumber, btcParams); + retiringFederation = FederationFactory.buildP2shErpFederation(retiringFedArgs, erpPubKeys, activationDelay); + + List activeFedSigners = BitcoinTestUtils.getBtcEcKeysFromSeeds( + new String[]{"fa07", "fa08", "fa09", "fa10", "fa11"}, true + ); + activeFedSigners.sort(BtcECKey.PUBKEY_COMPARATOR); + List activeFedMembers = FederationTestUtils.getFederationMembersWithBtcKeys( + activeFedSigners); + long activeFedCreationBlockNumber = 2L; + Instant creationTime = Instant.ofEpochMilli(1000L); + FederationArgs activeFedArgs = + new FederationArgs(activeFedMembers, creationTime, activeFedCreationBlockNumber, + btcParams); + activeFederation = FederationFactory.buildP2shErpFederation(activeFedArgs, erpPubKeys, + activationDelay); + + mockFactory = mock(BtcBlockStoreWithCache.Factory.class); + + bridgeEventLogger = mock(BridgeEventLogger.class); + btcLockSenderProvider = new BtcLockSenderProvider(); + + peginInstructionsProvider = new PeginInstructionsProvider(); + + provider = mock(BridgeStorageProvider.class); + when(provider.getHeightIfBtcTxhashIsAlreadyProcessed(any(Sha256Hash.class))).thenReturn( + Optional.empty()); + + repository = mock(Repository.class); + when(repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)).thenReturn( + co.rsk.core.Coin.fromBitcoin(bridgeMainnetConstants.getMaxRbtc())); + LockingCapSupport lockingCapSupport = mock(LockingCapSupport.class); + when(lockingCapSupport.getLockingCap()).thenReturn( + Optional.of(bridgeMainnetConstants.getMaxRbtc())); + + federationStorageProvider = mock(FederationStorageProvider.class); + when(federationStorageProvider.getOldFederationBtcUTXOs()) + .thenReturn(retiringFederationUtxos); + when(federationStorageProvider.getNewFederationBtcUTXOs(any(NetworkParameters.class), + any(ActivationConfig.ForBlock.class))) + .thenReturn(activeFederationUtxos); + + pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn( + pegoutsWaitingForConfirmations); + + when(federationStorageProvider.getNewFederation(any(FederationConstants.class), + any(ActivationConfig.ForBlock.class))) + .thenReturn(activeFederation); + + // Set execution block right after the fed creation block + long executionBlockNumber = activeFederation.getCreationBlockNumber() + 1; + rskExecutionBlock = mock(Block.class); + + when(rskExecutionBlock.getNumber()).thenReturn(executionBlockNumber); + + rskTx = mock(Transaction.class); + when(rskTx.getHash()).thenReturn(PegTestUtils.createHash3(1)); + + int btcHeightWhenPegoutTxIndexActivates = bridgeMainnetConstants.getBtcHeightWhenPegoutTxIndexActivates(); + int pegoutTxIndexGracePeriodInBtcBlocks = bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); + + heightAtWhichToStartUsingPegoutIndex = + btcHeightWhenPegoutTxIndexActivates + pegoutTxIndexGracePeriodInBtcBlocks; + } + + private PartialMerkleTree createPmtAndMockBlockStore(BtcTransaction btcTransaction) + throws BlockStoreException { + PartialMerkleTree pmt = new PartialMerkleTree(btcMainnetParams, new byte[]{0x3f}, + Collections.singletonList(btcTransaction.getHash()), 1); + Sha256Hash blockMerkleRoot = pmt.getTxnHashAndMerkleRoot(new ArrayList<>()); + + registerHeader = new co.rsk.bitcoinj.core.BtcBlock( + btcMainnetParams, + 1, + BitcoinTestUtils.createHash(1), + blockMerkleRoot, + 1, + 1, + 1, + new ArrayList<>() + ); + + StoredBlock block = new StoredBlock(registerHeader, new BigInteger("0"), + heightAtWhichToStartUsingPegoutIndex); + + BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); + + co.rsk.bitcoinj.core.BtcBlock headBlock = new co.rsk.bitcoinj.core.BtcBlock( + btcMainnetParams, + 1, + BitcoinTestUtils.createHash(2), + Sha256Hash.of(new byte[]{1}), + 1, + 1, + 1, + new ArrayList<>() + ); + + StoredBlock chainHead = new StoredBlock(headBlock, new BigInteger("0"), + heightAtWhichToStartUsingPegoutIndex + + bridgeMainnetConstants.getBtc2RskMinimumAcceptableConfirmations()); + when(btcBlockStore.getChainHead()).thenReturn(chainHead); + + when(btcBlockStore.getStoredBlockAtMainChainHeight(block.getHeight())).thenReturn(block); + when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); + + co.rsk.bitcoinj.core.BtcBlock btcBlock = new co.rsk.bitcoinj.core.BtcBlock( + btcMainnetParams, + 1, + BitcoinTestUtils.createHash(1), + blockMerkleRoot, + 1, + 1, + 1, + new ArrayList<>() + ); + + mockChainOfStoredBlocks( + btcBlockStore, + btcBlock, + heightAtWhichToStartUsingPegoutIndex + + bridgeMainnetConstants.getBtc2RskMinimumAcceptableConfirmations(), + heightAtWhichToStartUsingPegoutIndex + ); + return pmt; + } + + @ParameterizedTest + @MethodSource("activationsProvider") + void registerBtcTransaction_whenBelowTheMinimum_shouldRejectPegin(ActivationConfig.ForBlock activations) + throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); + btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + btcTransaction.addOutput(belowMinimumPeginTxValue, activeFederation.getAddress()); + + FederationSupport federationSupport = FederationSupportBuilder.builder() + .withFederationConstants(federationMainnetConstants) + .withFederationStorageProvider(federationStorageProvider) + .withActivations(activations) + .withRskExecutionBlock(rskExecutionBlock) + .build(); + + BridgeSupport bridgeSupport = BridgeSupportBuilder.builder() + .withBtcBlockStoreFactory(mockFactory) + .withBridgeConstants(bridgeMainnetConstants) + .withRepository(repository) + .withProvider(provider) + .withActivations(activations) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withExecutionBlock(rskExecutionBlock) + .withFederationSupport(federationSupport) + .build(); + + // act + bridgeSupport.registerBtcTransaction( + rskTx, + btcTransaction.bitcoinSerialize(), + heightAtWhichToStartUsingPegoutIndex, + createPmtAndMockBlockStore(btcTransaction).bitcoinSerialize() + ); + + // assert + + // tx should be marked as processed since RSKIP459 is active + var shouldMarkTxAsProcessed = activations == lovellActivations? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + + verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, INVALID_AMOUNT); + verify(bridgeEventLogger, times(1)).logUnrefundablePegin(btcTransaction, + UnrefundablePeginReason.INVALID_AMOUNT); + verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); + } + + @ParameterizedTest + @MethodSource("activationsProvider") + void registerBtcTransaction_whenUndeterminedSender_shouldRejectPegin(ActivationConfig.ForBlock activations) + throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + btcLockSenderProvider = mock(BtcLockSenderProvider.class); + // return empty to simulate undetermined sender + when(btcLockSenderProvider.tryGetBtcLockSender(any())).thenReturn(Optional.empty()); + + Coin amountToSend = Coin.COIN; + BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); + btcTransaction.addInput( + BitcoinTestUtils.createHash(1), + FIRST_OUTPUT_INDEX, + new Script(new byte[]{}) + ); + btcTransaction.addOutput(amountToSend, activeFederation.getAddress()); + + FederationSupport federationSupport = FederationSupportBuilder.builder() + .withFederationConstants(federationMainnetConstants) + .withFederationStorageProvider(federationStorageProvider) + .withActivations(activations) + .withRskExecutionBlock(rskExecutionBlock) + .build(); + + BridgeSupport bridgeSupport = BridgeSupportBuilder.builder() + .withBtcBlockStoreFactory(mockFactory) + .withBridgeConstants(bridgeMainnetConstants) + .withRepository(repository) + .withProvider(provider) + .withActivations(activations) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withExecutionBlock(rskExecutionBlock) + .withFederationSupport(federationSupport) + .build(); + + // act + bridgeSupport.registerBtcTransaction( + rskTx, + btcTransaction.bitcoinSerialize(), + heightAtWhichToStartUsingPegoutIndex, + createPmtAndMockBlockStore(btcTransaction).bitcoinSerialize() + ); + + // assert + verify(bridgeEventLogger, times(1)).logRejectedPegin( + btcTransaction, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER + ); + verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + btcTransaction, + LEGACY_PEGIN_UNDETERMINED_SENDER + ); + + verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); + verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); + + // tx should be marked as processed since RSKIP459 is active + var shouldMarkTxAsProcessed = activations == lovellActivations? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + + Assertions.assertTrue(activeFederationUtxos.isEmpty()); + Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + Assertions.assertTrue(pegoutsWaitingForConfirmations.getEntries().isEmpty()); + } + + @ParameterizedTest + @MethodSource("activationsProvider") + void registerBtcTransaction_whenPeginV1WithInvalidPayloadAndUnderminedSender_shouldRejectPegin(ActivationConfig.ForBlock activations) + throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + btcLockSenderProvider = mock(BtcLockSenderProvider.class); + // return empty to simulate undetermined sender + when(btcLockSenderProvider.tryGetBtcLockSender(any())).thenReturn(Optional.empty()); + + BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); + btcTransaction.addInput( + BitcoinTestUtils.createHash(1), + FIRST_OUTPUT_INDEX, + new Script(new byte[]{}) + ); + btcTransaction.addOutput(Coin.COIN, activeFederation.getAddress()); + btcTransaction.addOutput(Coin.ZERO, PegTestUtils.createOpReturnScriptForRskWithCustomPayload(1, new byte[]{})); + + FederationSupport federationSupport = FederationSupportBuilder.builder() + .withFederationConstants(federationMainnetConstants) + .withFederationStorageProvider(federationStorageProvider) + .withActivations(activations) + .withRskExecutionBlock(rskExecutionBlock) + .build(); + + BridgeSupport bridgeSupport = BridgeSupportBuilder.builder() + .withBtcBlockStoreFactory(mockFactory) + .withBridgeConstants(bridgeMainnetConstants) + .withRepository(repository) + .withProvider(provider) + .withActivations(activations) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withExecutionBlock(rskExecutionBlock) + .withFederationSupport(federationSupport) + .build(); + + // act + bridgeSupport.registerBtcTransaction( + rskTx, + btcTransaction.bitcoinSerialize(), + heightAtWhichToStartUsingPegoutIndex, + createPmtAndMockBlockStore(btcTransaction).bitcoinSerialize() + ); + + // assert + + // tx should be marked as processed since RSKIP459 is active + var shouldMarkTxAsProcessed = activations == lovellActivations? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + + verify(bridgeEventLogger, times(1)).logRejectedPegin( + btcTransaction, PEGIN_V1_INVALID_PAYLOAD + ); + verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + btcTransaction, + LEGACY_PEGIN_UNDETERMINED_SENDER + ); + + verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); + verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); + verify(bridgeEventLogger, never()).logPegoutTransactionCreated(any(), any()); + + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(pegoutsWaitingForConfirmations.getEntries().isEmpty()); + } + + @ParameterizedTest + @MethodSource("activationsProvider") + void registerBtcTransaction_whenUtxoToActiveFedBelowMinimumAndUtxoToRetiringFedAboveMinimum_shouldRejectPegin( + ActivationConfig.ForBlock activations + ) throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); + btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + btcTransaction.addOutput(belowMinimumPeginTxValue, activeFederation.getAddress()); + btcTransaction.addOutput(minimumPeginTxValue, retiringFederation.getAddress()); + + when(federationStorageProvider.getOldFederation(federationMainnetConstants, activations)).thenReturn(retiringFederation); + FederationSupport federationSupport = FederationSupportBuilder.builder() + .withFederationConstants(federationMainnetConstants) + .withFederationStorageProvider(federationStorageProvider) + .withActivations(activations) + .withRskExecutionBlock(rskExecutionBlock) + .build(); + + BridgeSupport bridgeSupport = BridgeSupportBuilder.builder() + .withBtcBlockStoreFactory(mockFactory) + .withBridgeConstants(bridgeMainnetConstants) + .withRepository(repository) + .withProvider(provider) + .withActivations(activations) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withExecutionBlock(rskExecutionBlock) + .withFederationSupport(federationSupport) + .build(); + + // act + bridgeSupport.registerBtcTransaction( + rskTx, + btcTransaction.bitcoinSerialize(), + heightAtWhichToStartUsingPegoutIndex, + createPmtAndMockBlockStore(btcTransaction).bitcoinSerialize() + ); + + // assert + var shouldMarkTxAsProcessed = activations == lovellActivations? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + + verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); + verify(bridgeEventLogger, times(1)).logUnrefundablePegin(btcTransaction, + UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); + verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); + } + + // flyover pegin + @ParameterizedTest + @MethodSource("activationsProvider") + void registerBtcTransaction_whenAttemptToRegisterFlyoverPegin_shouldIgnorePegin(ActivationConfig.ForBlock activations) + throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, + "userRefundBtcAddress"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, + "lpBtcAddress"); + Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); + RskAddress lbcAddress = PegTestUtils.createRandomRskAddress(); + + FederationSupport federationSupport = FederationSupportBuilder.builder() + .withFederationConstants(federationMainnetConstants) + .withFederationStorageProvider(federationStorageProvider) + .withActivations(activations) + .withRskExecutionBlock(rskExecutionBlock) + .build(); + + BridgeSupport bridgeSupport = BridgeSupportBuilder.builder() + .withBtcBlockStoreFactory(mockFactory) + .withBridgeConstants(bridgeMainnetConstants) + .withRepository(repository) + .withProvider(provider) + .withActivations(activations) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withExecutionBlock(rskExecutionBlock) + .withFederationSupport(federationSupport) + .build(); + + Keccak256 flyoverDerivationHash = bridgeSupport.getFlyoverDerivationHash( + derivationArgumentsHash, + userRefundBtcAddress, + lpBtcAddress, + lbcAddress + ); + + Address flyoverFederationAddress = PegTestUtils.getFlyoverAddressFromRedeemScript( + bridgeMainnetConstants, + activeFederation.getRedeemScript(), + Sha256Hash.wrap(flyoverDerivationHash.getBytes()) + ); + + BtcTransaction btcTransaction = new BtcTransaction(bridgeMainnetConstants.getBtcParams()); + btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + btcTransaction.addOutput(minimumPeginTxValue, flyoverFederationAddress); + + // act + bridgeSupport.registerBtcTransaction( + rskTx, + btcTransaction.bitcoinSerialize(), + heightAtWhichToStartUsingPegoutIndex, + createPmtAndMockBlockStore(btcTransaction).bitcoinSerialize() + ); + + assertUnknownTxIsIgnored(); + } + + private void assertUnknownTxIsIgnored() throws IOException { + verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); + verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); + verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); + } + + @ParameterizedTest + @MethodSource("activationsProvider") + void registerBtcTransaction_whenNoUtxoToFed_shouldIgnorePegin(ActivationConfig.ForBlock activations) + throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); + btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + btcTransaction.addOutput(minimumPeginTxValue, userAddress); + + FederationSupport federationSupport = FederationSupportBuilder.builder() + .withFederationConstants(federationMainnetConstants) + .withFederationStorageProvider(federationStorageProvider) + .withActivations(activations) + .withRskExecutionBlock(rskExecutionBlock) + .build(); + + BridgeSupport bridgeSupport = BridgeSupportBuilder.builder() + .withBtcBlockStoreFactory(mockFactory) + .withBridgeConstants(bridgeMainnetConstants) + .withRepository(repository) + .withProvider(provider) + .withActivations(activations) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withExecutionBlock(rskExecutionBlock) + .withFederationSupport(federationSupport) + .build(); + + // act + bridgeSupport.registerBtcTransaction( + rskTx, + btcTransaction.bitcoinSerialize(), + heightAtWhichToStartUsingPegoutIndex, + createPmtAndMockBlockStore(btcTransaction).bitcoinSerialize() + ); + + // assert + assertUnknownTxIsIgnored(); + } +} diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java index 3b47a96f485..4be1f7a365c 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -9,6 +9,7 @@ import static co.rsk.peg.bitcoin.BitcoinUtils.*; import static co.rsk.peg.bitcoin.UtxoUtils.extractOutpointValues; import static co.rsk.peg.federation.FederationStorageIndexKey.NEW_FEDERATION_BTC_UTXOS_KEY; +import static co.rsk.peg.pegin.RejectedPeginReason.INVALID_AMOUNT; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -30,6 +31,7 @@ import co.rsk.peg.storage.StorageAccessor; import co.rsk.peg.utils.BridgeEventLogger; import co.rsk.peg.utils.BridgeEventLoggerImpl; +import co.rsk.peg.utils.UnrefundablePeginReason; import co.rsk.test.builders.BridgeSupportBuilder; import co.rsk.test.builders.FederationSupportBuilder; import java.io.IOException; @@ -38,6 +40,7 @@ import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.ethereum.core.*; +import org.ethereum.core.CallTransaction.Function; import org.ethereum.crypto.ECKey; import org.ethereum.util.ByteUtil; import org.ethereum.vm.DataWord; @@ -1046,8 +1049,14 @@ void registerBtcTransaction_whenIsNotTheSpendTransaction_shouldNotProcessSpendTx assertProposedFederationExists(); } + /* + This is a hypothetical case, which is not realistic with the implementation of the svp. + A btc tx hash that is not saved as a spend tx, is identified as a pegin, and will be + rejected due to invalid amount. This is because the pegin amount is below the minimum. + Therefore, this tx should be rejected as pegin and mark as processed + */ @Test - void registerBtcTransaction_whenSpendTransactionHashIsNotSaved_shouldNotProcessSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_whenSpendTransactionHashIsNotSaved_shouldBeIdentifiedAsRejectedPeginAndMarkAsProcessed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange recreateSvpSpendTransactionUnsigned(); setUpForTransactionRegistration(svpSpendTransaction); @@ -1066,7 +1075,8 @@ void registerBtcTransaction_whenSpendTransactionHashIsNotSaved_shouldNotProcessS // assert // spend tx was not registered assertActiveFederationUtxosSize(activeFederationUtxosSizeBeforeRegisteringTx); - assertTransactionWasNotProcessed(svpSpendTransaction.getHash()); + + assertTxIsRejectedPeginAndMarkedAsProcessed(svpSpendTransaction); // svp success was not processed assertNoHandoverToNewFederation(); @@ -1431,6 +1441,28 @@ private void assertTransactionWasNotProcessed(Sha256Hash transactionHash) throws assertFalse(rskBlockHeightAtWhichBtcTxWasProcessed.isPresent()); } + private void assertTxIsRejectedPeginAndMarkedAsProcessed(BtcTransaction rejectedPegin) + throws IOException { + Optional rskBlockHeightAtWhichBtcTxWasProcessed = bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(rejectedPegin.getHash()); + assertTrue(rskBlockHeightAtWhichBtcTxWasProcessed.isPresent()); + + byte[] btcTxHashSerialized = rejectedPegin.getHash().getBytes(); + + Function rejectedPeginEvent = BridgeEvents.REJECTED_PEGIN.getEvent(); + List rejectedPeginEncodedTopics = getEncodedTopics(rejectedPeginEvent, btcTxHashSerialized); + byte[] rejectedPeginEncodedData = getEncodedData(rejectedPeginEvent, INVALID_AMOUNT.getValue()); + + assertEventWasEmittedWithExpectedTopics(rejectedPeginEncodedTopics); + assertEventWasEmittedWithExpectedData(rejectedPeginEncodedData); + + Function unrefundablePeginEvent = BridgeEvents.UNREFUNDABLE_PEGIN.getEvent(); + List encodedTopics = getEncodedTopics(unrefundablePeginEvent, btcTxHashSerialized); + byte[] encodedData = getEncodedData(unrefundablePeginEvent, UnrefundablePeginReason.INVALID_AMOUNT.getValue()); + + assertEventWasEmittedWithExpectedTopics(encodedTopics); + assertEventWasEmittedWithExpectedData(encodedData); + } + private void assertNoSvpFundTxHashUnsigned() { assertFalse(bridgeStorageProvider.getSvpFundTxHashUnsigned().isPresent()); } diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsEvaluatePeginTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsEvaluatePeginTest.java index e98cc53d924..2c68e61ab3b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsEvaluatePeginTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsEvaluatePeginTest.java @@ -54,7 +54,7 @@ private static Stream argumentsForWhenProtocolVersionLegacyIs0AndDiff Arguments.of(BtcLockSender.TxSenderAddressType.P2SHP2WPKH, PeginProcessAction.CAN_BE_REGISTERED, null), Arguments.of(BtcLockSender.TxSenderAddressType.P2SHMULTISIG, PeginProcessAction.CAN_BE_REFUNDED, RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER), Arguments.of(BtcLockSender.TxSenderAddressType.P2SHP2WSH, PeginProcessAction.CAN_BE_REFUNDED, RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER), - Arguments.of(BtcLockSender.TxSenderAddressType.UNKNOWN, PeginProcessAction.CANNOT_BE_PROCESSED, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER) + Arguments.of(BtcLockSender.TxSenderAddressType.UNKNOWN, PeginProcessAction.CANNOT_BE_REFUNDED, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER) ); } @@ -104,7 +104,7 @@ void evaluatePegin_valueBelowMinimum_returnsPeginEvaluationResultWithCannotBePro activations ); - assertEquals(PeginProcessAction.CANNOT_BE_PROCESSED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.CANNOT_BE_REFUNDED, peginEvaluationResult.getPeginProcessAction()); assertTrue(peginEvaluationResult.getRejectedPeginReason().isPresent()); assertEquals(RejectedPeginReason.INVALID_AMOUNT, peginEvaluationResult.getRejectedPeginReason().get()); } @@ -129,7 +129,7 @@ void evaluatePegin_btcRefundAddressNullAndDifferentProtocolVersions(int protocol activations ); - assertEquals(PeginProcessAction.CANNOT_BE_PROCESSED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.CANNOT_BE_REFUNDED, peginEvaluationResult.getPeginProcessAction()); assertTrue(peginEvaluationResult.getRejectedPeginReason().isPresent()); assertEquals(RejectedPeginReason.PEGIN_V1_INVALID_PAYLOAD, peginEvaluationResult.getRejectedPeginReason().get()); }