From f41a04e7be93eb6a6baf3bda2ffe22dc51d8e69a Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Thu, 19 Dec 2024 18:12:38 -0400 Subject: [PATCH 1/6] Added RSKIP459 activation code --- .../ethereum/config/blockchain/upgrades/ConsensusRule.java | 5 +++-- rskj-core/src/main/resources/expected.conf | 1 + rskj-core/src/main/resources/reference.conf | 1 + .../config/blockchain/upgrades/ActivationConfigTest.java | 1 + .../config/blockchain/upgrades/ActivationConfigsForTest.java | 3 ++- 5 files changed, 8 insertions(+), 3 deletions(-) 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 5a14eaa3d0..4667e5e546 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 @@ -101,9 +101,10 @@ public enum ConsensusRule { RSKIP434("rskip434"), RSKIP438("rskip438"), RSKIP445("rskip445"), // From EIP-5656 MCOPY instruction - RSKIP446("rskip446") ,// Transient storage opcodes addition implementing EIP-1153 + RSKIP446("rskip446"), // Transient storage opcodes addition implementing EIP-1153 RSKIP453("rskip453"), - RSKIP454("rskip454") + RSKIP454("rskip454"), + RSKIP459("rskip459"), ; private final String configKey; diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 8e88b97931..5710410f5e 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -105,6 +105,7 @@ blockchain = { rskip446 = rskip453 = rskip454 = + rskip459 = } } gc = { diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 511d906be9..f7f5d4bb8a 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -90,6 +90,7 @@ blockchain = { rskip446 = lovell700 rskip453 = lovell700 rskip454 = lovell700 + rskip459 = lovell700 } } gc = { 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 ecdd42f150..12f2d7c61a 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 @@ -131,6 +131,7 @@ class ActivationConfigTest { " rskip446: lovell700", " rskip453: lovell700", " rskip454: lovell700", + " rskip459: lovell700", "}" )); 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 e0dc663f34..399bb0b54b 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 @@ -180,7 +180,8 @@ private static List getLovell700Rskips() { ConsensusRule.RSKIP427, ConsensusRule.RSKIP428, ConsensusRule.RSKIP438, - ConsensusRule.RSKIP454 + ConsensusRule.RSKIP454, + ConsensusRule.RSKIP459 )); } From 974b254a45c23ba442701d6f4f17f1228947689f Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Fri, 20 Dec 2024 13:23:37 -0400 Subject: [PATCH 2/6] Mark rejected pegins as processed once RSKIP459 is active --- .../main/java/co/rsk/peg/BridgeSupport.java | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) 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 4508a55680..86372ffc62 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -504,28 +504,37 @@ 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); - } else { - 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); + switch (peginProcessAction) { + case CAN_BE_REGISTERED -> { + logger.debug("[{}] Peg-in is valid, going to register", METHOD_NAME); + executePegIn(btcTx, peginInformation, totalAmount); } - - RejectedPeginReason rejectedPeginReason = rejectedPeginReasonOptional.get(); - logger.debug("[{}] Rejected peg-in, reason {}", METHOD_NAME, rejectedPeginReason); - eventLogger.logRejectedPegin(btcTx, rejectedPeginReason); - if (peginProcessAction == PeginProcessAction.CAN_BE_REFUNDED) { - logger.debug("[{}] Refunding to address {} ", METHOD_NAME, peginInformation.getBtcRefundAddress()); - generateRejectionRelease(btcTx, peginInformation.getBtcRefundAddress(), rskTxHash, totalAmount); + case CAN_BE_REFUNDED -> { + logger.debug("[{}] Refunding to address {} ", METHOD_NAME, + peginInformation.getBtcRefundAddress()); + generateRejectionRelease(btcTx, peginInformation.getBtcRefundAddress(), rskTxHash, + totalAmount); markTxAsProcessed(btcTx); - } else { + } + 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); + handleUnprocessableBtcTx(btcTx, peginInformation.getProtocolVersion(), + rejectedPeginReason); + + // Since RSKIP459, rejected peg-ins should be marked as processed + if (activations.isActive(RSKIP459)) { + markTxAsProcessed(btcTx); + } } } } From 414b05183847ec1133dc74264639a247fbf55ad1 Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Tue, 31 Dec 2024 10:53:27 -0400 Subject: [PATCH 3/6] - 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 86372ffc62..8fec36f464 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -504,42 +504,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 6e25ba8051..afe6ef6862 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 57d451076d..5fc6708c07 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 aecb750544..d7d551fb88 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 0000000000..e4c3a6905e --- /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 3b47a96f48..4be1f7a365 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 e98cc53d92..2c68e61ab3 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()); } From d72d2c1dc29df0a056ee9cd918a2b37e7f3ef72e Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Tue, 7 Jan 2025 08:36:45 -0400 Subject: [PATCH 4/6] - Use new switch with arrow labels - Make logic handling rejected pegin functional using the Optional API - Fix formatting --- .../main/java/co/rsk/peg/BridgeSupport.java | 46 +++++----- ...idgeSupportRegisterBtcTransactionTest.java | 2 +- .../peg/BridgeSupportRejectedPeginTest.java | 83 ++++++++++++------- .../java/co/rsk/peg/BridgeSupportSvpTest.java | 2 +- 4 files changed, 79 insertions(+), 54 deletions(-) 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 8fec36f464..3a13365e90 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -505,40 +505,45 @@ protected void registerPegIn( PeginProcessAction peginProcessAction = peginEvaluationResult.getPeginProcessAction(); - if (peginProcessAction == PeginProcessAction.CAN_BE_REGISTERED){ + 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); + RejectedPeginReason rejectedPeginReason = peginEvaluationResult.getRejectedPeginReason() + .map(reason -> { + logger.debug("[{}] Rejected peg-in, reason {}", METHOD_NAME, reason); + eventLogger.logRejectedPegin(btcTx, reason); + return reason; + }).orElseThrow(() -> { + // 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); + return new IllegalStateException(message); + }); switch (peginProcessAction) { - 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); - break; - case CANNOT_BE_REFUNDED: + } + 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); + handleNonRefundablePegin(btcTx, peginInformation.getProtocolVersion(), + rejectedPeginReason); + + if (!activations.isActive(RSKIP459)) { + return; } - break; + + // Since RSKIP459, rejected peg-ins should be marked as processed + markTxAsProcessed(btcTx); + } } } @@ -556,7 +561,8 @@ private void handleNonRefundablePegin( UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; } - logger.debug("[handleUnprocessableBtcTx] Unprocessable tx {}. Reason {}", btcTx.getHash(), unrefundablePeginReason); + logger.debug("[handleNonRefundablePegin] Nonrefundable tx {}. Reason {}", btcTx.getHash(), + unrefundablePeginReason); eventLogger.logUnrefundablePegin(btcTx, unrefundablePeginReason); } 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 d7d551fb88..e72a8ebe7c 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -1555,7 +1555,7 @@ void pegin_legacy_from_segwit_to_active_fed_cannot_be_processed( ); // assert - if (activations == fingerrootActivations){ + if (activations == fingerrootActivations) { // BEFORE RSKIP379 REJECTED PEGIN WERE MARKED AS PROCESSED. assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloadBeforeRSKIP379(btcTransaction); } else { diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java index e4c3a6905e..ada0dd0746 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java @@ -1,5 +1,6 @@ package co.rsk.peg; +import static co.rsk.peg.BridgeSupportTestUtil.createValidPmtForTransactions; 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; @@ -40,7 +41,6 @@ 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; @@ -64,7 +64,6 @@ 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; @@ -74,9 +73,10 @@ 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 ActivationConfig.ForBlock arrowHeadActivations = ActivationConfigsForTest.arrowhead600() + .forBlock(0); + private static final ActivationConfig.ForBlock lovellActivations = ActivationConfigsForTest.lovell700() + .forBlock(0); private static final Coin minimumPeginTxValue = bridgeMainnetConstants.getMinimumPeginTxValue( ActivationConfigsForTest.all().forBlock(0)); @@ -122,7 +122,6 @@ void init() throws IOException { userAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userAddress"); NetworkParameters btcParams = bridgeMainnetConstants.getBtcParams(); - List erpPubKeys = federationMainnetConstants.getErpFedPubKeysList(); long activationDelay = federationMainnetConstants.getErpFedActivationDelay(); @@ -130,13 +129,16 @@ void init() throws IOException { new String[]{"fa04", "fa05", "fa06"}, true ); retiringFedSigners.sort(BtcECKey.PUBKEY_COMPARATOR); - List retiringFedMembers = FederationTestUtils.getFederationMembersWithBtcKeys(retiringFedSigners); + 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); + new FederationArgs(retiringFedMembers, retiringCreationTime, + retiringFedCreationBlockNumber, btcParams); + retiringFederation = FederationFactory.buildP2shErpFederation(retiringFedArgs, erpPubKeys, + activationDelay); List activeFedSigners = BitcoinTestUtils.getBtcEcKeysFromSeeds( new String[]{"fa07", "fa08", "fa09", "fa10", "fa11"}, true @@ -203,10 +205,11 @@ void init() throws IOException { 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<>()); + PartialMerkleTree pmt = createValidPmtForTransactions( + Collections.singletonList(btcTransaction.getHash()), btcMainnetParams); + + Sha256Hash blockMerkleRoot = pmt.getTxnHashAndMerkleRoot(new ArrayList<>()); registerHeader = new co.rsk.bitcoinj.core.BtcBlock( btcMainnetParams, 1, @@ -265,11 +268,13 @@ private PartialMerkleTree createPmtAndMockBlockStore(BtcTransaction btcTransacti @ParameterizedTest @MethodSource("activationsProvider") - void registerBtcTransaction_whenBelowTheMinimum_shouldRejectPegin(ActivationConfig.ForBlock activations) + 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.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, + new Script(new byte[]{})); btcTransaction.addOutput(belowMinimumPeginTxValue, activeFederation.getAddress()); FederationSupport federationSupport = FederationSupportBuilder.builder() @@ -303,8 +308,9 @@ void registerBtcTransaction_whenBelowTheMinimum_shouldRejectPegin(ActivationConf // assert // tx should be marked as processed since RSKIP459 is active - var shouldMarkTxAsProcessed = activations == lovellActivations? times(1) : never(); - verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + 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, @@ -316,7 +322,8 @@ void registerBtcTransaction_whenBelowTheMinimum_shouldRejectPegin(ActivationConf @ParameterizedTest @MethodSource("activationsProvider") - void registerBtcTransaction_whenUndeterminedSender_shouldRejectPegin(ActivationConfig.ForBlock activations) + void registerBtcTransaction_whenUndeterminedSender_shouldRejectPegin( + ActivationConfig.ForBlock activations) throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange btcLockSenderProvider = mock(BtcLockSenderProvider.class); @@ -373,8 +380,9 @@ void registerBtcTransaction_whenUndeterminedSender_shouldRejectPegin(ActivationC 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()); + var shouldMarkTxAsProcessed = activations == lovellActivations ? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), + anyLong()); Assertions.assertTrue(activeFederationUtxos.isEmpty()); Assertions.assertTrue(retiringFederationUtxos.isEmpty()); @@ -383,7 +391,8 @@ void registerBtcTransaction_whenUndeterminedSender_shouldRejectPegin(ActivationC @ParameterizedTest @MethodSource("activationsProvider") - void registerBtcTransaction_whenPeginV1WithInvalidPayloadAndUnderminedSender_shouldRejectPegin(ActivationConfig.ForBlock activations) + void registerBtcTransaction_whenPeginV1WithInvalidPayloadAndUnderminedSender_shouldRejectPegin( + ActivationConfig.ForBlock activations) throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange btcLockSenderProvider = mock(BtcLockSenderProvider.class); @@ -397,7 +406,8 @@ void registerBtcTransaction_whenPeginV1WithInvalidPayloadAndUnderminedSender_sho new Script(new byte[]{}) ); btcTransaction.addOutput(Coin.COIN, activeFederation.getAddress()); - btcTransaction.addOutput(Coin.ZERO, PegTestUtils.createOpReturnScriptForRskWithCustomPayload(1, new byte[]{})); + btcTransaction.addOutput(Coin.ZERO, + PegTestUtils.createOpReturnScriptForRskWithCustomPayload(1, new byte[]{})); FederationSupport federationSupport = FederationSupportBuilder.builder() .withFederationConstants(federationMainnetConstants) @@ -430,8 +440,9 @@ void registerBtcTransaction_whenPeginV1WithInvalidPayloadAndUnderminedSender_sho // assert // tx should be marked as processed since RSKIP459 is active - var shouldMarkTxAsProcessed = activations == lovellActivations? times(1) : never(); - verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + var shouldMarkTxAsProcessed = activations == lovellActivations ? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), + anyLong()); verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, PEGIN_V1_INVALID_PAYLOAD @@ -457,11 +468,13 @@ void registerBtcTransaction_whenUtxoToActiveFedBelowMinimumAndUtxoToRetiringFedA ) throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); - btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + 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); + when(federationStorageProvider.getOldFederation(federationMainnetConstants, + activations)).thenReturn(retiringFederation); FederationSupport federationSupport = FederationSupportBuilder.builder() .withFederationConstants(federationMainnetConstants) .withFederationStorageProvider(federationStorageProvider) @@ -491,10 +504,12 @@ void registerBtcTransaction_whenUtxoToActiveFedBelowMinimumAndUtxoToRetiringFedA ); // assert - var shouldMarkTxAsProcessed = activations == lovellActivations? times(1) : never(); - verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + 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)).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()); @@ -505,7 +520,8 @@ void registerBtcTransaction_whenUtxoToActiveFedBelowMinimumAndUtxoToRetiringFedA // flyover pegin @ParameterizedTest @MethodSource("activationsProvider") - void registerBtcTransaction_whenAttemptToRegisterFlyoverPegin_shouldIgnorePegin(ActivationConfig.ForBlock activations) + void registerBtcTransaction_whenAttemptToRegisterFlyoverPegin_shouldIgnorePegin( + ActivationConfig.ForBlock activations) throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, @@ -549,7 +565,8 @@ void registerBtcTransaction_whenAttemptToRegisterFlyoverPegin_shouldIgnorePegin( ); BtcTransaction btcTransaction = new BtcTransaction(bridgeMainnetConstants.getBtcParams()); - btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, + new Script(new byte[]{})); btcTransaction.addOutput(minimumPeginTxValue, flyoverFederationAddress); // act @@ -574,11 +591,13 @@ private void assertUnknownTxIsIgnored() throws IOException { @ParameterizedTest @MethodSource("activationsProvider") - void registerBtcTransaction_whenNoUtxoToFed_shouldIgnorePegin(ActivationConfig.ForBlock activations) + 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.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, + new Script(new byte[]{})); btcTransaction.addOutput(minimumPeginTxValue, userAddress); FederationSupport federationSupport = FederationSupportBuilder.builder() 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 4be1f7a365..630d8a3ed9 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -1052,7 +1052,7 @@ void registerBtcTransaction_whenIsNotTheSpendTransaction_shouldNotProcessSpendTx /* 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. + rejected due to invalid amount, since the pegin amount is below the minimum. Therefore, this tx should be rejected as pegin and mark as processed */ @Test From 659c821e64f7a51b7e449ce06fcea5081a238c83 Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Tue, 7 Jan 2025 10:23:53 -0400 Subject: [PATCH 5/6] Improve switch use to handle pegins --- .../main/java/co/rsk/peg/BridgeSupport.java | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) 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 3a13365e90..9b9f58bd28 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -505,27 +505,15 @@ 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 - RejectedPeginReason rejectedPeginReason = peginEvaluationResult.getRejectedPeginReason() - .map(reason -> { - logger.debug("[{}] Rejected peg-in, reason {}", METHOD_NAME, reason); - eventLogger.logRejectedPegin(btcTx, reason); - return reason; - }).orElseThrow(() -> { - // 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); - return new IllegalStateException(message); - }); - 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 -> { + // If the peg-in cannot be registered means it should be rejected + handleRejectedPegin(btcTx, + peginEvaluationResult); logger.debug("[{}] Refunding to address {} ", METHOD_NAME, peginInformation.getBtcRefundAddress()); generateRejectionRelease(btcTx, peginInformation.getBtcRefundAddress(), rskTxHash, @@ -533,20 +521,36 @@ protected void registerPegIn( markTxAsProcessed(btcTx); } case CANNOT_BE_REFUNDED -> { - logger.debug("[{}] Nonrefundable transaction {}.", METHOD_NAME, btcTx.getHash()); + // If the peg-in cannot be registered means it should be rejected + RejectedPeginReason rejectedPeginReason = handleRejectedPegin(btcTx, + peginEvaluationResult); + handleNonRefundablePegin(btcTx, peginInformation.getProtocolVersion(), rejectedPeginReason); if (!activations.isActive(RSKIP459)) { return; } - // Since RSKIP459, rejected peg-ins should be marked as processed markTxAsProcessed(btcTx); } } } + private RejectedPeginReason handleRejectedPegin(BtcTransaction btcTx, + PeginEvaluationResult peginEvaluationResult) { + return peginEvaluationResult.getRejectedPeginReason().map(reason -> { + logger.debug("[{handleRejectedPegin}] Rejected peg-in, reason {}", reason); + eventLogger.logRejectedPegin(btcTx, reason); + return reason; + }).orElseThrow(() -> { + // 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("[{handleRejectedPegin}] {}", message); + return new IllegalStateException(message); + }); + } + private void handleNonRefundablePegin( BtcTransaction btcTx, int protocolVersion, From 7b48c6472a7ecb1b997512236d2009b4a123e3c4 Mon Sep 17 00:00:00 2001 From: nathanieliov Date: Thu, 9 Jan 2025 00:09:18 -0400 Subject: [PATCH 6/6] - Rename UnrefundablePeginReason to NonRefundablePeginReason - Enhance switch for processing each PeginProcessAction --- .../main/java/co/rsk/peg/BridgeSupport.java | 107 +++++++++--------- .../src/main/java/co/rsk/peg/PegUtils.java | 14 +-- .../co/rsk/peg/pegin/PeginProcessAction.java | 6 +- .../co/rsk/peg/utils/BridgeEventLogger.java | 2 +- .../rsk/peg/utils/BridgeEventLoggerImpl.java | 2 +- ...son.java => NonRefundablePeginReason.java} | 4 +- ...idgeSupportRegisterBtcTransactionTest.java | 52 ++++----- .../peg/BridgeSupportRejectedPeginTest.java | 30 ++--- .../java/co/rsk/peg/BridgeSupportSvpTest.java | 4 +- .../java/co/rsk/peg/BridgeSupportTest.java | 8 +- .../co/rsk/peg/PegUtilsEvaluatePeginTest.java | 22 ++-- .../peg/utils/BridgeEventLoggerImplTest.java | 6 +- .../rsk/peg/utils/BridgeEventLoggerTest.java | 6 +- 13 files changed, 134 insertions(+), 129 deletions(-) rename rskj-core/src/main/java/co/rsk/peg/utils/{UnrefundablePeginReason.java => NonRefundablePeginReason.java} (75%) 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 9b9f58bd28..a2241c3416 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -23,7 +23,6 @@ import static co.rsk.peg.ReleaseTransactionBuilder.BTC_TX_VERSION_2; import static co.rsk.peg.bitcoin.BitcoinUtils.*; import static co.rsk.peg.bitcoin.UtxoUtils.extractOutpointValues; -import static co.rsk.peg.pegin.RejectedPeginReason.INVALID_AMOUNT; import static java.util.Objects.isNull; import static org.ethereum.config.blockchain.upgrades.ConsensusRule.*; @@ -506,68 +505,72 @@ protected void registerPegIn( PeginProcessAction peginProcessAction = peginEvaluationResult.getPeginProcessAction(); switch (peginProcessAction) { - case CAN_BE_REGISTERED -> { + case REGISTER -> { logger.debug("[{}] Peg-in is valid, going to register", METHOD_NAME); executePegIn(btcTx, peginInformation, totalAmount); } - case CAN_BE_REFUNDED -> { - // If the peg-in cannot be registered means it should be rejected - handleRejectedPegin(btcTx, - peginEvaluationResult); - logger.debug("[{}] Refunding to address {} ", METHOD_NAME, - peginInformation.getBtcRefundAddress()); - generateRejectionRelease(btcTx, peginInformation.getBtcRefundAddress(), rskTxHash, - totalAmount); - markTxAsProcessed(btcTx); - } - case CANNOT_BE_REFUNDED -> { - // If the peg-in cannot be registered means it should be rejected - RejectedPeginReason rejectedPeginReason = handleRejectedPegin(btcTx, - peginEvaluationResult); - - handleNonRefundablePegin(btcTx, peginInformation.getProtocolVersion(), - rejectedPeginReason); - - if (!activations.isActive(RSKIP459)) { - return; - } - // Since RSKIP459, rejected peg-ins should be marked as processed - markTxAsProcessed(btcTx); - } + case REFUND -> handleRefundablePegin(btcTx, rskTxHash, peginEvaluationResult, + peginInformation.getBtcRefundAddress()); + case NO_REFUND -> handleNonRefundablePegin(btcTx, peginInformation.getProtocolVersion(), + peginEvaluationResult); } } - private RejectedPeginReason handleRejectedPegin(BtcTransaction btcTx, - PeginEvaluationResult peginEvaluationResult) { - return peginEvaluationResult.getRejectedPeginReason().map(reason -> { - logger.debug("[{handleRejectedPegin}] Rejected peg-in, reason {}", reason); - eventLogger.logRejectedPegin(btcTx, reason); - return reason; - }).orElseThrow(() -> { - // 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("[{handleRejectedPegin}] {}", message); - return new IllegalStateException(message); - }); + private void handleRefundablePegin(BtcTransaction btcTx, Keccak256 rskTxHash, + PeginEvaluationResult peginEvaluationResult, Address btcRefundAddress) + throws IOException { + RejectedPeginReason rejectedPeginReason = peginEvaluationResult.getRejectedPeginReason() + .orElseThrow(() -> { + // 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("[{handleRefundablePegin}] {}", message); + return new IllegalStateException(message); + }); + + logger.debug("[{handleRefundablePegin}] Rejected peg-in, reason {}", rejectedPeginReason); + eventLogger.logRejectedPegin(btcTx, rejectedPeginReason); + + logger.debug("[{handleRefundablePegin}] Refunding to address {} ", btcRefundAddress); + Coin totalAmount = computeTotalAmountSent(btcTx); + generateRejectionRelease(btcTx, btcRefundAddress, rskTxHash, + totalAmount); + markTxAsProcessed(btcTx); } private void handleNonRefundablePegin( BtcTransaction btcTx, int protocolVersion, - RejectedPeginReason rejectedPeginReason - ) { - UnrefundablePeginReason unrefundablePeginReason; - if (rejectedPeginReason == INVALID_AMOUNT) { - unrefundablePeginReason = UnrefundablePeginReason.INVALID_AMOUNT; - } else { - unrefundablePeginReason = protocolVersion == 1 ? - UnrefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET : - UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; - } + PeginEvaluationResult peginEvaluationResult + ) throws IOException { + RejectedPeginReason rejectedPeginReason = peginEvaluationResult.getRejectedPeginReason() + .orElseThrow(() -> { + // 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("[{handleNonRefundablePegin}] {}", message); + return new IllegalStateException(message); + }); + + logger.debug("[{handleNonRefundablePegin}] Rejected peg-in, reason {}", + rejectedPeginReason); + eventLogger.logRejectedPegin(btcTx, rejectedPeginReason); + + NonRefundablePeginReason nonRefundablePeginReason = switch (rejectedPeginReason) { + case INVALID_AMOUNT -> NonRefundablePeginReason.INVALID_AMOUNT; + case LEGACY_PEGIN_UNDETERMINED_SENDER, PEGIN_V1_INVALID_PAYLOAD -> + protocolVersion == 1 ? NonRefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET + : NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; + default -> throw new IllegalStateException("Unexpected value: " + rejectedPeginReason); + }; logger.debug("[handleNonRefundablePegin] Nonrefundable tx {}. Reason {}", btcTx.getHash(), - unrefundablePeginReason); - eventLogger.logUnrefundablePegin(btcTx, unrefundablePeginReason); + nonRefundablePeginReason); + eventLogger.logNonRefundablePegin(btcTx, nonRefundablePeginReason); + + if (!activations.isActive(RSKIP459)) { + return; + } + // Since RSKIP459, rejected peg-ins should be marked as processed + markTxAsProcessed(btcTx); } /** @@ -735,9 +738,9 @@ private void refundTxSender( if (activations.isActive(ConsensusRule.RSKIP181)) { if (peginInformation.getProtocolVersion() == 1) { - eventLogger.logUnrefundablePegin(btcTx, UnrefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET); + eventLogger.logNonRefundablePegin(btcTx, NonRefundablePeginReason.PEGIN_V1_REFUND_ADDRESS_NOT_SET); } else { - eventLogger.logUnrefundablePegin(btcTx, UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); + eventLogger.logNonRefundablePegin(btcTx, NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); } } } 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 afe6ef6862..e5140f21f4 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_REFUNDED, INVALID_AMOUNT); + return new PeginEvaluationResult(PeginProcessAction.NO_REFUND, INVALID_AMOUNT); } try { @@ -196,8 +196,8 @@ static PeginEvaluationResult evaluatePegin( boolean hasRefundAddress = peginInformation.getBtcRefundAddress() != null; PeginProcessAction peginProcessAction = hasRefundAddress ? - PeginProcessAction.CAN_BE_REFUNDED : - PeginProcessAction.CANNOT_BE_REFUNDED; + PeginProcessAction.REFUND : + PeginProcessAction.NO_REFUND; return new PeginEvaluationResult(peginProcessAction, PEGIN_V1_INVALID_PAYLOAD); } @@ -207,7 +207,7 @@ static PeginEvaluationResult evaluatePegin( case 0: return evaluateLegacyPeginSender(peginInformation.getSenderBtcAddressType()); case 1: - return new PeginEvaluationResult(PeginProcessAction.CAN_BE_REGISTERED); + return new PeginEvaluationResult(PeginProcessAction.REGISTER); default: // This flow should never be reached. String message = String.format("Invalid state. Unexpected pegin protocol %d", protocolVersion); @@ -220,12 +220,12 @@ private static PeginEvaluationResult evaluateLegacyPeginSender(TxSenderAddressTy switch (senderAddressType) { case P2PKH: case P2SHP2WPKH: - return new PeginEvaluationResult(PeginProcessAction.CAN_BE_REGISTERED); + return new PeginEvaluationResult(PeginProcessAction.REGISTER); case P2SHMULTISIG: case P2SHP2WSH: - return new PeginEvaluationResult(PeginProcessAction.CAN_BE_REFUNDED, LEGACY_PEGIN_MULTISIG_SENDER); + return new PeginEvaluationResult(PeginProcessAction.REFUND, LEGACY_PEGIN_MULTISIG_SENDER); default: - return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_REFUNDED, LEGACY_PEGIN_UNDETERMINED_SENDER); + return new PeginEvaluationResult(PeginProcessAction.NO_REFUND, 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 5fc6708c07..7306b1df26 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 @@ -1,7 +1,7 @@ package co.rsk.peg.pegin; public enum PeginProcessAction { - CAN_BE_REGISTERED, - CAN_BE_REFUNDED, - CANNOT_BE_REFUNDED + REGISTER, + REFUND, + NO_REFUND } 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 8dd17341a9..10f6a708e2 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 @@ -60,7 +60,7 @@ default void logRejectedPegin(BtcTransaction btcTx, RejectedPeginReason reason) throw new UnsupportedOperationException(); } - default void logUnrefundablePegin(BtcTransaction btcTx, UnrefundablePeginReason reason) { + default void logNonRefundablePegin(BtcTransaction btcTx, NonRefundablePeginReason 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 30c549af7a..f2b94d1068 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 @@ -212,7 +212,7 @@ public void logRejectedPegin(BtcTransaction btcTx, RejectedPeginReason reason) { } @Override - public void logUnrefundablePegin(BtcTransaction btcTx, UnrefundablePeginReason reason) { + public void logNonRefundablePegin(BtcTransaction btcTx, NonRefundablePeginReason reason) { CallTransaction.Function event = BridgeEvents.UNREFUNDABLE_PEGIN.getEvent(); byte[] btcTxHashSerialized = btcTx.getHash().getBytes(); diff --git a/rskj-core/src/main/java/co/rsk/peg/utils/UnrefundablePeginReason.java b/rskj-core/src/main/java/co/rsk/peg/utils/NonRefundablePeginReason.java similarity index 75% rename from rskj-core/src/main/java/co/rsk/peg/utils/UnrefundablePeginReason.java rename to rskj-core/src/main/java/co/rsk/peg/utils/NonRefundablePeginReason.java index da523b55e8..95db596273 100644 --- a/rskj-core/src/main/java/co/rsk/peg/utils/UnrefundablePeginReason.java +++ b/rskj-core/src/main/java/co/rsk/peg/utils/NonRefundablePeginReason.java @@ -1,13 +1,13 @@ package co.rsk.peg.utils; -public enum UnrefundablePeginReason { +public enum NonRefundablePeginReason { LEGACY_PEGIN_UNDETERMINED_SENDER(1), PEGIN_V1_REFUND_ADDRESS_NOT_SET(2), INVALID_AMOUNT(3); private final int value; - UnrefundablePeginReason(int value) { + NonRefundablePeginReason(int value) { this.value = value; } 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 e72a8ebe7c..7bf9cfc446 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -4,7 +4,7 @@ import static co.rsk.peg.PegTestUtils.*; import static co.rsk.peg.bitcoin.UtxoUtils.extractOutpointValues; import static co.rsk.peg.pegin.RejectedPeginReason.*; -import static co.rsk.peg.utils.UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; +import static co.rsk.peg.utils.NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -31,7 +31,7 @@ import co.rsk.peg.storage.BridgeStorageAccessorImpl; import co.rsk.peg.storage.StorageAccessor; import co.rsk.peg.utils.BridgeEventLogger; -import co.rsk.peg.utils.UnrefundablePeginReason; +import co.rsk.peg.utils.NonRefundablePeginReason; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.WhitelistStorageProvider; import co.rsk.peg.whitelist.WhitelistSupportImpl; @@ -101,7 +101,7 @@ class BridgeSupportRegisterBtcTransactionTest { // Before peg-out tx index gets in use private void assertInvalidPeginIsIgnored() throws IOException { verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); assertTrue(activeFederationUtxos.isEmpty()); @@ -111,7 +111,7 @@ private void assertInvalidPeginIsIgnored() throws IOException { // After peg-out tx index gets in use 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, times(1)).logNonRefundablePegin(btcTransaction, NonRefundablePeginReason.INVALID_AMOUNT); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); var shouldMarkTxAsProcessed = activations == lovell700Activations? times(1) : never(); @@ -124,7 +124,7 @@ private void assertInvalidPeginIsRejectedWithInvalidAmountReason(BtcTransaction private void assertUnknownTxIsProcessedAsPegin(RskAddress expectedRskAddressToBeLogged, BtcTransaction btcTransaction, int protocolVersion) throws IOException { verify(bridgeEventLogger, times(1)).logPeginBtc(expectedRskAddressToBeLogged, btcTransaction, Coin.ZERO, protocolVersion); verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); assertTrue(activeFederationUtxos.isEmpty()); assertTrue(retiringFederationUtxos.isEmpty()); @@ -133,7 +133,7 @@ private void assertUnknownTxIsProcessedAsPegin(RskAddress expectedRskAddressToBe // After arrowhead600Activations but before grace period private void assertUnknownTxIsRejectedWithInvalidAmountReason(BtcTransaction btcTransaction) throws IOException { verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, INVALID_AMOUNT); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin(btcTransaction, UnrefundablePeginReason.INVALID_AMOUNT); + verify(bridgeEventLogger, times(1)).logNonRefundablePegin(btcTransaction, NonRefundablePeginReason.INVALID_AMOUNT); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); assertTrue(activeFederationUtxos.isEmpty()); @@ -143,7 +143,7 @@ private void assertUnknownTxIsRejectedWithInvalidAmountReason(BtcTransaction btc // After arrowhead600Activations and grace period private void assertUnknownTxIsIgnored() throws IOException { verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); assertTrue(activeFederationUtxos.isEmpty()); @@ -152,7 +152,7 @@ private void assertUnknownTxIsIgnored() throws IOException { private void assertPeginIsRejectedAndRefunded(ActivationConfig.ForBlock activations, BtcTransaction btcTransaction, Coin sentAmount, RejectedPeginReason expectedRejectedPeginReason) throws IOException { verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); assertTrue(activeFederationUtxos.isEmpty()); assertTrue(retiringFederationUtxos.isEmpty()); @@ -180,7 +180,7 @@ private void assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloa verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, PEGIN_V1_INVALID_PAYLOAD ); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( btcTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER ); @@ -207,7 +207,7 @@ private void assertLegacyUndeterminedSenderPeginIsRejected(BtcTransaction btcTra verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER ); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( btcTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER ); @@ -229,7 +229,7 @@ private void assertInvalidPeginV1UndeterminedSenderIsRejected(BtcTransaction btc verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, PEGIN_V1_INVALID_PAYLOAD ); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( btcTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER ); @@ -785,7 +785,7 @@ void pegin_legacy_to_active_fed( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -826,7 +826,7 @@ void pegin_multiple_outputs_to_active_fed( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue.multiply(10)), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -866,7 +866,7 @@ void pegin_to_active_fed_with_bech32_output( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -906,7 +906,7 @@ void pegin_to_active_fed_equal_to_minimum_with_other_random_outputs_below_minimu // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -1059,7 +1059,7 @@ void pegin_to_active_and_retiring_fed( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue.multiply(2)), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -1133,7 +1133,7 @@ void pegin_to_active_and_retiring_fed_and_unknown_address( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue.multiply(2)), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -1178,7 +1178,7 @@ void pegin_v1_to_retiring_fed_can_be_registered( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(1)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -1230,7 +1230,7 @@ void pegin_v1_two_rsk_op_return_cannot_be_registered( // assert verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, PEGIN_V1_INVALID_PAYLOAD); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -1272,7 +1272,7 @@ void pegin_v1_invalid_protocol_legacy_sender_to_active_fed_( // assert verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, PEGIN_V1_INVALID_PAYLOAD); @@ -1315,7 +1315,7 @@ void pegin_v1_invalid_prefix_to_active_fed_can_be_registered( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -1366,7 +1366,7 @@ void pegin_v1_segwit_to_retiring_fed_can_be_registered( // assert verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(1)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -1691,7 +1691,7 @@ void pegout_sighash_no_exists_in_provider() throws BlockStoreException, BridgeIl ); // assert - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); verify(bridgeEventLogger, times(1)).logReleaseBtcRequested(eq(rskTx.getHash().getBytes()), any(BtcTransaction.class), eq(amountToSend)); @@ -2017,7 +2017,7 @@ void migration_sighash_no_exists_in_provider() throws BlockStoreException, Bridg // assert verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); verify(bridgeEventLogger, times(1)).logReleaseBtcRequested(eq(rskTx.getHash().getBytes()), any(BtcTransaction.class), eq(amountToSend)); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); @@ -2654,7 +2654,7 @@ void old_fed_migration( ); // assert - verify(bridgeEventLogger, never()).logUnrefundablePegin(migrationTx, LEGACY_PEGIN_UNDETERMINED_SENDER); + verify(bridgeEventLogger, never()).logNonRefundablePegin(migrationTx, LEGACY_PEGIN_UNDETERMINED_SENDER); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); assertTrue(retiringFederationUtxos.isEmpty()); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(migrationTx.getHash(false), rskExecutionBlock.getNumber()); @@ -2778,7 +2778,7 @@ void no_last_retired_fed_in_storage_sending_funds_to_active_fed( // assert if (shouldUsePegoutTxIndex) { verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java index ada0dd0746..3f78930eee 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java @@ -4,7 +4,7 @@ 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 co.rsk.peg.utils.NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -44,7 +44,7 @@ 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.peg.utils.NonRefundablePeginReason; import co.rsk.test.builders.BridgeSupportBuilder; import co.rsk.test.builders.FederationSupportBuilder; import java.io.IOException; @@ -75,7 +75,7 @@ class BridgeSupportRejectedPeginTest { 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() + private static final ActivationConfig.ForBlock allActivations = ActivationConfigsForTest.all() .forBlock(0); private static final Coin minimumPeginTxValue = bridgeMainnetConstants.getMinimumPeginTxValue( @@ -110,7 +110,7 @@ class BridgeSupportRejectedPeginTest { public static Stream activationsProvider() { return Stream.of( - Arguments.of(lovellActivations), + Arguments.of(allActivations), Arguments.of(arrowHeadActivations) ); } @@ -308,13 +308,13 @@ void registerBtcTransaction_whenBelowTheMinimum_shouldRejectPegin( // assert // tx should be marked as processed since RSKIP459 is active - var shouldMarkTxAsProcessed = activations == lovellActivations ? times(1) : never(); + var shouldMarkTxAsProcessed = activations == allActivations ? 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, times(1)).logNonRefundablePegin(btcTransaction, + NonRefundablePeginReason.INVALID_AMOUNT); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); assertTrue(activeFederationUtxos.isEmpty()); assertTrue(retiringFederationUtxos.isEmpty()); @@ -371,7 +371,7 @@ void registerBtcTransaction_whenUndeterminedSender_shouldRejectPegin( verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER ); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( btcTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER ); @@ -380,7 +380,7 @@ void registerBtcTransaction_whenUndeterminedSender_shouldRejectPegin( verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); // tx should be marked as processed since RSKIP459 is active - var shouldMarkTxAsProcessed = activations == lovellActivations ? times(1) : never(); + var shouldMarkTxAsProcessed = activations == allActivations ? times(1) : never(); verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); @@ -440,14 +440,14 @@ void registerBtcTransaction_whenPeginV1WithInvalidPayloadAndUnderminedSender_sho // assert // tx should be marked as processed since RSKIP459 is active - var shouldMarkTxAsProcessed = activations == lovellActivations ? times(1) : never(); + var shouldMarkTxAsProcessed = activations == allActivations ? times(1) : never(); verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); verify(bridgeEventLogger, times(1)).logRejectedPegin( btcTransaction, PEGIN_V1_INVALID_PAYLOAD ); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( btcTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER ); @@ -504,14 +504,14 @@ void registerBtcTransaction_whenUtxoToActiveFedBelowMinimumAndUtxoToRetiringFedA ); // assert - var shouldMarkTxAsProcessed = activations == lovellActivations ? times(1) : never(); + var shouldMarkTxAsProcessed = activations == allActivations ? 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, times(1)).logNonRefundablePegin(btcTransaction, + NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); assertTrue(activeFederationUtxos.isEmpty()); assertTrue(retiringFederationUtxos.isEmpty()); @@ -582,7 +582,7 @@ void registerBtcTransaction_whenAttemptToRegisterFlyoverPegin_shouldIgnorePegin( private void assertUnknownTxIsIgnored() throws IOException { verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); - verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logNonRefundablePegin(any(), any()); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); assertTrue(activeFederationUtxos.isEmpty()); 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 630d8a3ed9..e605aa5bec 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -31,7 +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.peg.utils.NonRefundablePeginReason; import co.rsk.test.builders.BridgeSupportBuilder; import co.rsk.test.builders.FederationSupportBuilder; import java.io.IOException; @@ -1457,7 +1457,7 @@ private void assertTxIsRejectedPeginAndMarkedAsProcessed(BtcTransaction rejected Function unrefundablePeginEvent = BridgeEvents.UNREFUNDABLE_PEGIN.getEvent(); List encodedTopics = getEncodedTopics(unrefundablePeginEvent, btcTxHashSerialized); - byte[] encodedData = getEncodedData(unrefundablePeginEvent, UnrefundablePeginReason.INVALID_AMOUNT.getValue()); + byte[] encodedData = getEncodedData(unrefundablePeginEvent, NonRefundablePeginReason.INVALID_AMOUNT.getValue()); assertEventWasEmittedWithExpectedTopics(encodedTopics); assertEventWasEmittedWithExpectedData(encodedData); diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index 70185e73c1..93b2a24361 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -55,7 +55,7 @@ import co.rsk.peg.pegininstructions.*; import co.rsk.peg.storage.*; import co.rsk.peg.utils.*; -import co.rsk.peg.utils.UnrefundablePeginReason; +import co.rsk.peg.utils.NonRefundablePeginReason; import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.whitelist.*; import co.rsk.peg.whitelist.constants.WhitelistMainNetConstants; @@ -1169,7 +1169,8 @@ void eventLoggerLogPeginRejectionEvents_before_rskip_181_activation() throws Exc bridgeSupport.registerBtcTransaction(mock(Transaction.class), tx.bitcoinSerialize(), height, pmt.bitcoinSerialize()); verify(mockedEventLogger, never()).logRejectedPegin(any(BtcTransaction.class), any(RejectedPeginReason.class)); - verify(mockedEventLogger, never()).logUnrefundablePegin(any(BtcTransaction.class), any(UnrefundablePeginReason.class)); + verify(mockedEventLogger, never()).logNonRefundablePegin(any(BtcTransaction.class), any( + NonRefundablePeginReason.class)); } @Test @@ -1265,7 +1266,8 @@ void eventLoggerLogPeginRejectionEvents_after_rskip_181_activation() throws Exce ); verify(mockedEventLogger, atLeastOnce()).logRejectedPegin(any(BtcTransaction.class), any(RejectedPeginReason.class)); - verify(mockedEventLogger, atLeastOnce()).logUnrefundablePegin(any(BtcTransaction.class), any(UnrefundablePeginReason.class)); + verify(mockedEventLogger, atLeastOnce()).logNonRefundablePegin(any(BtcTransaction.class), any( + NonRefundablePeginReason.class)); } @Test 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 2c68e61ab3..8c3e31c511 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsEvaluatePeginTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsEvaluatePeginTest.java @@ -50,11 +50,11 @@ private static Stream protocolVersionArgs() { private static Stream argumentsForWhenProtocolVersionLegacyIs0AndDifferentAddressTypes() { return Stream.of( - Arguments.of(BtcLockSender.TxSenderAddressType.P2PKH, PeginProcessAction.CAN_BE_REGISTERED, null), - 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_REFUNDED, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER) + Arguments.of(BtcLockSender.TxSenderAddressType.P2PKH, PeginProcessAction.REGISTER, null), + Arguments.of(BtcLockSender.TxSenderAddressType.P2SHP2WPKH, PeginProcessAction.REGISTER, null), + Arguments.of(BtcLockSender.TxSenderAddressType.P2SHMULTISIG, PeginProcessAction.REFUND, RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER), + Arguments.of(BtcLockSender.TxSenderAddressType.P2SHP2WSH, PeginProcessAction.REFUND, RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER), + Arguments.of(BtcLockSender.TxSenderAddressType.UNKNOWN, PeginProcessAction.NO_REFUND, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER) ); } @@ -104,7 +104,7 @@ void evaluatePegin_valueBelowMinimum_returnsPeginEvaluationResultWithCannotBePro activations ); - assertEquals(PeginProcessAction.CANNOT_BE_REFUNDED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.NO_REFUND, 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_REFUNDED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.NO_REFUND, peginEvaluationResult.getPeginProcessAction()); assertTrue(peginEvaluationResult.getRejectedPeginReason().isPresent()); assertEquals(RejectedPeginReason.PEGIN_V1_INVALID_PAYLOAD, peginEvaluationResult.getRejectedPeginReason().get()); } @@ -156,7 +156,7 @@ void evaluatePegin_parseThrowsExceptionAndBtcRefundAddressIsPresent(int protocol activations ); - assertEquals(PeginProcessAction.CAN_BE_REFUNDED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.REFUND, peginEvaluationResult.getPeginProcessAction()); assertTrue(peginEvaluationResult.getRejectedPeginReason().isPresent()); assertEquals(RejectedPeginReason.PEGIN_V1_INVALID_PAYLOAD, peginEvaluationResult.getRejectedPeginReason().get()); } @@ -203,7 +203,7 @@ void evaluatePegin_validPeginInformationWithProtocolVersion1_peginProcessActionC activations ); - assertEquals(PeginProcessAction.CAN_BE_REGISTERED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.REGISTER, peginEvaluationResult.getPeginProcessAction()); } @Test() @@ -255,7 +255,7 @@ void evaluatePegin_pegout_peginProcessActionCanBeRegistered() { activations ); - assertEquals(PeginProcessAction.CAN_BE_REGISTERED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.REGISTER, peginEvaluationResult.getPeginProcessAction()); } @Test @@ -280,6 +280,6 @@ void evaluatePegin_migration_peginProcessActionCanBeRegistered() { activations ); - assertEquals(PeginProcessAction.CAN_BE_REGISTERED, peginEvaluationResult.getPeginProcessAction()); + assertEquals(PeginProcessAction.REGISTER, peginEvaluationResult.getPeginProcessAction()); } } 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 635ece7377..f4a0ee250b 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 @@ -398,9 +398,9 @@ void logRejectedPegin() { } @Test - void logUnrefundablePegin() { + void logNonRefundablePegin() { // Setup event logger - eventLogger.logUnrefundablePegin(BTC_TRANSACTION, UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); + eventLogger.logNonRefundablePegin(BTC_TRANSACTION, NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); assertEquals(1, eventLogs.size()); LogInfo entry = eventLogs.get(0); @@ -423,7 +423,7 @@ void logUnrefundablePegin() { // Assert log data assertArrayEquals( - event.encodeEventData(UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER.getValue()), + event.encodeEventData(NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER.getValue()), result.getData() ); } 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 598d233c48..d4374366ae 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 @@ -64,10 +64,10 @@ void logRejectedPegin() { } @Test - void logUnrefundablePegin() { - assertThrows(UnsupportedOperationException.class, () -> eventLogger.logUnrefundablePegin( + void logNonRefundablePegin() { + assertThrows(UnsupportedOperationException.class, () -> eventLogger.logNonRefundablePegin( btcTxMock, - UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER + NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER )); }