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 4508a55680f..a2241c3416e 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.*; @@ -504,48 +503,74 @@ 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); - } - 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); - markTxAsProcessed(btcTx); - } else { - logger.debug("[{}] Unprocessable transaction {}.", METHOD_NAME, btcTx.getHash()); - handleUnprocessableBtcTx(btcTx, peginInformation.getProtocolVersion(), rejectedPeginReason); + switch (peginProcessAction) { + case REGISTER -> { + logger.debug("[{}] Peg-in is valid, going to register", METHOD_NAME); + executePegIn(btcTx, peginInformation, totalAmount); } + case REFUND -> handleRefundablePegin(btcTx, rskTxHash, peginEvaluationResult, + peginInformation.getBtcRefundAddress()); + case NO_REFUND -> handleNonRefundablePegin(btcTx, peginInformation.getProtocolVersion(), + peginEvaluationResult); } } - private void handleUnprocessableBtcTx( + 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(), + nonRefundablePeginReason); + eventLogger.logNonRefundablePegin(btcTx, nonRefundablePeginReason); - logger.debug("[handleUnprocessableBtcTx] Unprocessable tx {}. Reason {}", btcTx.getHash(), unrefundablePeginReason); - eventLogger.logUnrefundablePegin(btcTx, unrefundablePeginReason); + if (!activations.isActive(RSKIP459)) { + return; + } + // Since RSKIP459, rejected peg-ins should be marked as processed + markTxAsProcessed(btcTx); } /** @@ -713,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 6e25ba8051f..e5140f21f4f 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.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_PROCESSED; + 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_PROCESSED, 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 57d451076df..7306b1df261 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_PROCESSED + 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 8dd17341a9e..10f6a708e26 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 30c549af7a9..f2b94d10688 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 da523b55e8d..95db596273f 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/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java index 5a14eaa3d09..4667e5e5465 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 8e88b979314..5710410f5e7 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 511d906be92..f7f5d4bb8a5 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/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java index aecb7505444..7bf9cfc4464 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; @@ -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; @@ -100,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()); @@ -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, times(1)).logNonRefundablePegin(btcTransaction, NonRefundablePeginReason.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()); } @@ -121,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()); @@ -130,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()); @@ -140,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()); @@ -149,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()); @@ -177,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 ); @@ -194,29 +197,39 @@ 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 ); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( btcTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER ); 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 ); - verify(bridgeEventLogger, times(1)).logUnrefundablePegin( + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( btcTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER ); @@ -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()); @@ -773,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()); @@ -814,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()); @@ -854,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()); @@ -894,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()); @@ -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(); } @@ -1047,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()); @@ -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(); } @@ -1121,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()); @@ -1166,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()); @@ -1218,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()); @@ -1260,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); @@ -1303,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()); @@ -1354,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()); @@ -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){ + if (activations == fingerrootActivations) { + // BEFORE RSKIP379 REJECTED PEGIN WERE MARKED AS PROCESSED. assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloadBeforeRSKIP379(btcTransaction); } else { - assertLegacyUndeterminedSenderPeginIsRejected(btcTransaction); + assertLegacyUndeterminedSenderPeginIsRejected(btcTransaction, activations); } } @@ -1680,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)); @@ -2006,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()); @@ -2643,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()); @@ -2767,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 new file mode 100644 index 00000000000..3f78930eeec --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRejectedPeginTest.java @@ -0,0 +1,634 @@ +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; +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; +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.RejectedPeginReason; +import co.rsk.peg.pegininstructions.PeginInstructionsProvider; +import co.rsk.peg.utils.BridgeEventLogger; +import co.rsk.peg.utils.NonRefundablePeginReason; +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.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 allActivations = 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(allActivations), + 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 = createValidPmtForTransactions( + Collections.singletonList(btcTransaction.getHash()), btcMainnetParams); + + 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 == allActivations ? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), + anyLong()); + + verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, 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()); + } + + @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)).logNonRefundablePegin( + 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 == allActivations ? 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 == allActivations ? times(1) : never(); + verify(provider, shouldMarkTxAsProcessed).setHeightBtcTxhashAlreadyProcessed(any(), + anyLong()); + + verify(bridgeEventLogger, times(1)).logRejectedPegin( + btcTransaction, PEGIN_V1_INVALID_PAYLOAD + ); + verify(bridgeEventLogger, times(1)).logNonRefundablePegin( + 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 == 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)).logNonRefundablePegin(btcTransaction, + NonRefundablePeginReason.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()).logNonRefundablePegin(any(), any()); + verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); + verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); + } + + @ParameterizedTest + @MethodSource("activationsProvider") + void registerBtcTransaction_whenNoUtxoToFed_shouldIgnorePegin( + ActivationConfig.ForBlock activations) + throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); + btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, + new Script(new byte[]{})); + btcTransaction.addOutput(minimumPeginTxValue, userAddress); + + FederationSupport federationSupport = FederationSupportBuilder.builder() + .withFederationConstants(federationMainnetConstants) + .withFederationStorageProvider(federationStorageProvider) + .withActivations(activations) + .withRskExecutionBlock(rskExecutionBlock) + .build(); + + BridgeSupport bridgeSupport = BridgeSupportBuilder.builder() + .withBtcBlockStoreFactory(mockFactory) + .withBridgeConstants(bridgeMainnetConstants) + .withRepository(repository) + .withProvider(provider) + .withActivations(activations) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withExecutionBlock(rskExecutionBlock) + .withFederationSupport(federationSupport) + .build(); + + // act + bridgeSupport.registerBtcTransaction( + rskTx, + btcTransaction.bitcoinSerialize(), + heightAtWhichToStartUsingPegoutIndex, + createPmtAndMockBlockStore(btcTransaction).bitcoinSerialize() + ); + + // assert + assertUnknownTxIsIgnored(); + } +} diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java index 3b47a96f485..e605aa5bec6 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.NonRefundablePeginReason; 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, since 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, NonRefundablePeginReason.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/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index 70185e73c13..93b2a243619 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 e98cc53d924..8c3e31c5117 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_PROCESSED, 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_PROCESSED, 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_PROCESSED, 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 635ece73774..f4a0ee250bc 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 598d233c48c..d4374366ae3 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 )); } 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 ecdd42f1503..12f2d7c61a3 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 e0dc663f34c..399bb0b54b8 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 )); }