From 8d33886478ba6f41eaf2457a66c8b8b0491eee30 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Wed, 21 Oct 2026 16:08:51 -0300 Subject: [PATCH 01/23] feat: stop looking up the pegout index after the federations pending btc utxos grace period --- .../src/main/java/co/rsk/peg/PegUtils.java | 29 +- .../test/java/co/rsk/peg/PegUtilsTest.java | 366 +++++++++++++++--- 2 files changed, 330 insertions(+), 65 deletions(-) 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 1827ff38b09..54a33fc976f 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java @@ -34,8 +34,10 @@ private PegUtils() { } static PegTxType getTransactionTypeUsingPegoutIndex( ActivationConfig.ForBlock activations, BridgeStorageProvider provider, + BridgeConstants bridgeConstants, Wallet liveFederationsWallet, - BtcTransaction btcTransaction + BtcTransaction btcTransaction, + long btcTransactionHeight ) { if (!activations.isActive(ConsensusRule.RSKIP379)) { throw new IllegalStateException("Can't call this method before RSKIP379 activation"); @@ -43,7 +45,12 @@ static PegTxType getTransactionTypeUsingPegoutIndex( List liveFederationOutputs = btcTransaction.getWalletOutputs(liveFederationsWallet); - Optional inputSigHash = BitcoinUtils.getSigHashForPegoutIndex(btcTransaction); + Optional inputSigHash = getSigHashToLookUpInPegoutIndex( + bridgeConstants, + activations, + btcTransaction, + btcTransactionHeight + ); if (inputSigHash.isPresent() && provider.hasPegoutTxSigHash(inputSigHash.get())){ return PegTxType.PEGOUT_OR_MIGRATION; } else if (!liveFederationOutputs.isEmpty()){ @@ -53,6 +60,20 @@ static PegTxType getTransactionTypeUsingPegoutIndex( } } + private static Optional getSigHashToLookUpInPegoutIndex( + BridgeConstants bridgeConstants, + ActivationConfig.ForBlock activations, + BtcTransaction btcTransaction, + long btcTransactionHeight + ) { + // Once the grace period ends, releases are only identified by their federations pending btc utxos, + // so the sighash is no longer computed to look it up in the pegout index + if (isFederationsPendingBtcUTXOsEnabled(bridgeConstants, activations, btcTransactionHeight)) { + return Optional.empty(); + } + return BitcoinUtils.getSigHashForPegoutIndex(btcTransaction); + } + /** * Checks if all utxos sent to the fedWallet are equal or above the minimum pegin value. * If no utxo is sent to the fedWallet or there is at least 1 utxo sent to the fedWallet that is below minimum, @@ -126,8 +147,10 @@ static PegTxType getTransactionType( return getTransactionTypeUsingPegoutIndex( activations, provider, + bridgeConstants, liveFederationsWallet, - btcTransaction + btcTransaction, + btcTransactionHeight ); } diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java index 53b88ba4984..31fb78302b9 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java @@ -7,15 +7,18 @@ import co.rsk.peg.constants.BridgeConstants; import co.rsk.peg.constants.BridgeMainNetConstants; import co.rsk.peg.constants.BridgeTestNetConstants; +import co.rsk.RskTestUtils; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import co.rsk.peg.bitcoin.BitcoinTestUtils; +import co.rsk.peg.bitcoin.BitcoinUtils; import co.rsk.peg.federation.*; import co.rsk.peg.federation.constants.FederationConstants; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import java.time.Instant; import java.util.Arrays; @@ -24,6 +27,8 @@ import java.util.Optional; import static co.rsk.peg.PegTestUtils.createFederation; +import static co.rsk.peg.PegTxType.*; +import static co.rsk.peg.PegTxType.PEGOUT_OR_MIGRATION; import static co.rsk.peg.PegUtils.*; import static co.rsk.peg.federation.FederationTestUtils.createP2shErpFederation; import static org.junit.jupiter.api.Assertions.*; @@ -35,7 +40,10 @@ class PegUtilsTest { private static final NetworkParameters btcMainnetParams = bridgeMainnetConstants.getBtcParams(); private static final FederationConstants federationMainNetConstants = bridgeMainnetConstants.getFederationConstants(); private static final Context context = new Context(bridgeMainnetConstants.getBtcParams()); - private static final ActivationConfig.ForBlock activations = ActivationConfigsForTest.all().forBlock(0); + private static final ActivationConfig.ForBlock allActivations = ActivationConfigsForTest.all().forBlock(0); + private static final ActivationConfig.ForBlock vetiverActivations = ActivationConfigsForTest.vetiver900().forBlock(0); + private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = bridgeMainnetConstants.getBtcHeightWhenPegoutTxIndexActivates() + + bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); private static final int FIRST_OUTPUT_INDEX = 0; private static final int FIRST_INPUT_INDEX = 0; @@ -74,7 +82,7 @@ void getFlyoverDerivationHash_returnsExpectedDerivationHash() { userRefundBtcAddress, lpBtcAddress, lbcAddress, - activations + allActivations ); // assert @@ -174,7 +182,14 @@ void test_getTransactionType_before_rskip379() { // Act IllegalStateException exception = assertThrows(IllegalStateException.class, () -> - PegUtils.getTransactionTypeUsingPegoutIndex(fingerrootActivations, provider, liveFederationWallet, btcTransaction) + PegUtils.getTransactionTypeUsingPegoutIndex( + fingerrootActivations, + provider, + bridgeMainnetConstants, + liveFederationWallet, + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX - 1 + ) ); // Assert @@ -193,14 +208,16 @@ void test_getTransactionType_tx_sending_funds_to_unknown_address() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.UNKNOWN, pegTxType); + assertEquals(UNKNOWN, pegTxType); } @Test @@ -208,21 +225,23 @@ void test_getTransactionType_pegin_below_minimum_active_fed() { // Arrange Wallet liveFederationWallet = new BridgeBtcWallet(context, Collections.singletonList(activeFederation)); - Coin minimumPeginTxValue = bridgeMainnetConstants.getMinimumPeginTxValue(activations); + Coin minimumPeginTxValue = bridgeMainnetConstants.getMinimumPeginTxValue(allActivations); BtcTransaction btcTransaction = new BtcTransaction(btcMainnetParams); btcTransaction.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); btcTransaction.addOutput(minimumPeginTxValue.minus(Coin.SATOSHI), activeFederation.getAddress()); // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -236,14 +255,16 @@ void test_getTransactionType_pegin_active_fed() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -260,14 +281,16 @@ void test_getTransactionType_pegin_output_to_active_fed_and_other_addresses() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -284,14 +307,16 @@ void test_getTransactionType_pegin_multiple_outputs_to_active_fed() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -317,14 +342,16 @@ void test_getTransactionType_pegin_output_to_retiring_fed_and_other_addresses() // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -338,14 +365,16 @@ void test_getTransactionType_pegin_retiring_fed() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -362,14 +391,16 @@ void test_getTransactionType_pegin_multiple_outputs_to_retiring_fed() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -385,14 +416,16 @@ void test_getTransactionType_pegin_outputs_to_active_and_retiring_fed() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -410,14 +443,16 @@ void test_getTransactionType_pegin_outputs_to_active_and_retiring_fed_and_other_ // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -445,14 +480,16 @@ void test_getTransactionType_pegout_no_change_output() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); } @Test @@ -471,14 +508,16 @@ void test_getTransactionType_pegout_no_change_output_sighash_no_exists_in_provid // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.UNKNOWN, pegTxType); + assertEquals(UNKNOWN, pegTxType); } @Test @@ -507,14 +546,16 @@ void test_getTransactionType_standard_pegout() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); } @Test @@ -534,14 +575,16 @@ void test_getTransactionType_standard_pegout_sighash_no_exists_in_provider() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -570,14 +613,16 @@ void test_getTransactionType_migration() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); } @Test @@ -598,14 +643,16 @@ void test_getTransactionType_migration_sighash_no_exists_in_provider() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGIN, pegTxType); + assertEquals(PEGIN, pegTxType); } @Test @@ -634,14 +681,16 @@ void test_getTransactionType_migration_from_retired_fed() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); } @Test @@ -659,7 +708,7 @@ void test_getTransactionType_flyover() { userRefundBtcAddress, lpBtcAddress, lbcAddress, - activations + allActivations ); Address activeFederationAddress = PegTestUtils.getFlyoverAddressFromRedeemScript( @@ -678,14 +727,16 @@ void test_getTransactionType_flyover() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.UNKNOWN, pegTxType); + assertEquals(UNKNOWN, pegTxType); } @Test @@ -712,14 +763,16 @@ void test_getTransactionType_flyover_segwit() { // Act PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - activations, + allActivations, provider, + bridgeMainnetConstants, liveFederationWallet, - btcTransaction + btcTransaction, + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // Assert - assertEquals(PegTxType.UNKNOWN, pegTxType); + assertEquals(UNKNOWN, pegTxType); } @Test @@ -761,4 +814,193 @@ void isTheSvpFundTxHashUnsigned_whenHashDoesNotMatchSvpFundTxHashUnsigned_should // Assert assertFalse(isTheSvpFundTransaction); } + + @Nested + class FederationsPendingBtcUTXOsGracePeriod { + private static final int HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + + bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); + // while in the grace period, releases created before RSKIP643 are still looked up in the pegout index + private static final int HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - 1; + + private BridgeStorageProvider bridgeStorageProvider; + + @BeforeEach + void setUp() { + activeFederation = P2shP2wshErpFederationBuilder.builder().build(); + } + + @Test + void getTransactionType_withPegoutInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(vetiverActivations); + Wallet liveFederationWallet = new BridgeBtcWallet(context, Collections.singletonList(activeFederation)); + BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); + savePegoutSigHashInPegoutIndex(pegout); + + // act + PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( + vetiverActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + liveFederationWallet, + pegout, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withPegoutInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(allActivations); + Wallet liveFederationWallet = new BridgeBtcWallet(context, Collections.singletonList(activeFederation)); + BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); + savePegoutSigHashInPegoutIndex(pegout); + + // act + PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + liveFederationWallet, + pegout, + HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + ); + + // assert + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withPegoutInPegoutIndex_afterGracePeriod_shouldBePegin() { + // arrange + setUpBridgeStorageProvider(allActivations); + Wallet liveFederationWallet = new BridgeBtcWallet(context, Collections.singletonList(activeFederation)); + BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); + savePegoutSigHashInPegoutIndex(pegout); + + // act + PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + liveFederationWallet, + pegout, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PEGIN, pegTxType); + } + + @Test + void getTransactionType_withMigrationInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(vetiverActivations); + Wallet liveFederationWallet = new BridgeBtcWallet(context, Arrays.asList(retiringFederation, activeFederation)); + BtcTransaction migration = buildMigrationTransaction(); + savePegoutSigHashInPegoutIndex(migration); + + // act + PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( + vetiverActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + liveFederationWallet, + migration, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withMigrationInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(allActivations); + Wallet liveFederationWallet = new BridgeBtcWallet(context, Arrays.asList(retiringFederation, activeFederation)); + BtcTransaction migration = buildMigrationTransaction(); + savePegoutSigHashInPegoutIndex(migration); + + // act + PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + liveFederationWallet, + migration, + HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + ); + + // assert + assertEquals(PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withMigrationInPegoutIndex_afterGracePeriod_shouldBePegin() { + // arrange + setUpBridgeStorageProvider(allActivations); + Wallet liveFederationWallet = new BridgeBtcWallet(context, Arrays.asList(retiringFederation, activeFederation)); + BtcTransaction migration = buildMigrationTransaction(); + savePegoutSigHashInPegoutIndex(migration); + + // act + PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + liveFederationWallet, + migration, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PEGIN, pegTxType); + } + + private void setUpBridgeStorageProvider(ActivationConfig.ForBlock activations) { + bridgeStorageProvider = new BridgeStorageProvider( + RskTestUtils.createRepository(), + btcMainnetParams, + activations + ); + } + + private BtcTransaction buildPegoutWithChangeFromActiveFed() { + BtcTransaction pegout = new BtcTransaction(btcMainnetParams); + pegout.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + addSpendingFederationBaseScript(pegout, activeFederation); + pegout.addOutput(Coin.COIN, userAddress); + pegout.addOutput(Coin.COIN, activeFederation.getAddress()); + return pegout; + } + + private BtcTransaction buildMigrationTransaction() { + BtcTransaction migration = new BtcTransaction(btcMainnetParams); + migration.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); + addSpendingFederationBaseScript(migration, retiringFederation); + migration.addOutput(Coin.COIN, activeFederation.getAddress()); + return migration; + } + + private void addSpendingFederationBaseScript(BtcTransaction releaseTransaction, Federation spendingFederation) { + BitcoinUtils.addSpendingFederationBaseScript( + releaseTransaction, + FIRST_INPUT_INDEX, + spendingFederation.getRedeemScript(), + spendingFederation.getFormatVersion() + ); + } + + private void savePegoutSigHashInPegoutIndex(BtcTransaction releaseTransaction) { + // the same sighash the bridge saves in the pegout index when creating the release + Sha256Hash pegoutTxSigHash = BitcoinUtils.getSigHashForPegoutIndex(releaseTransaction).orElseThrow(); + bridgeStorageProvider.setPegoutTxSigHash(pegoutTxSigHash); + // the sighash is only buffered until saved, while the lookup reads it from the repository + bridgeStorageProvider.save(); + } + } } From ae7a20795ede3abdc7b99356f983d8f5c72e4066 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Wed, 21 Oct 2026 16:15:10 -0300 Subject: [PATCH 02/23] feat: stop looking up the pegout index after the federations pending btc utxos grace period --- rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java index 31fb78302b9..e75437ce75b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java @@ -26,9 +26,11 @@ import java.util.List; import java.util.Optional; +import static co.rsk.RskTestUtils.generateAddress; import static co.rsk.peg.PegTestUtils.createFederation; -import static co.rsk.peg.PegTxType.*; +import static co.rsk.peg.PegTxType.PEGIN; import static co.rsk.peg.PegTxType.PEGOUT_OR_MIGRATION; +import static co.rsk.peg.PegTxType.UNKNOWN; import static co.rsk.peg.PegUtils.*; import static co.rsk.peg.federation.FederationTestUtils.createP2shErpFederation; import static org.junit.jupiter.api.Assertions.*; @@ -73,7 +75,7 @@ void getFlyoverDerivationHash_returnsExpectedDerivationHash() { // arrange Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userRefundBtcAddress"); Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "lpBtcAddress"); - Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(5); + Keccak256 derivationArgumentsHash = RskTestUtils.createHash(5); RskAddress lbcAddress = new RskAddress("461750b4824b14c3d9b7702bc6fbb82469082b23"); // act @@ -700,8 +702,8 @@ void test_getTransactionType_flyover() { Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userRefundBtcAddress"); Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "lpBtcAddress"); - Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); - RskAddress lbcAddress = PegTestUtils.createRandomRskAddress(); + Keccak256 derivationArgumentsHash = RskTestUtils.createHash(0); + RskAddress lbcAddress = generateAddress("lbcAddress"); Keccak256 flyoverDerivationHash = PegUtils.getFlyoverDerivationHash( derivationArgumentsHash, From f111535581857fe7e5ce89e0225d168c57c62fe6 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Wed, 21 Oct 2026 17:37:26 -0300 Subject: [PATCH 03/23] test: cover releases created for vetiver registered within and after the federations pending btc utxos grace period --- ...idgeSupportRegisterBtcTransactionTest.java | 304 +++++++++++++----- 1 file changed, 218 insertions(+), 86 deletions(-) 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 604728af23c..96680d3e2d2 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -89,6 +89,12 @@ class BridgeSupportRegisterBtcTransactionTest { private static final int BTC_HEIGHT_WHEN_PEGOUT_TX_INDEX_ACTIVATES = bridgeMainnetConstants.getBtcHeightWhenPegoutTxIndexActivates(); private static final int PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS = bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = BTC_HEIGHT_WHEN_PEGOUT_TX_INDEX_ACTIVATES + PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS; + // past the pegout index start, so releases are not identified by their inputs as legacy releases are, + // and past the grace period, so releases created before RSKIP643 are no longer looked up in the pegout index + private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + + PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS; + // still past the pegout index start, and releases created before RSKIP643 are still looked up in it + private static final int BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT = HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - 1; private static final int HEIGHT_BEFORE_USING_PEGOUT_INDEX = 1; private static final int UTXO_HEIGHT_BEFORE_CARDAMOM = 0; private static final Address userAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userAddress"); @@ -3059,7 +3065,7 @@ void registerBtcTransaction_withNoChangeOutput_forReed_withRetiringFed_withSegwi registerPegoutTxSigHash(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); @@ -3073,7 +3079,7 @@ void registerBtcTransaction_withNoChangeOutput_withoutRetiringFed_withSegwitActi registerPegoutTxSigHash(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); @@ -3087,7 +3093,7 @@ void registerBtcTransaction_withNoChangeOutput_withoutRetiringFed_withSegwitActi // with no output sent to the live federations, no federations pending utxos are saved // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert assertReleaseTxWasNotProcessed(btcTransaction); @@ -3101,7 +3107,7 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); // act - registerLegacyReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX, bridgeMainnetConstants); + registerLegacyReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, bridgeMainnetConstants); // assert assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); @@ -3129,7 +3135,7 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); @@ -3151,13 +3157,13 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit } @Test - void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_withinGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange setupSegwitActiveAndSegwitRetiringFeds(allActivations); BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT); // assert assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); @@ -3296,7 +3302,7 @@ void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_forReed_with registerPegoutTxSigHash(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( @@ -3315,7 +3321,7 @@ void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withRetiring registerPegoutTxSigHash(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( @@ -3334,13 +3340,13 @@ void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withRetiring registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3355,13 +3361,13 @@ void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withoutRetir registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3486,7 +3492,7 @@ void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_forReed_wi registerPegoutTxSigHash(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( @@ -3506,13 +3512,13 @@ void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withRetiri registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3527,13 +3533,13 @@ void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withoutRet registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3628,7 +3634,7 @@ void registerBtcTransaction_withNoChangeOutputAndManyInputs_forReed_withRetiring // act registerPegoutTxSigHash(btcTransaction); - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); @@ -3642,7 +3648,7 @@ void registerBtcTransaction_withNoChangeOutputAndManyInputs_withRetiringFed_with // act // with no output sent to the live federations, no federations pending utxos are saved - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert assertReleaseTxWasNotProcessed(btcTransaction); @@ -3657,7 +3663,7 @@ void registerBtcTransaction_withNoChangeOutputAndManyInputs_withoutRetiringFed_w // act // with no output sent to the live federations, no federations pending utxos are saved - registerReleaseTransaction(btcTransaction); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert assertReleaseTxWasNotProcessed(btcTransaction); @@ -3858,7 +3864,7 @@ void registerBtcTransaction_withOneInputAndOutput_withSegwitActiveAndRetiringFed // act registerPegoutTxSigHash(migrationTx); - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( @@ -3881,13 +3887,13 @@ void registerBtcTransaction_withOneInputAndOutput_withSegwitActiveAndRetiringFed registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertMigrationTxWasProcessed( migrationTx, @@ -4047,7 +4053,7 @@ void registerBtcTransaction_withManyOutputsAndInputs_withSegwitActiveAndRetiring // act registerPegoutTxSigHash(migrationTx); - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( @@ -4070,13 +4076,13 @@ void registerBtcTransaction_withManyOutputsAndInputs_withSegwitActiveAndRetiring registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertMigrationTxWasProcessed( migrationTx, @@ -4186,13 +4192,13 @@ void registerBtcTransaction_withManyOutputsAndOneInput_withSegwitActiveAndRetiri registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertMigrationTxWasProcessed( migrationTx, @@ -4302,13 +4308,13 @@ void registerBtcTransaction_withOneOutputAndManyInputs_withSegwitActiveAndRetiri registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertMigrationTxWasProcessed( migrationTx, @@ -4418,7 +4424,7 @@ void registerBtcTransaction_withFlyoverUtxoWithOneInputAndOutput_withSegwitActiv // act registerPegoutTxSigHash(migrationTx); - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( @@ -4442,13 +4448,13 @@ void registerBtcTransaction_withFlyoverUtxoWithOneInputAndOutput_withSegwitActiv registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx); + registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertMigrationTxWasProcessed( migrationTx, @@ -4675,13 +4681,13 @@ void registerBtcTransaction_fromRetiredFederationNotInStorage_withSegwitActiveFe registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerLegacyReleaseTransaction(migrationTx, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX, bridgeMainnetConstants); + registerLegacyReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, bridgeMainnetConstants); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertMigrationTxWasProcessed( migrationTx, @@ -5092,11 +5098,11 @@ private void registerLegacyReleaseTransaction(BtcTransaction releaseTx, int heig bridgeSupport.save(); } - private void registerReleaseTransaction(BtcTransaction releaseTx) throws BlockStoreException, BridgeIllegalArgumentException, IOException { + private void registerReleaseTransaction(BtcTransaction releaseTx, int height) throws BlockStoreException, BridgeIllegalArgumentException, IOException { PartialMerkleTree pmtWithWitness = buildPMTAndRecreateChainForSegwitTransactionRegistration( bridgeStorageProvider, bridgeMainnetConstants, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX, + height, releaseTx, btcBlockStore ); @@ -5104,7 +5110,7 @@ private void registerReleaseTransaction(BtcTransaction releaseTx) throws BlockSt bridgeSupport.registerBtcTransaction( rskTx, releaseTx.bitcoinSerialize(), - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX, + height, pmtWithWitness.bitcoinSerialize() ); bridgeSupport.save(); @@ -5176,9 +5182,6 @@ private BtcTransaction getReleaseTxWithOneInputAndOutputWithoutChange(Federation @Nested class ReleaseWithFederationsPendingBtcUTXOs { - // well past the pegout index start, so the release is not identified by its inputs as legacy releases are, - // and since it was created after RSKIP643 it is not in the pegout index either - private static final int BTC_BLOCK_WITH_RELEASE_HEIGHT = HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + 1_000; private static final long ACTIVE_FEDERATION_CREATION_BLOCK_NUMBER = 1L; // the active federation must be active for the pegout to be created private static final long PEGOUT_CREATION_BLOCK_NUMBER = ACTIVE_FEDERATION_CREATION_BLOCK_NUMBER @@ -5253,6 +5256,63 @@ void setUp() { btcBlockStore = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, allActivations); } + @Test + void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_withinGracePeriod_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + // before RSKIP643 the pegout sighash is saved in the pegout index instead of its change as federations pending utxos + BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); + assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(pegout.getHash())); + setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); + + // act + signAndRegisterReleaseTransaction( + pegout, + segwitActiveFederation, + segwitActiveFederationKeys, + BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + ); + + // assert + List expectedUtxosRegistered = buildExpectedUtxosRegistered( + pegout, + segwitActiveFederation, + BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + ); + assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); + assertReleaseWasRegistered( + bridgeStorageProvider, + federationSupport, + logs, + (int) rskExecutionBlock.getNumber(), + pegout, + List.of(CHANGE_VALUE), + List.of(OUTPUT_INDEX_FOR_PEGOUT_CHANGE), + segwitActiveFederation.getAddress() + ); + } + + @Test + void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_afterGracePeriod_shouldRejectAsUnrefundablePegin() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); + assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(pegout.getHash())); + setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); + + // act + signAndRegisterReleaseTransaction( + pegout, + segwitActiveFederation, + segwitActiveFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + ); + + // assert + // the pegout index is no longer looked up, so the change sent from the federation is evaluated as a legacy pegin + assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); + assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); + assertReleaseWasRejectedAsUnrefundablePegin(pegout); + } + @Test void registerBtcTransaction_withPegoutWithChange_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -5263,14 +5323,15 @@ void registerBtcTransaction_withPegoutWithChange_shouldRegisterChangeInActiveFed signAndRegisterReleaseTransaction( pegout, segwitActiveFederation, - segwitActiveFederationKeys + segwitActiveFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( pegout, segwitActiveFederation, - BTC_BLOCK_WITH_RELEASE_HEIGHT + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); assertReleaseWasRegistered( @@ -5297,7 +5358,8 @@ void registerBtcTransaction_withPegoutWithoutChange_shouldNotRegister() throws B signAndRegisterReleaseTransaction( pegout, segwitActiveFederation, - segwitActiveFederationKeys + segwitActiveFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert @@ -5308,7 +5370,7 @@ void registerBtcTransaction_withPegoutWithoutChange_shouldNotRegister() throws B } @Test - void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_shouldMarkAsProcessedWithoutRegisteringUtxos() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_withinGracePeriod_shouldMarkAsProcessedWithoutRegisteringUtxos() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange // before RSKIP643 the pegout sighash is saved in the pegout index, even when the pegout has no change // requesting the whole input value leaves no change @@ -5320,7 +5382,8 @@ void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_shouldMarkA signAndRegisterReleaseTransaction( pegout, segwitActiveFederation, - segwitActiveFederationKeys + segwitActiveFederationKeys, + BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT ); // assert @@ -5334,9 +5397,10 @@ void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_shouldMarkA } @Test - void registerBtcTransaction_withPegoutCreatedForVetiver_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_afterGracePeriod_shouldNotRegister() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange // before RSKIP643 the pegout sighash is saved in the pegout index instead of its change as federations pending utxos + // requesting the whole input value leaves no change BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); assertNotPendingUtxos(pegout); setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); @@ -5345,26 +5409,15 @@ void registerBtcTransaction_withPegoutCreatedForVetiver_shouldRegisterChangeInAc signAndRegisterReleaseTransaction( pegout, segwitActiveFederation, - segwitActiveFederationKeys + segwitActiveFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert - List expectedUtxosRegistered = buildExpectedUtxosRegistered( - pegout, - segwitActiveFederation, - BTC_BLOCK_WITH_RELEASE_HEIGHT - ); - assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); - assertReleaseWasRegistered( - bridgeStorageProvider, - federationSupport, - logs, - (int) rskExecutionBlock.getNumber(), - pegout, - List.of(CHANGE_VALUE), - List.of(OUTPUT_INDEX_FOR_PEGOUT_CHANGE), - segwitActiveFederation.getAddress() - ); + // the pegout index is no longer looked up, and with no output to the live federations the pegout is unknown + assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); + assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(pegout.getHash()).isEmpty()); + assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); } @Test @@ -5379,14 +5432,15 @@ void registerBtcTransaction_withPegoutToActiveFed_afterChangingToRetiringFed_sho signAndRegisterReleaseTransaction( pegout, segwitActiveFederation, - segwitActiveFederationKeys + segwitActiveFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( pegout, segwitActiveFederation, - BTC_BLOCK_WITH_RELEASE_HEIGHT + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getRetiringFederationBtcUTXOs()); assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); @@ -5414,7 +5468,8 @@ void registerBtcTransaction_withPegoutToActiveFed_afterChangingToRetiredFed_shou signAndRegisterReleaseTransaction( pegout, segwitActiveFederation, - segwitActiveFederationKeys + segwitActiveFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert @@ -5442,7 +5497,7 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran PartialMerkleTree pmtWithWitness = buildPMTAndRecreateChainForSegwitTransactionRegistration( bridgeStorageProvider, bridgeMainnetConstants, - BTC_BLOCK_WITH_RELEASE_HEIGHT, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, pegout, btcBlockStore ); @@ -5450,7 +5505,7 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran PartialMerkleTree pmtWithTxId = createValidPmtForTransactionsHashes(List.of(pegout.getHash()), btcMainnetParams); bridgeSupport.registerPegoutTransaction( pegout.getHash(), - BTC_BLOCK_WITH_RELEASE_HEIGHT, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, pmtWithTxId.bitcoinSerialize() ); bridgeSupport.save(); @@ -5465,7 +5520,7 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran bridgeSupport.registerBtcTransaction( rskTx, pegout.bitcoinSerialize(), - BTC_BLOCK_WITH_RELEASE_HEIGHT, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, pmtWithWitness.bitcoinSerialize() ); bridgeSupport.save(); @@ -5477,6 +5532,54 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran assertArrayEquals(repositoryRootAfterFirstRegistration, repository.getRoot()); } + @Test + void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_withinGracePeriod_shouldRegisterMigratedUtxosInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + // before RSKIP643 the migration sighash is saved in the pegout index instead of its outputs as federations pending utxos + BtcTransaction migrationTransaction = createMigrationForVetiverFromRetiringFedToActiveFed(); + assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(migrationTransaction.getHash())); + setUpBridgeAndFederationSupport(MIGRATION_REGISTRATION_BLOCK_NUMBER); + + // act + signAndRegisterReleaseTransaction( + migrationTransaction, + retiringFederation, + retiringFederationKeys, + BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + ); + + // assert + assertEquals(1, migrationTransaction.getOutputs().size()); + assertMigrationWasRegisteredInActiveFed( + migrationTransaction, + List.of(0L), + BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + ); + } + + @Test + void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_afterGracePeriod_shouldRejectAsUnrefundablePegin() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + BtcTransaction migrationTransaction = createMigrationForVetiverFromRetiringFedToActiveFed(); + assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(migrationTransaction.getHash())); + setUpBridgeAndFederationSupport(MIGRATION_REGISTRATION_BLOCK_NUMBER); + + // act + signAndRegisterReleaseTransaction( + migrationTransaction, + retiringFederation, + retiringFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + ); + + // assert + // the pegout index is no longer looked up, so the migrated funds are evaluated as a legacy pegin + assertEquals(1, migrationTransaction.getOutputs().size()); + assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); + assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); + assertReleaseWasRejectedAsUnrefundablePegin(migrationTransaction); + } + @Test void registerBtcTransaction_withMigrationWithOneOutput_shouldRegisterMigratedUtxosInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -5487,14 +5590,16 @@ void registerBtcTransaction_withMigrationWithOneOutput_shouldRegisterMigratedUtx signAndRegisterReleaseTransaction( migrationTransaction, retiringFederation, - retiringFederationKeys + retiringFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert assertEquals(1, migrationTransaction.getOutputs().size()); assertMigrationWasRegisteredInActiveFed( migrationTransaction, - List.of(0L) + List.of(0L), + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); } @@ -5508,14 +5613,16 @@ void registerBtcTransaction_withMigrationWithFixedValueOutputs_shouldRegisterMig signAndRegisterReleaseTransaction( migrationTransaction, retiringFederation, - retiringFederationKeys + retiringFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert assertEquals(FIXED_VALUE_MIGRATION_OUTPUTS, migrationTransaction.getOutputs().size()); assertMigrationWasRegisteredInActiveFed( migrationTransaction, - List.of(0L, 1L, 2L) + List.of(0L, 1L, 2L), + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); } @@ -5530,7 +5637,8 @@ void registerBtcTransaction_withMigrationWithEvenlyDistributedOutputs_withMaximu signAndRegisterReleaseTransaction( migrationTransaction, retiringFederation, - retiringFederationKeys + retiringFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert @@ -5541,7 +5649,8 @@ void registerBtcTransaction_withMigrationWithEvenlyDistributedOutputs_withMaximu .toList(); assertMigrationWasRegisteredInActiveFed( migrationTransaction, - expectedOutputIndexes + expectedOutputIndexes, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); } @@ -5608,7 +5717,16 @@ private BtcTransaction createMigrationFromRetiringFedToActiveFed(Coin retiringFe .withValue(retiringFederationBalance) .withScriptPubKey(retiringFederation.getP2SHScript()) .build(); - return createMigrationSpendingRetiringFedUtxos(List.of(retiringFederationUtxo)); + return createMigrationWithActivationsSpendingRetiringFedUtxos(allActivations, List.of(retiringFederationUtxo)); + } + + private BtcTransaction createMigrationForVetiverFromRetiringFedToActiveFed() throws IOException { + UTXO retiringFederationUtxo = UTXOBuilder.builder() + .withTransactionHash(BitcoinTestUtils.createHash(3)) + .withValue(INPUT_VALUE) + .withScriptPubKey(retiringFederation.getP2SHScript()) + .build(); + return createMigrationWithActivationsSpendingRetiringFedUtxos(vetiver900Activations, List.of(retiringFederationUtxo)); } private BtcTransaction createMigrationWithMaximumInputsFromRetiringFedToActiveFed() throws IOException { @@ -5616,15 +5734,16 @@ private BtcTransaction createMigrationWithMaximumInputsFromRetiringFedToActiveFe .withValue(EVENLY_DISTRIBUTED_MIGRATION_RETIRING_FEDERATION_UTXO_VALUE) .withScriptPubKey(retiringFederation.getP2SHScript()) .buildMany(MAXIMUM_MIGRATION_INPUTS, i -> BitcoinTestUtils.createHash(i + 1)); - return createMigrationSpendingRetiringFedUtxos(retiringFederationUtxos); + return createMigrationWithActivationsSpendingRetiringFedUtxos(allActivations, retiringFederationUtxos); } - private BtcTransaction createMigrationSpendingRetiringFedUtxos(List retiringFederationUtxos) throws IOException { - setUpBridgeAndFederationSupport(MIGRATION_CREATION_BLOCK_NUMBER); + private BtcTransaction createMigrationWithActivationsSpendingRetiringFedUtxos(ForBlock activations, List retiringFederationUtxos) throws IOException { + setUpBridgeAndFederationSupportWithActivations(MIGRATION_CREATION_BLOCK_NUMBER, activations); federationStorageProvider.setOldFederation(retiringFederation); federationStorageProvider.getOldFederationBtcUTXOs().addAll(retiringFederationUtxos); // with the migration ongoing, migrates the retiring federation funds, storing the migrated outputs as federations pending utxos + // after RSKIP643, or the migration sighash in the pegout index before it bridgeSupport.updateCollections(updateCollectionsTransaction); return getReleaseFromPegoutsWFC(bridgeStorageProvider); @@ -5632,12 +5751,13 @@ private BtcTransaction createMigrationSpendingRetiringFedUtxos(List retiri private void assertMigrationWasRegisteredInActiveFed( BtcTransaction migrationTransaction, - List expectedOutputIndexes + List expectedOutputIndexes, + int btcBlockWithReleaseHeight ) throws IOException { List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTransaction, segwitActiveFederation, - BTC_BLOCK_WITH_RELEASE_HEIGHT + btcBlockWithReleaseHeight ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); List migratedValues = migrationTransaction.getOutputs().stream() @@ -5655,10 +5775,22 @@ private void assertMigrationWasRegisteredInActiveFed( ); } + private void assertReleaseWasRejectedAsUnrefundablePegin(BtcTransaction rejectedRelease) throws IOException { + // the redeem script of a p2sh-p2wsh erp federation is not a plain multisig, so the sender can't be determined + assertLogRejectedPegin(logs, rejectedRelease, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); + assertLogNonRefundablePegin(logs, rejectedRelease, LEGACY_PEGIN_UNDETERMINED_SENDER); + assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(rejectedRelease.getHash()).isEmpty()); + boolean anyReleaseSpendsRejectedRelease = bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries(allActivations).stream() + .map(PegoutsWaitingForConfirmations.Entry::getBtcTransaction) + .anyMatch(release -> release.getInput(FIRST_INPUT_INDEX).getOutpoint().getHash().equals(rejectedRelease.getHash())); + assertFalse(anyReleaseSpendsRejectedRelease); + } + private void signAndRegisterReleaseTransaction( BtcTransaction releaseTransaction, Federation signingFederation, - List signingFederationKeys + List signingFederationKeys, + int btcBlockWithReleaseHeight ) throws BlockStoreException, BridgeIllegalArgumentException, IOException { signInputs( signingFederation, @@ -5668,7 +5800,7 @@ private void signAndRegisterReleaseTransaction( PartialMerkleTree pmtWithWitness = buildPMTAndRecreateChainForSegwitTransactionRegistration( bridgeStorageProvider, bridgeMainnetConstants, - BTC_BLOCK_WITH_RELEASE_HEIGHT, + btcBlockWithReleaseHeight, releaseTransaction, btcBlockStore ); @@ -5676,7 +5808,7 @@ private void signAndRegisterReleaseTransaction( bridgeSupport.registerBtcTransaction( rskTx, releaseTransaction.bitcoinSerialize(), - BTC_BLOCK_WITH_RELEASE_HEIGHT, + btcBlockWithReleaseHeight, pmtWithWitness.bitcoinSerialize() ); bridgeSupport.save(); From 3a504d1c01ad01637ffa42017dec0f383c835383 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Wed, 21 Oct 2026 20:37:51 -0300 Subject: [PATCH 04/23] refactor: register svp test transactions after the grace period when RSKIP643 is active --- .../java/co/rsk/peg/BridgeSupportSvpTest.java | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) 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 d983a2821b8..43527fb708d 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -70,6 +70,12 @@ class BridgeSupportSvpTest { private static final RskAddress bridgeContractAddress = PrecompiledContracts.BRIDGE_ADDR; private static final BridgeConstants bridgeMainNetConstants = BridgeMainNetConstants.getInstance(); private static final NetworkParameters btcMainnetParams = bridgeMainNetConstants.getBtcParams(); + // releases created before RSKIP643 are identified through the pegout index from this height on + private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = bridgeMainNetConstants.getBtcHeightWhenPegoutTxIndexActivates() + + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); + // past the grace period, so releases created before RSKIP643 are no longer looked up in the pegout index + private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainNetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); private static final FederationConstants federationMainNetConstants = bridgeMainNetConstants.getFederationConstants(); private static final List svpFundTxOutpointsValues = Arrays.asList( Coin.valueOf(1_000_000), @@ -881,7 +887,7 @@ void registerBtcTransaction_forNormalPegout_whenSvpPeriodIsOngoing_forVetiver_sh .build(); savePegoutIndex(pegout); - setUpForTransactionRegistration(pegout); + setUpForTransactionRegistration(pegout, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); setUpBridgeSupportForVetiver(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -919,7 +925,7 @@ void registerBtcTransaction_forNormalPegout_whenSvpPeriodIsOngoing_shouldRegiste FEDERATIONS_PENDING_UTXO_HEIGHT ); federationSupport.storeFederationsPendingBtcUTXOs(pegout.getHash(), pegoutChangeUtxos); - setUpForTransactionRegistration(pegout); + setUpForTransactionRegistration(pegout, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -946,7 +952,7 @@ void registerBtcTransaction_forSvpFundTransactionWithoutChangeOutput_whenSvpPeri saveSvpFundTransactionHashUnsigned(svpFundTransaction.getHash()); signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); - setUpForTransactionRegistration(svpFundTransaction); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -965,7 +971,7 @@ void registerBtcTransaction_forSvpFundTransactionWithoutChangeOutput_whenSvpPeri saveSvpFundTransactionUnsignedForVetiver(); signInputs(activeFederation, activeFederationKeys, svpFundTransaction); - setUpForTransactionRegistration(svpFundTransaction); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); setUpBridgeSupportForVetiver(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1015,7 +1021,7 @@ void registerBtcTransaction_forSvpFundTransactionChange_withFundTxCreatedBeforeR signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); // and it is registered after RSKIP643 - setUpForTransactionRegistration(svpFundTransaction); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -1032,14 +1038,14 @@ private void arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered() assertTrue(federationSupport.hasFederationsPendingBtcUTXOs(svpFundTransaction.getHash())); signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); - setUpForTransactionRegistration(svpFundTransaction); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); } private void arrangeSvpFundTransactionToBeRegisteredForVetiver() throws BlockStoreException { arrangeSvpFundTransactionUnsignedForVetiver(); signInputs(activeFederation, activeFederationKeys, svpFundTransaction); - setUpForTransactionRegistration(svpFundTransaction); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); setUpBridgeSupportForVetiver(); } @@ -1402,7 +1408,7 @@ class SpendTxRegistrationTests { void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_forVetiver_shouldProcessAndRegisterPegout_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); BtcTransaction pegout = PegoutTransactionBuilder.builder() .withActiveFederation(activeFederation) @@ -1412,7 +1418,7 @@ void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_forVetiver_should .build(); savePegoutIndex(pegout); - setUpForTransactionRegistration(pegout); + setUpForTransactionRegistration(pegout, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); setUpBridgeSupportForVetiver(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1450,7 +1456,7 @@ void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_shouldProcessAndR // arrange setupSegwitActiveFederationWithUtxos(); arrangeSvpSpendTransactionFromSegwitActiveFederation(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); BtcTransaction pegout = PegoutTransactionBuilder.builder() .withActiveFederation(segwitActiveFederation) @@ -1465,7 +1471,7 @@ void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_shouldProcessAndR FEDERATIONS_PENDING_UTXO_HEIGHT ); federationSupport.storeFederationsPendingBtcUTXOs(pegout.getHash(), pegoutChangeUtxos); - setUpForTransactionRegistration(pegout); + setUpForTransactionRegistration(pegout, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1502,7 +1508,7 @@ void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_shouldProcessAndR void registerBtcTransaction_forLegacyPeginFromP2pkh_whenWaitingForSvpSpendTx_shouldProcessAndRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); BtcECKey senderPubKey = getBtcEcKeyFromSeed("legacy_pegin_sender"); @@ -1510,7 +1516,7 @@ void registerBtcTransaction_forLegacyPeginFromP2pkh_whenWaitingForSvpSpendTx_sho pegin.addInput(BitcoinTestUtils.createHash(1), 0, scriptSig); Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin); + setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); @@ -1560,7 +1566,7 @@ void registerBtcTransaction_forLegacyPeginFromP2pkh_whenWaitingForSvpSpendTx_sho void registerBtcTransaction_forLegacyPeginFromP2shP2wpkh_whenWaitingForSvpSpendTx_shouldProcessAndRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); BtcECKey senderPubKey = getBtcEcKeyFromSeed("legacy_pegin_p2shp2wpkh_sender"); @@ -1578,7 +1584,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wpkh_whenWaitingForSvpSpendT Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin); + setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); @@ -1628,7 +1634,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wpkh_whenWaitingForSvpSpendT void registerBtcTransaction_forLegacyPeginFromP2shMultisig_whenWaitingForSvpSpendTx_shouldProcessButNotRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); List pubKeys = Arrays.asList( @@ -1641,7 +1647,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shMultisig_whenWaitingForSvpSpen Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin); + setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); @@ -1692,7 +1698,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shMultisig_whenWaitingForSvpSpen void registerBtcTransaction_forLegacyPeginFromP2shP2wsh_whenWaitingForSvpSpendTx_shouldProcessButNotRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); List pubKeys = Arrays.asList( @@ -1714,7 +1720,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wsh_whenWaitingForSvpSpendTx Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin); + setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); @@ -1765,7 +1771,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wsh_whenWaitingForSvpSpendTx void registerBtcTransaction_forPeginV1_whenWaitingForSvpSpendTx_shouldProcessAndRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException, PeginInstructionsException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); BtcECKey senderPubKey = getBtcEcKeyFromSeed("legacy_pegin_sender"); @@ -1775,7 +1781,7 @@ void registerBtcTransaction_forPeginV1_whenWaitingForSvpSpendTx_shouldProcessAnd pegin.addOutput(amountToSend, activeFederation.getAddress()); Script opReturnScript = PegTestUtils.createOpReturnScriptForRsk(1, bridgeContractAddress, Optional.empty()); pegin.addOutput(Coin.ZERO, opReturnScript); - setUpForTransactionRegistration(pegin); + setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // recreate bridge support with real btcLockSenderProvider and peginInstructionsProvider instead of a mock to be able to parse pegin v1 BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); @@ -1832,7 +1838,7 @@ void registerBtcTransaction_forPeginV1_whenWaitingForSvpSpendTx_shouldProcessAnd void registerBtcTransaction_whenSpendTransactionHashIsNotSaved_shouldBeIdentifiedAsRejectedPeginAndMarkAsProcessed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange recreateSvpSpendTransactionUnsigned(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1866,7 +1872,7 @@ private void assertProposedFederationExists() { void registerBtcTransaction_whenIsTheSpendTransaction_shouldProcessSpendTxAndSvpSuccess() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1888,7 +1894,7 @@ void registerBtcTransaction_whenIsTheSpendTransaction_shouldProcessSpendTxAndSvp void registerBtcTransaction_whenIsTheSpendTransaction_forVetiver_shouldRegisterSpendTxUtxoWithZeroHeight() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); bridgeSupport = bridgeSupportBuilder .withActivations(vetiverActivations) .build(); @@ -1915,7 +1921,7 @@ void registerBtcTransaction_evenIfValidationPeriodEnded_shouldRegisterSpendTxAnd arrangeExecutionBlockIsAfterValidationPeriodEnded(); arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1943,7 +1949,7 @@ void registerBtcTransaction_whenIsTheSpendTransaction_withAmountBelowMinPeginVal addSpendTransactionOutput(amountToSend); saveSvpSpendTransactionValues(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1965,7 +1971,7 @@ void registerBtcTransaction_whenIsTheSpendTransaction_withAmountBelowMinPeginVal void registerBtcTransaction_twice_whenIsTheSpendTransaction_shouldRegisterItJustOnce() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -2235,13 +2241,13 @@ private void saveSvpSpendTransactionValues() { bridgeStorageProvider.save(); } - private void setUpForTransactionRegistration(BtcTransaction transaction) throws BlockStoreException { + private void setUpForTransactionRegistration(BtcTransaction transaction, int btcBlockWithTransactionHeight) throws BlockStoreException { // recreate a valid chain that has the tx, so it passes the previous checks in registerBtcTransaction BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(btcMainnetParams, 100, 100); BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainNetConstants, bridgeStorageProvider, allActivations); pmtWithTransactions = createValidPmtForTransactions(List.of(transaction), btcMainnetParams); - btcBlockWithPmtHeight = bridgeMainNetConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); // we want pegout tx index to be activated + btcBlockWithPmtHeight = btcBlockWithTransactionHeight; int chainHeight = btcBlockWithPmtHeight + bridgeMainNetConstants.getBtc2RskMinimumAcceptableConfirmations(); recreateChainFromPmt(btcBlockStoreWithCache, chainHeight, pmtWithTransactions, btcBlockWithPmtHeight, btcMainnetParams); From 5d08155a65b2dcd9a819bea01c2d34e41bd14704 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Wed, 21 Oct 2026 20:43:12 -0300 Subject: [PATCH 05/23] test: cover svp fund tx created for vetiver registered within and after the grace period once its svp values were cleared --- .../java/co/rsk/peg/BridgeSupportSvpTest.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) 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 43527fb708d..9a56d04d58d 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -16,6 +16,7 @@ import static co.rsk.peg.federation.FederationStorageIndexKey.NEW_FEDERATION_BTC_UTXOS_KEY; import static co.rsk.peg.federation.FederationTestUtils.signInputs; import static co.rsk.peg.pegin.RejectedPeginReason.INVALID_AMOUNT; +import static co.rsk.peg.pegin.RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -76,6 +77,8 @@ class BridgeSupportSvpTest { // past the grace period, so releases created before RSKIP643 are no longer looked up in the pegout index private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainNetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); + // still past the pegout index start, and releases created before RSKIP643 are still looked up in it + private static final int HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - 1; private static final FederationConstants federationMainNetConstants = bridgeMainNetConstants.getFederationConstants(); private static final List svpFundTxOutpointsValues = Arrays.asList( Coin.valueOf(1_000_000), @@ -874,6 +877,42 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared assertSvpFundTxChangeWasRegisteredForVetiver(activeFederationUtxosBeforeRegisteringTx); } + @Test + void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForVetiver_withinGracePeriod_shouldRegisterChangeUtxo() throws Exception { + // arrange + arrangeExecutionBlockIsAfterValidationPeriodEnded(); + arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + arrangeSvpValuesWereClearedAfterValidationPeriodEnded(); + List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); + + // act + registerBtcTransaction(svpFundTransaction); + + // assert + assertSvpFundTxChangeWasRegisteredInSegwitActiveFederation(activeFederationUtxosBeforeRegisteringTx); + } + + @Test + void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForVetiver_afterGracePeriod_shouldRejectAsUnrefundablePegin() throws Exception { + // arrange + arrangeExecutionBlockIsAfterValidationPeriodEnded(); + arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + arrangeSvpValuesWereClearedAfterValidationPeriodEnded(); + List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); + + // act + registerBtcTransaction(svpFundTransaction); + + // assert + // the pegout index is no longer looked up, so the change sent from the federation is evaluated as a legacy pegin, + // and since the redeem script of a p2sh-p2wsh erp federation is not a plain multisig, the sender can't be determined + assertLogRejectedPegin(logs, svpFundTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER); + assertLogNonRefundablePegin(logs, svpFundTransaction, NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); + assertUtxosAreEqual(activeFederationUtxosBeforeRegisteringTx, federationSupport.getActiveFederationBtcUTXOs()); + assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); + assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(svpFundTransaction.getHash()).isEmpty()); + } + @Test void registerBtcTransaction_forNormalPegout_whenSvpPeriodIsOngoing_forVetiver_shouldRegisterTransactionButNotUpdateSvpFundTransactionValues() throws Exception { // arrange @@ -1041,6 +1080,16 @@ private void arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered() setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); } + private void arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(int btcBlockWithTransactionHeight) throws BlockStoreException { + setupSegwitActiveFederationWithUtxos(); + arrangeSvpFundTransactionUnsignedForVetiver(); + assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(svpFundTransaction.getHash())); + + signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); + // and it is registered after RSKIP643 + setUpForTransactionRegistration(svpFundTransaction, btcBlockWithTransactionHeight); + } + private void arrangeSvpFundTransactionToBeRegisteredForVetiver() throws BlockStoreException { arrangeSvpFundTransactionUnsignedForVetiver(); From 8205bd3c11a7c53cd0b287864caeabca0d38daa9 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Wed, 21 Oct 2026 21:31:03 -0300 Subject: [PATCH 06/23] refactor: build grace period release transactions with the pegout and migration builders --- .../test/java/co/rsk/peg/PegUtilsTest.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java index e75437ce75b..0efbe978d2d 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java @@ -14,6 +14,8 @@ import co.rsk.peg.bitcoin.BitcoinUtils; import co.rsk.peg.federation.*; import co.rsk.peg.federation.constants.FederationConstants; +import co.rsk.test.builders.MigrationTransactionBuilder; +import co.rsk.test.builders.PegoutTransactionBuilder; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; @@ -972,29 +974,22 @@ private void setUpBridgeStorageProvider(ActivationConfig.ForBlock activations) { } private BtcTransaction buildPegoutWithChangeFromActiveFed() { - BtcTransaction pegout = new BtcTransaction(btcMainnetParams); - pegout.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); - addSpendingFederationBaseScript(pegout, activeFederation); - pegout.addOutput(Coin.COIN, userAddress); - pegout.addOutput(Coin.COIN, activeFederation.getAddress()); - return pegout; + return PegoutTransactionBuilder.builder() + .withNetworkParameters(btcMainnetParams) + .withActiveFederation(activeFederation) + .withInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, Coin.COIN) + .withOutput(Coin.COIN, userAddress) + .withChangeAmount(Coin.COIN) + .build(); } private BtcTransaction buildMigrationTransaction() { - BtcTransaction migration = new BtcTransaction(btcMainnetParams); - migration.addInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, new Script(new byte[]{})); - addSpendingFederationBaseScript(migration, retiringFederation); - migration.addOutput(Coin.COIN, activeFederation.getAddress()); - return migration; - } - - private void addSpendingFederationBaseScript(BtcTransaction releaseTransaction, Federation spendingFederation) { - BitcoinUtils.addSpendingFederationBaseScript( - releaseTransaction, - FIRST_INPUT_INDEX, - spendingFederation.getRedeemScript(), - spendingFederation.getFormatVersion() - ); + return MigrationTransactionBuilder.builder() + .withNetworkParameters(btcMainnetParams) + .withRetiringFederation(retiringFederation) + .withActiveFederation(activeFederation) + .withOutput(Coin.COIN) + .build(); } private void savePegoutSigHashInPegoutIndex(BtcTransaction releaseTransaction) { From 95878f40fc8c1a655e6b7d42db48dd2193860e43 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 09:22:17 -0300 Subject: [PATCH 07/23] refactor: test the federations pending btc utxos grace period through getTransactionType --- .../peg/PegUtilsGetTransactionTypeTest.java | 201 ++++++++++++++++++ .../test/java/co/rsk/peg/PegUtilsTest.java | 187 ---------------- 2 files changed, 201 insertions(+), 187 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java index 9b54bd5f9cb..94ce0adad68 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java @@ -39,6 +39,8 @@ import co.rsk.peg.federation.constants.FederationConstants; import co.rsk.peg.storage.InMemoryStorage; import co.rsk.peg.storage.StorageAccessor; +import co.rsk.test.builders.MigrationTransactionBuilder; +import co.rsk.test.builders.PegoutTransactionBuilder; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -2547,4 +2549,203 @@ private static Stream activeAndRetiringFeds() { ); } } + + @Nested + class FederationsPendingBtcUTXOsGracePeriod { + private static final ActivationConfig.ForBlock allActivations = ActivationConfigsForTest.all().forBlock(0); + private static final ActivationConfig.ForBlock vetiverActivations = ActivationConfigsForTest.vetiver900().forBlock(0); + private static final int HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + + bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); + // while in the grace period, releases created before RSKIP643 are still looked up in the pegout index + private static final int HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - 1; + + private BridgeStorageProvider bridgeStorageProvider; + + @BeforeEach + void setUp() { + activeFederation = P2shP2wshErpFederationBuilder.builder().build(); + } + + @Test + void getTransactionType_withPegoutInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(vetiverActivations); + FederationContext activeFederationContext = FederationContext.builder() + .withActiveFederation(activeFederation) + .build(); + BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); + savePegoutSigHashInPegoutIndex(pegout); + + // act + PegTxType pegTxType = PegUtils.getTransactionType( + vetiverActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + activeFederationContext, + pegout, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withPegoutInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(allActivations); + FederationContext activeFederationContext = FederationContext.builder() + .withActiveFederation(activeFederation) + .build(); + BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); + savePegoutSigHashInPegoutIndex(pegout); + + // act + PegTxType pegTxType = PegUtils.getTransactionType( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + activeFederationContext, + pegout, + HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + ); + + // assert + assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withPegoutInPegoutIndex_afterGracePeriod_shouldBePegin() { + // arrange + setUpBridgeStorageProvider(allActivations); + FederationContext activeFederationContext = FederationContext.builder() + .withActiveFederation(activeFederation) + .build(); + BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); + savePegoutSigHashInPegoutIndex(pegout); + + // act + PegTxType pegTxType = PegUtils.getTransactionType( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + activeFederationContext, + pegout, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PegTxType.PEGIN, pegTxType); + } + + @Test + void getTransactionType_withMigrationInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(vetiverActivations); + FederationContext activeAndRetiringFederationContext = FederationContext.builder() + .withActiveFederation(activeFederation) + .withRetiringFederation(retiringFederation) + .build(); + BtcTransaction migration = buildMigrationTransaction(); + savePegoutSigHashInPegoutIndex(migration); + + // act + PegTxType pegTxType = PegUtils.getTransactionType( + vetiverActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + activeAndRetiringFederationContext, + migration, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withMigrationInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { + // arrange + setUpBridgeStorageProvider(allActivations); + FederationContext activeAndRetiringFederationContext = FederationContext.builder() + .withActiveFederation(activeFederation) + .withRetiringFederation(retiringFederation) + .build(); + BtcTransaction migration = buildMigrationTransaction(); + savePegoutSigHashInPegoutIndex(migration); + + // act + PegTxType pegTxType = PegUtils.getTransactionType( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + activeAndRetiringFederationContext, + migration, + HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + ); + + // assert + assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); + } + + @Test + void getTransactionType_withMigrationInPegoutIndex_afterGracePeriod_shouldBePegin() { + // arrange + setUpBridgeStorageProvider(allActivations); + FederationContext activeAndRetiringFederationContext = FederationContext.builder() + .withActiveFederation(activeFederation) + .withRetiringFederation(retiringFederation) + .build(); + BtcTransaction migration = buildMigrationTransaction(); + savePegoutSigHashInPegoutIndex(migration); + + // act + PegTxType pegTxType = PegUtils.getTransactionType( + allActivations, + bridgeStorageProvider, + bridgeMainnetConstants, + activeAndRetiringFederationContext, + migration, + HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS + ); + + // assert + assertEquals(PegTxType.PEGIN, pegTxType); + } + + private void setUpBridgeStorageProvider(ActivationConfig.ForBlock activations) { + bridgeStorageProvider = new BridgeStorageProvider( + createRepository(), + btcMainnetParams, + activations + ); + } + + private BtcTransaction buildPegoutWithChangeFromActiveFed() { + return PegoutTransactionBuilder.builder() + .withNetworkParameters(btcMainnetParams) + .withActiveFederation(activeFederation) + .withInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, Coin.COIN) + .withOutput(Coin.COIN, userAddress) + .withChangeAmount(Coin.COIN) + .build(); + } + + private BtcTransaction buildMigrationTransaction() { + return MigrationTransactionBuilder.builder() + .withNetworkParameters(btcMainnetParams) + .withRetiringFederation(retiringFederation) + .withActiveFederation(activeFederation) + .withOutput(Coin.COIN) + .build(); + } + + private void savePegoutSigHashInPegoutIndex(BtcTransaction releaseTransaction) { + // the same sighash the bridge saves in the pegout index when creating the release + Sha256Hash pegoutTxSigHash = BitcoinUtils.getSigHashForPegoutIndex(releaseTransaction).orElseThrow(); + bridgeStorageProvider.setPegoutTxSigHash(pegoutTxSigHash); + // the sighash is only buffered until saved, while the lookup reads it from the repository + bridgeStorageProvider.save(); + } + } } diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java index 0efbe978d2d..245cc0b6e6d 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java @@ -11,16 +11,12 @@ import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import co.rsk.peg.bitcoin.BitcoinTestUtils; -import co.rsk.peg.bitcoin.BitcoinUtils; import co.rsk.peg.federation.*; import co.rsk.peg.federation.constants.FederationConstants; -import co.rsk.test.builders.MigrationTransactionBuilder; -import co.rsk.test.builders.PegoutTransactionBuilder; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import java.time.Instant; import java.util.Arrays; @@ -45,7 +41,6 @@ class PegUtilsTest { private static final FederationConstants federationMainNetConstants = bridgeMainnetConstants.getFederationConstants(); private static final Context context = new Context(bridgeMainnetConstants.getBtcParams()); private static final ActivationConfig.ForBlock allActivations = ActivationConfigsForTest.all().forBlock(0); - private static final ActivationConfig.ForBlock vetiverActivations = ActivationConfigsForTest.vetiver900().forBlock(0); private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = bridgeMainnetConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); @@ -818,186 +813,4 @@ void isTheSvpFundTxHashUnsigned_whenHashDoesNotMatchSvpFundTxHashUnsigned_should // Assert assertFalse(isTheSvpFundTransaction); } - - @Nested - class FederationsPendingBtcUTXOsGracePeriod { - private static final int HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() - + bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); - // while in the grace period, releases created before RSKIP643 are still looked up in the pegout index - private static final int HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - 1; - - private BridgeStorageProvider bridgeStorageProvider; - - @BeforeEach - void setUp() { - activeFederation = P2shP2wshErpFederationBuilder.builder().build(); - } - - @Test - void getTransactionType_withPegoutInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(vetiverActivations); - Wallet liveFederationWallet = new BridgeBtcWallet(context, Collections.singletonList(activeFederation)); - BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); - savePegoutSigHashInPegoutIndex(pegout); - - // act - PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - vetiverActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - liveFederationWallet, - pegout, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withPegoutInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(allActivations); - Wallet liveFederationWallet = new BridgeBtcWallet(context, Collections.singletonList(activeFederation)); - BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); - savePegoutSigHashInPegoutIndex(pegout); - - // act - PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - liveFederationWallet, - pegout, - HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - ); - - // assert - assertEquals(PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withPegoutInPegoutIndex_afterGracePeriod_shouldBePegin() { - // arrange - setUpBridgeStorageProvider(allActivations); - Wallet liveFederationWallet = new BridgeBtcWallet(context, Collections.singletonList(activeFederation)); - BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); - savePegoutSigHashInPegoutIndex(pegout); - - // act - PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - liveFederationWallet, - pegout, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PEGIN, pegTxType); - } - - @Test - void getTransactionType_withMigrationInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(vetiverActivations); - Wallet liveFederationWallet = new BridgeBtcWallet(context, Arrays.asList(retiringFederation, activeFederation)); - BtcTransaction migration = buildMigrationTransaction(); - savePegoutSigHashInPegoutIndex(migration); - - // act - PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - vetiverActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - liveFederationWallet, - migration, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withMigrationInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(allActivations); - Wallet liveFederationWallet = new BridgeBtcWallet(context, Arrays.asList(retiringFederation, activeFederation)); - BtcTransaction migration = buildMigrationTransaction(); - savePegoutSigHashInPegoutIndex(migration); - - // act - PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - liveFederationWallet, - migration, - HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - ); - - // assert - assertEquals(PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withMigrationInPegoutIndex_afterGracePeriod_shouldBePegin() { - // arrange - setUpBridgeStorageProvider(allActivations); - Wallet liveFederationWallet = new BridgeBtcWallet(context, Arrays.asList(retiringFederation, activeFederation)); - BtcTransaction migration = buildMigrationTransaction(); - savePegoutSigHashInPegoutIndex(migration); - - // act - PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - liveFederationWallet, - migration, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PEGIN, pegTxType); - } - - private void setUpBridgeStorageProvider(ActivationConfig.ForBlock activations) { - bridgeStorageProvider = new BridgeStorageProvider( - RskTestUtils.createRepository(), - btcMainnetParams, - activations - ); - } - - private BtcTransaction buildPegoutWithChangeFromActiveFed() { - return PegoutTransactionBuilder.builder() - .withNetworkParameters(btcMainnetParams) - .withActiveFederation(activeFederation) - .withInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, Coin.COIN) - .withOutput(Coin.COIN, userAddress) - .withChangeAmount(Coin.COIN) - .build(); - } - - private BtcTransaction buildMigrationTransaction() { - return MigrationTransactionBuilder.builder() - .withNetworkParameters(btcMainnetParams) - .withRetiringFederation(retiringFederation) - .withActiveFederation(activeFederation) - .withOutput(Coin.COIN) - .build(); - } - - private void savePegoutSigHashInPegoutIndex(BtcTransaction releaseTransaction) { - // the same sighash the bridge saves in the pegout index when creating the release - Sha256Hash pegoutTxSigHash = BitcoinUtils.getSigHashForPegoutIndex(releaseTransaction).orElseThrow(); - bridgeStorageProvider.setPegoutTxSigHash(pegoutTxSigHash); - // the sighash is only buffered until saved, while the lookup reads it from the repository - bridgeStorageProvider.save(); - } - } } From 79338aaa55f02cd296b6adbf909240b9ebc674f6 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 09:25:22 -0300 Subject: [PATCH 08/23] refactor: reuse the svp fund transaction created for vetiver arrange helper --- .../src/test/java/co/rsk/peg/BridgeSupportSvpTest.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) 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 9a56d04d58d..949f0c1a808 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -1053,14 +1053,7 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpPeriodIsOngoing_s @Test void registerBtcTransaction_forSvpFundTransactionChange_withFundTxCreatedBeforeRSKIP643_shouldRegisterTransactionAndUpdateSvpFundTransactionValues() throws Exception { // arrange - setupSegwitActiveFederationWithUtxos(); - // the fund tx was created before RSKIP643, so its pegout index was saved instead of its pending utxos - arrangeSvpFundTransactionUnsignedForVetiver(); - assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(svpFundTransaction.getHash())); - - signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); - // and it is registered after RSKIP643 - setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -1082,6 +1075,7 @@ private void arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered() private void arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(int btcBlockWithTransactionHeight) throws BlockStoreException { setupSegwitActiveFederationWithUtxos(); + // the fund tx was created before RSKIP643, so its pegout index was saved instead of its pending utxos arrangeSvpFundTransactionUnsignedForVetiver(); assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(svpFundTransaction.getHash())); From f0ede5ea912b1b5c4c686884a3a40ac889111fc6 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 09:27:57 -0300 Subject: [PATCH 09/23] refactor: check every input when asserting a rejected release is not spent --- .../co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 96680d3e2d2..4051926611b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -5782,7 +5782,8 @@ private void assertReleaseWasRejectedAsUnrefundablePegin(BtcTransaction rejected assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(rejectedRelease.getHash()).isEmpty()); boolean anyReleaseSpendsRejectedRelease = bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries(allActivations).stream() .map(PegoutsWaitingForConfirmations.Entry::getBtcTransaction) - .anyMatch(release -> release.getInput(FIRST_INPUT_INDEX).getOutpoint().getHash().equals(rejectedRelease.getHash())); + .flatMap(release -> release.getInputs().stream()) + .anyMatch(input -> input.getOutpoint().getHash().equals(rejectedRelease.getHash())); assertFalse(anyReleaseSpendsRejectedRelease); } From e4d9e20982bddb919b11e67ba16c0b34e52099dd Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 09:45:34 -0300 Subject: [PATCH 10/23] test: cover releases not in the pegout index for vetiver and within the grace period --- ...idgeSupportRegisterBtcTransactionTest.java | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) 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 4051926611b..bca35e3cce1 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -3107,7 +3107,63 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); // act - registerLegacyReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, bridgeMainnetConstants); + registerLegacyReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX, bridgeMainnetConstants); + + // assert + assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); + + BtcTransaction refundPegout = getReleaseFromPegoutsWFC(bridgeStorageProvider); + assertReleaseRejectionWasSettled( + repository, + bridgeStorageProvider, + logs, + currentBlock.getNumber(), + rskTx.getHash(), + refundPegout, + List.of(changeValue), + changeValue + ); + + assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); + assertUtxosRegisteredWasNotEmitted(); + } + + @Test + void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_forVetiver_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveAndSegwitRetiringFeds(vetiver900Activations); + BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); + + // act + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); + + BtcTransaction refundPegout = getReleaseFromPegoutsWFC(bridgeStorageProvider); + assertReleaseRejectionWasSettled( + repository, + bridgeStorageProvider, + logs, + currentBlock.getNumber(), + rskTx.getHash(), + refundPegout, + List.of(changeValue), + changeValue + ); + + assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); + assertUtxosRegisteredWasNotEmitted(); + } + + @Test + void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_withinGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveAndSegwitRetiringFeds(allActivations); + BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); + + // act + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); // assert assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); From 63b2bcdee23e84845f114398d5e5a4dc492bc8d0 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 09:59:34 -0300 Subject: [PATCH 11/23] refactor: share the rejected and refunded release assertion between register and svp tests --- ...idgeSupportRegisterBtcTransactionTest.java | 21 ++--- .../java/co/rsk/peg/BridgeSupportSvpTest.java | 80 ++----------------- .../co/rsk/peg/BridgeSupportTestUtil.java | 21 +++++ 3 files changed, 33 insertions(+), 89 deletions(-) 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 bca35e3cce1..c66a2668756 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -5348,7 +5348,7 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_withinGracePer } @Test - void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_afterGracePeriod_shouldRejectAsUnrefundablePegin() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_afterGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(pegout.getHash())); @@ -5366,7 +5366,7 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_afterGracePeri // the pegout index is no longer looked up, so the change sent from the federation is evaluated as a legacy pegin assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - assertReleaseWasRejectedAsUnrefundablePegin(pegout); + assertReleaseWasRejectedAndRefundedToSpendingFederation(logs, bridgeStorageProvider, pegout, segwitActiveFederation); } @Test @@ -5614,7 +5614,7 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_withinGr } @Test - void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_afterGracePeriod_shouldRejectAsUnrefundablePegin() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_afterGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange BtcTransaction migrationTransaction = createMigrationForVetiverFromRetiringFedToActiveFed(); assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(migrationTransaction.getHash())); @@ -5633,7 +5633,7 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_afterGra assertEquals(1, migrationTransaction.getOutputs().size()); assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - assertReleaseWasRejectedAsUnrefundablePegin(migrationTransaction); + assertReleaseWasRejectedAndRefundedToSpendingFederation(logs, bridgeStorageProvider, migrationTransaction, retiringFederation); } @Test @@ -5732,6 +5732,7 @@ private void setUpBridgeAndFederationSupportWithActivations(long executionBlockN .withRepository(repository) .withEventLogger(new BridgeEventLoggerImpl(bridgeMainnetConstants, activations, logs)) .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withBtcLockSenderProvider(btcLockSenderProvider) .withFederationSupport(federationSupport) .withFeePerKbSupport(feePerKbSupport) .build(); @@ -5831,18 +5832,6 @@ private void assertMigrationWasRegisteredInActiveFed( ); } - private void assertReleaseWasRejectedAsUnrefundablePegin(BtcTransaction rejectedRelease) throws IOException { - // the redeem script of a p2sh-p2wsh erp federation is not a plain multisig, so the sender can't be determined - assertLogRejectedPegin(logs, rejectedRelease, RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); - assertLogNonRefundablePegin(logs, rejectedRelease, LEGACY_PEGIN_UNDETERMINED_SENDER); - assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(rejectedRelease.getHash()).isEmpty()); - boolean anyReleaseSpendsRejectedRelease = bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries(allActivations).stream() - .map(PegoutsWaitingForConfirmations.Entry::getBtcTransaction) - .flatMap(release -> release.getInputs().stream()) - .anyMatch(input -> input.getOutpoint().getHash().equals(rejectedRelease.getHash())); - assertFalse(anyReleaseSpendsRejectedRelease); - } - private void signAndRegisterReleaseTransaction( BtcTransaction releaseTransaction, Federation signingFederation, 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 949f0c1a808..d3290f3bcf6 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -16,7 +16,6 @@ import static co.rsk.peg.federation.FederationStorageIndexKey.NEW_FEDERATION_BTC_UTXOS_KEY; import static co.rsk.peg.federation.FederationTestUtils.signInputs; import static co.rsk.peg.pegin.RejectedPeginReason.INVALID_AMOUNT; -import static co.rsk.peg.pegin.RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -80,6 +79,8 @@ class BridgeSupportSvpTest { // still past the pegout index start, and releases created before RSKIP643 are still looked up in it private static final int HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - 1; private static final FederationConstants federationMainNetConstants = bridgeMainNetConstants.getFederationConstants(); + private static final BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); + private static final PeginInstructionsProvider peginInstructionsProvider = new PeginInstructionsProvider(); private static final List svpFundTxOutpointsValues = Arrays.asList( Coin.valueOf(1_000_000), Coin.valueOf(500_000), @@ -893,7 +894,7 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared } @Test - void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForVetiver_afterGracePeriod_shouldRejectAsUnrefundablePegin() throws Exception { + void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForVetiver_afterGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws Exception { // arrange arrangeExecutionBlockIsAfterValidationPeriodEnded(); arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); @@ -905,12 +906,10 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared // assert // the pegout index is no longer looked up, so the change sent from the federation is evaluated as a legacy pegin, - // and since the redeem script of a p2sh-p2wsh erp federation is not a plain multisig, the sender can't be determined - assertLogRejectedPegin(logs, svpFundTransaction, LEGACY_PEGIN_UNDETERMINED_SENDER); - assertLogNonRefundablePegin(logs, svpFundTransaction, NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER); + // and since the active federation is detected as a multisig sender, the change is refunded to it assertUtxosAreEqual(activeFederationUtxosBeforeRegisteringTx, federationSupport.getActiveFederationBtcUTXOs()); assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(svpFundTransaction.getHash()).isEmpty()); + assertReleaseWasRejectedAndRefundedToSpendingFederation(logs, bridgeStorageProvider, svpFundTransaction, segwitActiveFederation); } @Test @@ -1561,19 +1560,6 @@ void registerBtcTransaction_forLegacyPeginFromP2pkh_whenWaitingForSvpSpendTx_sho pegin.addOutput(amountToSend, activeFederation.getAddress()); setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); - // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin - BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainNetConstants) - .withProvider(bridgeStorageProvider) - .withEventLogger(bridgeEventLogger) - .withActivations(allActivations) - .withFederationSupport(federationSupport) - .withFeePerKbSupport(feePerKbSupport) - .withExecutionBlock(rskExecutionBlock) - .withBtcLockSenderProvider(btcLockSenderProvider) - .build(); - int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1629,19 +1615,6 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wpkh_whenWaitingForSvpSpendT pegin.addOutput(amountToSend, activeFederation.getAddress()); setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); - // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin - BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainNetConstants) - .withProvider(bridgeStorageProvider) - .withEventLogger(bridgeEventLogger) - .withActivations(allActivations) - .withFederationSupport(federationSupport) - .withFeePerKbSupport(feePerKbSupport) - .withExecutionBlock(rskExecutionBlock) - .withBtcLockSenderProvider(btcLockSenderProvider) - .build(); - int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1692,19 +1665,6 @@ void registerBtcTransaction_forLegacyPeginFromP2shMultisig_whenWaitingForSvpSpen pegin.addOutput(amountToSend, activeFederation.getAddress()); setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); - // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin - BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainNetConstants) - .withProvider(bridgeStorageProvider) - .withEventLogger(bridgeEventLogger) - .withActivations(allActivations) - .withFederationSupport(federationSupport) - .withFeePerKbSupport(feePerKbSupport) - .withExecutionBlock(rskExecutionBlock) - .withBtcLockSenderProvider(btcLockSenderProvider) - .build(); - int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1765,19 +1725,6 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wsh_whenWaitingForSvpSpendTx pegin.addOutput(amountToSend, activeFederation.getAddress()); setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); - // recreate bridge support with real btcLockSenderProvider instead of a mock to be able to parse pegin - BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainNetConstants) - .withProvider(bridgeStorageProvider) - .withEventLogger(bridgeEventLogger) - .withActivations(allActivations) - .withFederationSupport(federationSupport) - .withFeePerKbSupport(feePerKbSupport) - .withExecutionBlock(rskExecutionBlock) - .withBtcLockSenderProvider(btcLockSenderProvider) - .build(); - int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1826,21 +1773,6 @@ void registerBtcTransaction_forPeginV1_whenWaitingForSvpSpendTx_shouldProcessAnd pegin.addOutput(Coin.ZERO, opReturnScript); setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); - // recreate bridge support with real btcLockSenderProvider and peginInstructionsProvider instead of a mock to be able to parse pegin v1 - BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); - PeginInstructionsProvider peginInstructionsProvider = new PeginInstructionsProvider(); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainNetConstants) - .withProvider(bridgeStorageProvider) - .withEventLogger(bridgeEventLogger) - .withActivations(allActivations) - .withFederationSupport(federationSupport) - .withFeePerKbSupport(feePerKbSupport) - .withExecutionBlock(rskExecutionBlock) - .withBtcLockSenderProvider(btcLockSenderProvider) - .withPeginInstructionsProvider(peginInstructionsProvider) - .build(); - int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -2305,6 +2237,8 @@ private void setUpForTransactionRegistration(BtcTransaction transaction, int btc .withFeePerKbSupport(feePerKbSupport) .withExecutionBlock(rskExecutionBlock) .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) .withRepository(repository) .build(); } diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java index d8cafe566c8..5b38cc0dd50 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java @@ -412,6 +412,27 @@ public static void assertReleaseRejectionWasSettled( assertReleaseTransactionInfoWasProcessed(repository, bridgeStorageProvider, logs, releaseTransaction, expectedOutpointsValues); } + public static void assertReleaseWasRejectedAndRefundedToSpendingFederation( + List logs, + BridgeStorageProvider bridgeStorageProvider, + BtcTransaction rejectedRelease, + Federation spendingFederation + ) throws IOException { + // the spending federation is detected as a multisig sender, so the funds sent to the live federations are refunded to it + assertLogRejectedPegin(logs, rejectedRelease, RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER); + assertEventWasNotEmitted(logs, BridgeEvents.UNREFUNDABLE_PEGIN.getEvent()); + assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(rejectedRelease.getHash(false)).isPresent()); + + List refunds = bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries(ACTIVATIONS_ALL).stream() + .map(PegoutsWaitingForConfirmations.Entry::getBtcTransaction) + .filter(release -> release.getInputs().stream().anyMatch(input -> input.getOutpoint().getHash().equals(rejectedRelease.getHash()))) + .toList(); + assertEquals(1, refunds.size()); + BtcTransaction refund = refunds.get(0); + assertEquals(1, refund.getOutputs().size()); + assertEquals(spendingFederation.getAddress(), refund.getOutput(0).getScriptPubKey().getToAddress(rejectedRelease.getParams())); + } + public static void assertLegacyReleaseRejectionWasSettled( BridgeStorageProvider bridgeStorageProvider, List logs, From e7ae24c801e13886d4a334c3c09598f8e34a6ca9 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 12:48:02 -0300 Subject: [PATCH 12/23] test: cover pre-RSKIP643 pegout with change below minimum pegin value rejected without refund after grace period --- ...idgeSupportRegisterBtcTransactionTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) 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 c66a2668756..8c0e53a2e0e 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -5270,6 +5270,8 @@ class ReleaseWithFederationsPendingBtcUTXOs { private static final Coin CHANGE_VALUE = Coin.COIN.div(4); // the pegout recipients pay the fees, so the change is the input value minus the requested value private static final Coin PEGOUT_REQUEST_VALUE = INPUT_VALUE.subtract(CHANGE_VALUE); + private static final Coin CHANGE_VALUE_BELOW_MINIMUM_PEGIN_VALUE = minimumPeginTxValue.subtract(Coin.SATOSHI); + private static final Coin PEGOUT_REQUEST_VALUE_LEAVING_CHANGE_BELOW_MINIMUM_PEGIN_VALUE = INPUT_VALUE.subtract(CHANGE_VALUE_BELOW_MINIMUM_PEGIN_VALUE); private static final Keccak256 PEGOUT_REQUEST_RSK_TX_HASH = RskTestUtils.createHash(2); // the pegout change output is added last, after the user output private static final long OUTPUT_INDEX_FOR_PEGOUT_CHANGE = 1L; @@ -5369,6 +5371,36 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_afterGracePeri assertReleaseWasRejectedAndRefundedToSpendingFederation(logs, bridgeStorageProvider, pegout, segwitActiveFederation); } + @Test + void registerBtcTransaction_withPegoutWithChangeBelowMinimumPeginValueCreatedForVetiver_afterGracePeriod_shouldBeRejectedWithoutRefund() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE_LEAVING_CHANGE_BELOW_MINIMUM_PEGIN_VALUE); + assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(pegout.getHash())); + setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); + + // act + signAndRegisterReleaseTransaction( + pegout, + segwitActiveFederation, + segwitActiveFederationKeys, + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + ); + + // assert + // the change is evaluated as a legacy pegin, and its amount is checked before its multisig sender, + // so it is rejected without a refund and never reaches the federation utxos + assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); + assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); + assertLogRejectedPegin(logs, pegout, RejectedPeginReason.INVALID_AMOUNT); + assertLogNonRefundablePegin(logs, pegout, NonRefundablePeginReason.INVALID_AMOUNT); + assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(pegout.getHash()).isEmpty()); + + boolean wasRefunded = bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries(allActivations).stream() + .map(PegoutsWaitingForConfirmations.Entry::getBtcTransaction) + .anyMatch(release -> release.getInputs().stream().anyMatch(input -> input.getOutpoint().getHash().equals(pegout.getHash()))); + assertFalse(wasRefunded); + } + @Test void registerBtcTransaction_withPegoutWithChange_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange From a576b2af5cf862abf90ee4ec22865461d2b5609e Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:12:09 -0300 Subject: [PATCH 13/23] feat: added isIdentifiedByPegoutIndex --- .../src/main/java/co/rsk/peg/PegUtils.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) 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 54a33fc976f..009a9b8d067 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java @@ -45,13 +45,7 @@ static PegTxType getTransactionTypeUsingPegoutIndex( List liveFederationOutputs = btcTransaction.getWalletOutputs(liveFederationsWallet); - Optional inputSigHash = getSigHashToLookUpInPegoutIndex( - bridgeConstants, - activations, - btcTransaction, - btcTransactionHeight - ); - if (inputSigHash.isPresent() && provider.hasPegoutTxSigHash(inputSigHash.get())){ + if (isIdentifiedByPegoutIndex(provider, bridgeConstants, activations, btcTransaction, btcTransactionHeight)){ return PegTxType.PEGOUT_OR_MIGRATION; } else if (!liveFederationOutputs.isEmpty()){ return PegTxType.PEGIN; @@ -60,18 +54,20 @@ static PegTxType getTransactionTypeUsingPegoutIndex( } } - private static Optional getSigHashToLookUpInPegoutIndex( + private static boolean isIdentifiedByPegoutIndex( + BridgeStorageProvider provider, BridgeConstants bridgeConstants, ActivationConfig.ForBlock activations, BtcTransaction btcTransaction, long btcTransactionHeight ) { - // Once the grace period ends, releases are only identified by their federations pending btc utxos, - // so the sighash is no longer computed to look it up in the pegout index - if (isFederationsPendingBtcUTXOsEnabled(bridgeConstants, activations, btcTransactionHeight)) { - return Optional.empty(); - } - return BitcoinUtils.getSigHashForPegoutIndex(btcTransaction); + // Once the grace period ends, releases are only identified by their federations pending btc utxos + boolean shouldUsePegoutIndex = !isFederationsPendingBtcUTXOsEnabled(bridgeConstants, activations, btcTransactionHeight); + boolean isInPegoutIndex = BitcoinUtils.getSigHashForPegoutIndex(btcTransaction) + .map(provider::hasPegoutTxSigHash) + .orElse(false); + + return shouldUsePegoutIndex && isInPegoutIndex; } /** From 67fcdd35357a19ebc932d3c4b68b79d572e3014b Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:15:01 -0300 Subject: [PATCH 14/23] fix: deleeted duplicated tests --- ...idgeSupportRegisterBtcTransactionTest.java | 56 ------------------- 1 file changed, 56 deletions(-) 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 8c0e53a2e0e..d8a070bfd0a 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -3156,62 +3156,6 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit assertUtxosRegisteredWasNotEmitted(); } - @Test - void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_withinGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { - // arrange - setupSegwitActiveAndSegwitRetiringFeds(allActivations); - BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); - - // act - registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); - - // assert - assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); - - BtcTransaction refundPegout = getReleaseFromPegoutsWFC(bridgeStorageProvider); - assertReleaseRejectionWasSettled( - repository, - bridgeStorageProvider, - logs, - currentBlock.getNumber(), - rskTx.getHash(), - refundPegout, - List.of(changeValue), - changeValue - ); - - assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); - assertUtxosRegisteredWasNotEmitted(); - } - - @Test - void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_forVetiver_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { - // arrange - setupSegwitActiveAndSegwitRetiringFeds(vetiver900Activations); - BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); - - // act - registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); - - // assert - assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); - - BtcTransaction refundPegout = getReleaseFromPegoutsWFC(bridgeStorageProvider); - assertReleaseRejectionWasSettled( - repository, - bridgeStorageProvider, - logs, - currentBlock.getNumber(), - rskTx.getHash(), - refundPegout, - List.of(changeValue), - changeValue - ); - - assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); - assertUtxosRegisteredWasNotEmitted(); - } - @Test void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_withinGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange From 19e7e703e47b85c4448e3d4ac2f93f91f21fddb2 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:22:30 -0300 Subject: [PATCH 15/23] fix: use the whole input value in the vetiver pegout without change test after the grace period --- .../co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d8a070bfd0a..cf38e29ba34 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -5433,7 +5433,7 @@ void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_afterGraceP // arrange // before RSKIP643 the pegout sighash is saved in the pegout index instead of its change as federations pending utxos // requesting the whole input value leaves no change - BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); + BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(INPUT_VALUE); assertNotPendingUtxos(pegout); setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); From b3f37b0187560280f2f5c520d495689502c52fee Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:31:22 -0300 Subject: [PATCH 16/23] fix: format --- rskj-core/src/main/java/co/rsk/peg/PegUtils.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 009a9b8d067..6cad67cc3bf 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java @@ -45,7 +45,13 @@ static PegTxType getTransactionTypeUsingPegoutIndex( List liveFederationOutputs = btcTransaction.getWalletOutputs(liveFederationsWallet); - if (isIdentifiedByPegoutIndex(provider, bridgeConstants, activations, btcTransaction, btcTransactionHeight)){ + if (isIdentifiedByPegoutIndex( + provider, + bridgeConstants, + activations, + btcTransaction, + btcTransactionHeight + )) { return PegTxType.PEGOUT_OR_MIGRATION; } else if (!liveFederationOutputs.isEmpty()){ return PegTxType.PEGIN; From d463e7217c9d6b39083cc6d33b211f92d171d6dd Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:34:22 -0300 Subject: [PATCH 17/23] refactor: made isIdentifiedByPegoutIndex simpler --- rskj-core/src/main/java/co/rsk/peg/PegUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 6cad67cc3bf..540ca6fc67b 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java @@ -68,12 +68,12 @@ private static boolean isIdentifiedByPegoutIndex( long btcTransactionHeight ) { // Once the grace period ends, releases are only identified by their federations pending btc utxos - boolean shouldUsePegoutIndex = !isFederationsPendingBtcUTXOsEnabled(bridgeConstants, activations, btcTransactionHeight); - boolean isInPegoutIndex = BitcoinUtils.getSigHashForPegoutIndex(btcTransaction) + if (isFederationsPendingBtcUTXOsEnabled(bridgeConstants, activations, btcTransactionHeight)) { + return false; + } + return BitcoinUtils.getSigHashForPegoutIndex(btcTransaction) .map(provider::hasPegoutTxSigHash) .orElse(false); - - return shouldUsePegoutIndex && isInPegoutIndex; } /** From 51398c3cb96b926b9717c18d4ce48cc2e6169b5e Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:42:40 -0300 Subject: [PATCH 18/23] fix: use registerReleaseTransaction instead --- .../co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 cf38e29ba34..0d1ef1a4450 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -4681,7 +4681,7 @@ void registerBtcTransaction_fromRetiredFederationNotInStorage_withSegwitActiveFe registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerLegacyReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, bridgeMainnetConstants); + registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( From a8dea2498c14104fd7b6b7b63f0bc3c6f56aa735 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:42:53 -0300 Subject: [PATCH 19/23] changed BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT to HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK --- .../BridgeSupportRegisterBtcTransactionTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 0d1ef1a4450..f7c357d991c 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -94,7 +94,7 @@ class BridgeSupportRegisterBtcTransactionTest { private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS; // still past the pegout index start, and releases created before RSKIP643 are still looked up in it - private static final int BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT = HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - 1; + private static final int HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK = HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - 1; private static final int HEIGHT_BEFORE_USING_PEGOUT_INDEX = 1; private static final int UTXO_HEIGHT_BEFORE_CARDAMOM = 0; private static final Address userAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userAddress"); @@ -3163,7 +3163,7 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); // act - registerReleaseTransaction(btcTransaction, BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT); + registerReleaseTransaction(btcTransaction, HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK); // assert assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); @@ -5271,14 +5271,14 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_withinGracePer pegout, segwitActiveFederation, segwitActiveFederationKeys, - BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK ); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( pegout, segwitActiveFederation, - BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); assertReleaseWasRegistered( @@ -5415,7 +5415,7 @@ void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_withinGrace pegout, segwitActiveFederation, segwitActiveFederationKeys, - BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK ); // assert @@ -5577,7 +5577,7 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_withinGr migrationTransaction, retiringFederation, retiringFederationKeys, - BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK ); // assert @@ -5585,7 +5585,7 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_withinGr assertMigrationWasRegisteredInActiveFed( migrationTransaction, List.of(0L), - BTC_BLOCK_WITH_RELEASE_WITHIN_GRACE_PERIOD_HEIGHT + HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK ); } From 1409e06ae284456e68f2ec4862aa643e1c03af2e Mon Sep 17 00:00:00 2001 From: Julian Len Date: Thu, 22 Oct 2026 18:52:16 -0300 Subject: [PATCH 20/23] test: add forVetiver cases for pegout txs --- ...idgeSupportRegisterBtcTransactionTest.java | 168 +++++++++++++++++- 1 file changed, 167 insertions(+), 1 deletion(-) 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 f7c357d991c..b885b17be78 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -3353,6 +3353,25 @@ void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withRetiring assertNotPendingUtxos(btcTransaction); } + @Test + void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withoutRetiringFed_withSegwitActiveFed_forVetiver_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveFed(vetiver900Activations); + BtcTransaction btcTransaction = getPegoutTxWithManyOutputsAndInputsWithChangeOutput(); + registerPegoutTxSigHash(btcTransaction); + + // act + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + List expectedUtxosRegistered = buildExpectedUtxosRegistered( + btcTransaction, + activeFederation, + UTXO_HEIGHT_BEFORE_CARDAMOM + ); + assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); + } + @Test void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withoutRetiringFed_withSegwitActiveFed_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -3504,6 +3523,25 @@ void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_forReed_wi assertUtxosRegisteredWasNotEmitted(); } + @Test + void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withRetiringFed_withSegwitActiveFed_forVetiver_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveAndSegwitRetiringFeds(vetiver900Activations); + BtcTransaction btcTransaction = getPegoutTxWithManyOutputsAndOneInputWithChangeOutput(); + registerPegoutTxSigHash(btcTransaction); + + // act + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + List expectedUtxosRegistered = buildExpectedUtxosRegistered( + btcTransaction, + activeFederation, + UTXO_HEIGHT_BEFORE_CARDAMOM + ); + assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); + } + @Test void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withRetiringFed_withSegwitActiveFed_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -3525,6 +3563,25 @@ void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withRetiri assertNotPendingUtxos(btcTransaction); } + @Test + void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withoutRetiringFed_withSegwitActiveFed_forVetiver_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveFed(vetiver900Activations); + BtcTransaction btcTransaction = getPegoutTxWithManyOutputsAndOneInputWithChangeOutput(); + registerPegoutTxSigHash(btcTransaction); + + // act + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + List expectedUtxosRegistered = buildExpectedUtxosRegistered( + btcTransaction, + activeFederation, + UTXO_HEIGHT_BEFORE_CARDAMOM + ); + assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); + } + @Test void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withoutRetiringFed_withSegwitActiveFed_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -3640,6 +3697,20 @@ void registerBtcTransaction_withNoChangeOutputAndManyInputs_forReed_withRetiring assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); } + @Test + void registerBtcTransaction_withNoChangeOutputAndManyInputs_withRetiringFed_withSegwitActiveFed_forVetiver_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveAndSegwitRetiringFeds(vetiver900Activations); + BtcTransaction btcTransaction = getPegoutTxWithOneOutputAndManyInputsWithoutChange(); + registerPegoutTxSigHash(btcTransaction); + + // act + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); + } + @Test void registerBtcTransaction_withNoChangeOutputAndManyInputs_withRetiringFed_withSegwitActiveFed_shouldNotRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -3655,6 +3726,20 @@ void registerBtcTransaction_withNoChangeOutputAndManyInputs_withRetiringFed_with assertUtxosRegisteredWasNotEmitted(); } + @Test + void registerBtcTransaction_withNoChangeOutputAndManyInputs_withoutRetiringFed_withSegwitActiveFed_forVetiver_shouldRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveFed(vetiver900Activations); + BtcTransaction btcTransaction = getPegoutTxWithOneOutputAndManyInputsWithoutChange(); + registerPegoutTxSigHash(btcTransaction); + + // act + registerReleaseTransaction(btcTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + assertReleaseTxWasProcessedWithNoNewUtxo(btcTransaction); + } + @Test void registerBtcTransaction_withNoChangeOutputAndManyInputs_withoutRetiringFed_withSegwitActiveFed_shouldNotRegisterPegoutTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -3765,6 +3850,16 @@ class MigrationTransaction { private static final int MANY_MIGRATION_UTXOS = 40; private static final int OLD_FEDERATION_MIGRATION_HEIGHT = 5; + // registerReleaseTransaction needs a witness-bearing tx, so the retired fed must be segwit + private Federation buildSegwitRetiredFed() { + return P2shP2wshErpFederationBuilder.builder() + .withNetworkParameters(btcMainnetParams) + .withMembersBtcPublicKeys(retiredFedSigners) + .withErpActivationDelay(activationDelay) + .withErpPublicKeys(erpPubKeys) + .build(); + } + @Test void registerBtcTransaction_withOneInputAndOutput_forFingerroot_shouldRegisterMigrationTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -4184,6 +4279,29 @@ void registerBtcTransaction_withManyOutputsAndOneInput_forReed_withSegwitActiveF assertUtxosRegisteredWasNotEmitted(); } + @Test + void registerBtcTransaction_withManyOutputsAndOneInput_withSegwitActiveAndRetiringFeds_forVetiver_shouldRegisterMigrationTxUtxosWithZeroHeight() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveAndSegwitRetiringFeds(vetiver900Activations); + BtcTransaction migrationTx = getMigrationTxWithManyOutputsAndOneInput(); + registerPegoutTxSigHash(migrationTx); + + // act + registerReleaseTransaction(migrationTx, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + List expectedUtxosRegistered = buildExpectedUtxosRegistered( + migrationTx, + activeFederation, + UTXO_HEIGHT_BEFORE_CARDAMOM + ); + assertMigrationTxWasProcessed( + migrationTx, + MANY_MIGRATION_UTXOS, + expectedUtxosRegistered + ); + } + @Test void registerBtcTransaction_withManyOutputsAndOneInput_withSegwitActiveAndRetiringFeds_shouldRegisterMigrationTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -4300,6 +4418,29 @@ void registerBtcTransaction_withOneOutputAndManyInputs_forReed_withSegwitActiveF assertUtxosRegisteredWasNotEmitted(); } + @Test + void registerBtcTransaction_withOneOutputAndManyInputs_withSegwitActiveAndRetiringFeds_forVetiver_shouldRegisterMigrationTxUtxosWithZeroHeight() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveAndSegwitRetiringFeds(vetiver900Activations); + BtcTransaction migrationTx = getMigrationTxWithOneOutputAndManyInputs(); + registerPegoutTxSigHash(migrationTx); + + // act + registerReleaseTransaction(migrationTx, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + List expectedUtxosRegistered = buildExpectedUtxosRegistered( + migrationTx, + activeFederation, + UTXO_HEIGHT_BEFORE_CARDAMOM + ); + assertMigrationTxWasProcessed( + migrationTx, + ONE_MIGRATION_UTXO, + expectedUtxosRegistered + ); + } + @Test void registerBtcTransaction_withOneOutputAndManyInputs_withSegwitActiveAndRetiringFeds_shouldRegisterMigrationTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -4673,11 +4814,36 @@ void registerBtcTransaction_fromRetiredFederationNotInStorage_withPegoutIndex_fo ); } + @Test + void registerBtcTransaction_fromRetiredFederationNotInStorage_withSegwitActiveFed_forVetiver_shouldRegisterMigrationTxUtxosWithZeroHeight() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + // arrange + setupSegwitActiveFed(vetiver900Activations); + Federation segwitRetiredFed = buildSegwitRetiredFed(); + BtcTransaction migrationTx = getReleaseTxWithOneInputAndOutputWithoutChange(segwitRetiredFed, retiredFedSigners, activeFederation.getAddress()); + registerPegoutTxSigHash(migrationTx); + + // act + registerReleaseTransaction(migrationTx, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); + + // assert + List expectedUtxosRegistered = buildExpectedUtxosRegistered( + migrationTx, + activeFederation, + UTXO_HEIGHT_BEFORE_CARDAMOM + ); + assertMigrationTxWasProcessed( + migrationTx, + ONE_MIGRATION_UTXO, + expectedUtxosRegistered + ); + } + @Test void registerBtcTransaction_fromRetiredFederationNotInStorage_withSegwitActiveFed_shouldRegisterMigrationTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange setupSegwitActiveFed(allActivations); - BtcTransaction migrationTx = getReleaseTxWithOneInputAndOutputWithoutChange(retiredFed, retiredFedSigners, activeFederation.getAddress()); + Federation segwitRetiredFed = buildSegwitRetiredFed(); + BtcTransaction migrationTx = getReleaseTxWithOneInputAndOutputWithoutChange(segwitRetiredFed, retiredFedSigners, activeFederation.getAddress()); registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act From 8b41f7c14a32bfd7d54ed0d2eac6e34a2b2b487b Mon Sep 17 00:00:00 2001 From: Julian Len Date: Fri, 23 Oct 2026 11:36:42 -0300 Subject: [PATCH 21/23] refactor: remove RSKIP643 pegout index grace period --- .../src/main/java/co/rsk/peg/PegUtils.java | 45 +--- ...idgeSupportRegisterBtcTransactionTest.java | 124 +---------- .../java/co/rsk/peg/BridgeSupportSvpTest.java | 33 +-- .../co/rsk/peg/BridgeSupportTestUtil.java | 21 -- .../peg/PegUtilsGetTransactionTypeTest.java | 199 ------------------ .../test/java/co/rsk/peg/PegUtilsTest.java | 82 ++------ .../peg/constants/BridgeConstantsTest.java | 19 -- 7 files changed, 40 insertions(+), 483 deletions(-) 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 540ca6fc67b..ab534322e96 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java @@ -34,10 +34,8 @@ private PegUtils() { } static PegTxType getTransactionTypeUsingPegoutIndex( ActivationConfig.ForBlock activations, BridgeStorageProvider provider, - BridgeConstants bridgeConstants, Wallet liveFederationsWallet, - BtcTransaction btcTransaction, - long btcTransactionHeight + BtcTransaction btcTransaction ) { if (!activations.isActive(ConsensusRule.RSKIP379)) { throw new IllegalStateException("Can't call this method before RSKIP379 activation"); @@ -45,13 +43,8 @@ static PegTxType getTransactionTypeUsingPegoutIndex( List liveFederationOutputs = btcTransaction.getWalletOutputs(liveFederationsWallet); - if (isIdentifiedByPegoutIndex( - provider, - bridgeConstants, - activations, - btcTransaction, - btcTransactionHeight - )) { + Optional inputSigHash = BitcoinUtils.getSigHashForPegoutIndex(btcTransaction); + if (inputSigHash.isPresent() && provider.hasPegoutTxSigHash(inputSigHash.get())) { return PegTxType.PEGOUT_OR_MIGRATION; } else if (!liveFederationOutputs.isEmpty()){ return PegTxType.PEGIN; @@ -60,22 +53,6 @@ static PegTxType getTransactionTypeUsingPegoutIndex( } } - private static boolean isIdentifiedByPegoutIndex( - BridgeStorageProvider provider, - BridgeConstants bridgeConstants, - ActivationConfig.ForBlock activations, - BtcTransaction btcTransaction, - long btcTransactionHeight - ) { - // Once the grace period ends, releases are only identified by their federations pending btc utxos - if (isFederationsPendingBtcUTXOsEnabled(bridgeConstants, activations, btcTransactionHeight)) { - return false; - } - return BitcoinUtils.getSigHashForPegoutIndex(btcTransaction) - .map(provider::hasPegoutTxSigHash) - .orElse(false); - } - /** * Checks if all utxos sent to the fedWallet are equal or above the minimum pegin value. * If no utxo is sent to the fedWallet or there is at least 1 utxo sent to the fedWallet that is below minimum, @@ -149,10 +126,8 @@ static PegTxType getTransactionType( return getTransactionTypeUsingPegoutIndex( activations, provider, - bridgeConstants, liveFederationsWallet, - btcTransaction, - btcTransactionHeight + btcTransaction ); } @@ -168,18 +143,6 @@ private static boolean isPegoutTxIndexEnabled( btcTransactionHeight >= heightAtWhichToStartUsingPegoutIndex; } - private static boolean isFederationsPendingBtcUTXOsEnabled( - BridgeConstants bridgeConstants, - ActivationConfig.ForBlock activations, - long btcTransactionHeight - ) { - int btcHeightWhenFederationsPendingBtcUTXOsActivates = bridgeConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates(); - int gracePeriodInBtcBlocks = bridgeConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); - int heightAtWhichToStartUsingFederationsPendingBtcUTXOs = btcHeightWhenFederationsPendingBtcUTXOsActivates + gracePeriodInBtcBlocks; - return activations.isActive(ConsensusRule.RSKIP643) && - btcTransactionHeight >= heightAtWhichToStartUsingFederationsPendingBtcUTXOs; - } - private static boolean isTheSvpFundTransaction( BridgeStorageProvider provider, ActivationConfig.ForBlock activations, 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 b885b17be78..3dad682f255 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -89,12 +89,9 @@ class BridgeSupportRegisterBtcTransactionTest { private static final int BTC_HEIGHT_WHEN_PEGOUT_TX_INDEX_ACTIVATES = bridgeMainnetConstants.getBtcHeightWhenPegoutTxIndexActivates(); private static final int PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS = bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = BTC_HEIGHT_WHEN_PEGOUT_TX_INDEX_ACTIVATES + PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS; - // past the pegout index start, so releases are not identified by their inputs as legacy releases are, - // and past the grace period, so releases created before RSKIP643 are no longer looked up in the pegout index + // past the pegout index start, so releases are not identified by their inputs as legacy releases are private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS; - // still past the pegout index start, and releases created before RSKIP643 are still looked up in it - private static final int HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK = HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - 1; private static final int HEIGHT_BEFORE_USING_PEGOUT_INDEX = 1; private static final int UTXO_HEIGHT_BEFORE_CARDAMOM = 0; private static final Address userAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userAddress"); @@ -3157,13 +3154,13 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit } @Test - void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_withinGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_withSegwitActiveAndRetiringFeds_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange setupSegwitActiveAndSegwitRetiringFeds(allActivations); BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); // act - registerReleaseTransaction(btcTransaction, HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK); + registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); // assert assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); @@ -5380,8 +5377,6 @@ class ReleaseWithFederationsPendingBtcUTXOs { private static final Coin CHANGE_VALUE = Coin.COIN.div(4); // the pegout recipients pay the fees, so the change is the input value minus the requested value private static final Coin PEGOUT_REQUEST_VALUE = INPUT_VALUE.subtract(CHANGE_VALUE); - private static final Coin CHANGE_VALUE_BELOW_MINIMUM_PEGIN_VALUE = minimumPeginTxValue.subtract(Coin.SATOSHI); - private static final Coin PEGOUT_REQUEST_VALUE_LEAVING_CHANGE_BELOW_MINIMUM_PEGIN_VALUE = INPUT_VALUE.subtract(CHANGE_VALUE_BELOW_MINIMUM_PEGIN_VALUE); private static final Keccak256 PEGOUT_REQUEST_RSK_TX_HASH = RskTestUtils.createHash(2); // the pegout change output is added last, after the user output private static final long OUTPUT_INDEX_FOR_PEGOUT_CHANGE = 1L; @@ -5425,7 +5420,7 @@ void setUp() { } @Test - void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_withinGracePeriod_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange // before RSKIP643 the pegout sighash is saved in the pegout index instead of its change as federations pending utxos BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); @@ -5437,14 +5432,14 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_withinGracePer pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( pegout, segwitActiveFederation, - HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); assertReleaseWasRegistered( @@ -5459,58 +5454,6 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_withinGracePer ); } - @Test - void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_afterGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { - // arrange - BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); - assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(pegout.getHash())); - setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); - - // act - signAndRegisterReleaseTransaction( - pegout, - segwitActiveFederation, - segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - ); - - // assert - // the pegout index is no longer looked up, so the change sent from the federation is evaluated as a legacy pegin - assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); - assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - assertReleaseWasRejectedAndRefundedToSpendingFederation(logs, bridgeStorageProvider, pegout, segwitActiveFederation); - } - - @Test - void registerBtcTransaction_withPegoutWithChangeBelowMinimumPeginValueCreatedForVetiver_afterGracePeriod_shouldBeRejectedWithoutRefund() throws BlockStoreException, BridgeIllegalArgumentException, IOException { - // arrange - BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE_LEAVING_CHANGE_BELOW_MINIMUM_PEGIN_VALUE); - assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(pegout.getHash())); - setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); - - // act - signAndRegisterReleaseTransaction( - pegout, - segwitActiveFederation, - segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - ); - - // assert - // the change is evaluated as a legacy pegin, and its amount is checked before its multisig sender, - // so it is rejected without a refund and never reaches the federation utxos - assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); - assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - assertLogRejectedPegin(logs, pegout, RejectedPeginReason.INVALID_AMOUNT); - assertLogNonRefundablePegin(logs, pegout, NonRefundablePeginReason.INVALID_AMOUNT); - assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(pegout.getHash()).isEmpty()); - - boolean wasRefunded = bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries(allActivations).stream() - .map(PegoutsWaitingForConfirmations.Entry::getBtcTransaction) - .anyMatch(release -> release.getInputs().stream().anyMatch(input -> input.getOutpoint().getHash().equals(pegout.getHash()))); - assertFalse(wasRefunded); - } - @Test void registerBtcTransaction_withPegoutWithChange_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -5568,7 +5511,7 @@ void registerBtcTransaction_withPegoutWithoutChange_shouldNotRegister() throws B } @Test - void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_withinGracePeriod_shouldMarkAsProcessedWithoutRegisteringUtxos() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_shouldMarkAsProcessedWithoutRegisteringUtxos() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange // before RSKIP643 the pegout sighash is saved in the pegout index, even when the pegout has no change // requesting the whole input value leaves no change @@ -5581,7 +5524,7 @@ void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_withinGrace pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert @@ -5594,30 +5537,6 @@ void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_withinGrace assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); } - @Test - void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_afterGracePeriod_shouldNotRegister() throws BlockStoreException, BridgeIllegalArgumentException, IOException { - // arrange - // before RSKIP643 the pegout sighash is saved in the pegout index instead of its change as federations pending utxos - // requesting the whole input value leaves no change - BtcTransaction pegout = createPegoutForVetiverFromActiveFedPayingToUser(INPUT_VALUE); - assertNotPendingUtxos(pegout); - setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); - - // act - signAndRegisterReleaseTransaction( - pegout, - segwitActiveFederation, - segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - ); - - // assert - // the pegout index is no longer looked up, and with no output to the live federations the pegout is unknown - assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); - assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(pegout.getHash()).isEmpty()); - assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - } - @Test void registerBtcTransaction_withPegoutToActiveFed_afterChangingToRetiringFed_shouldRegisterChangeInRetiringFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange @@ -5731,7 +5650,7 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran } @Test - void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_withinGracePeriod_shouldRegisterMigratedUtxosInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_shouldRegisterMigratedUtxosInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange // before RSKIP643 the migration sighash is saved in the pegout index instead of its outputs as federations pending utxos BtcTransaction migrationTransaction = createMigrationForVetiverFromRetiringFedToActiveFed(); @@ -5743,7 +5662,7 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_withinGr migrationTransaction, retiringFederation, retiringFederationKeys, - HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK + HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); // assert @@ -5751,31 +5670,8 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_withinGr assertMigrationWasRegisteredInActiveFed( migrationTransaction, List.of(0L), - HEIGHT_WITHIN_GRACE_PERIOD_HEIGHT_BLOCK - ); - } - - @Test - void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_afterGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws BlockStoreException, BridgeIllegalArgumentException, IOException { - // arrange - BtcTransaction migrationTransaction = createMigrationForVetiverFromRetiringFedToActiveFed(); - assertFalse(federationSupport.hasFederationsPendingBtcUTXOs(migrationTransaction.getHash())); - setUpBridgeAndFederationSupport(MIGRATION_REGISTRATION_BLOCK_NUMBER); - - // act - signAndRegisterReleaseTransaction( - migrationTransaction, - retiringFederation, - retiringFederationKeys, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD ); - - // assert - // the pegout index is no longer looked up, so the migrated funds are evaluated as a legacy pegin - assertEquals(1, migrationTransaction.getOutputs().size()); - assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); - assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - assertReleaseWasRejectedAndRefundedToSpendingFederation(logs, bridgeStorageProvider, migrationTransaction, retiringFederation); } @Test 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 d3290f3bcf6..e53b9b5abb3 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -73,11 +73,9 @@ class BridgeSupportSvpTest { // releases created before RSKIP643 are identified through the pegout index from this height on private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = bridgeMainNetConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); - // past the grace period, so releases created before RSKIP643 are no longer looked up in the pegout index + // past the pegout index start, so releases are not identified by their inputs as legacy releases are private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainNetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); - // still past the pegout index start, and releases created before RSKIP643 are still looked up in it - private static final int HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - 1; private static final FederationConstants federationMainNetConstants = bridgeMainNetConstants.getFederationConstants(); private static final BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); private static final PeginInstructionsProvider peginInstructionsProvider = new PeginInstructionsProvider(); @@ -879,10 +877,10 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared } @Test - void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForVetiver_withinGracePeriod_shouldRegisterChangeUtxo() throws Exception { + void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForVetiver_shouldRegisterChangeUtxo() throws Exception { // arrange arrangeExecutionBlockIsAfterValidationPeriodEnded(); - arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(); arrangeSvpValuesWereClearedAfterValidationPeriodEnded(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -893,25 +891,6 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared assertSvpFundTxChangeWasRegisteredInSegwitActiveFederation(activeFederationUtxosBeforeRegisteringTx); } - @Test - void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForVetiver_afterGracePeriod_shouldBeDetectedAsLegacyPeginRejectedAndRefunded() throws Exception { - // arrange - arrangeExecutionBlockIsAfterValidationPeriodEnded(); - arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); - arrangeSvpValuesWereClearedAfterValidationPeriodEnded(); - List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); - - // act - registerBtcTransaction(svpFundTransaction); - - // assert - // the pegout index is no longer looked up, so the change sent from the federation is evaluated as a legacy pegin, - // and since the active federation is detected as a multisig sender, the change is refunded to it - assertUtxosAreEqual(activeFederationUtxosBeforeRegisteringTx, federationSupport.getActiveFederationBtcUTXOs()); - assertEventWasNotEmitted(logs, BridgeEvents.UTXOS_REGISTERED.getEvent()); - assertReleaseWasRejectedAndRefundedToSpendingFederation(logs, bridgeStorageProvider, svpFundTransaction, segwitActiveFederation); - } - @Test void registerBtcTransaction_forNormalPegout_whenSvpPeriodIsOngoing_forVetiver_shouldRegisterTransactionButNotUpdateSvpFundTransactionValues() throws Exception { // arrange @@ -1052,7 +1031,7 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpPeriodIsOngoing_s @Test void registerBtcTransaction_forSvpFundTransactionChange_withFundTxCreatedBeforeRSKIP643_shouldRegisterTransactionAndUpdateSvpFundTransactionValues() throws Exception { // arrange - arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -1072,7 +1051,7 @@ private void arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered() setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); } - private void arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(int btcBlockWithTransactionHeight) throws BlockStoreException { + private void arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered() throws BlockStoreException { setupSegwitActiveFederationWithUtxos(); // the fund tx was created before RSKIP643, so its pegout index was saved instead of its pending utxos arrangeSvpFundTransactionUnsignedForVetiver(); @@ -1080,7 +1059,7 @@ private void arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederatio signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); // and it is registered after RSKIP643 - setUpForTransactionRegistration(svpFundTransaction, btcBlockWithTransactionHeight); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); } private void arrangeSvpFundTransactionToBeRegisteredForVetiver() throws BlockStoreException { diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java index 5b38cc0dd50..d8cafe566c8 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java @@ -412,27 +412,6 @@ public static void assertReleaseRejectionWasSettled( assertReleaseTransactionInfoWasProcessed(repository, bridgeStorageProvider, logs, releaseTransaction, expectedOutpointsValues); } - public static void assertReleaseWasRejectedAndRefundedToSpendingFederation( - List logs, - BridgeStorageProvider bridgeStorageProvider, - BtcTransaction rejectedRelease, - Federation spendingFederation - ) throws IOException { - // the spending federation is detected as a multisig sender, so the funds sent to the live federations are refunded to it - assertLogRejectedPegin(logs, rejectedRelease, RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER); - assertEventWasNotEmitted(logs, BridgeEvents.UNREFUNDABLE_PEGIN.getEvent()); - assertTrue(bridgeStorageProvider.getHeightIfBtcTxhashIsAlreadyProcessed(rejectedRelease.getHash(false)).isPresent()); - - List refunds = bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries(ACTIVATIONS_ALL).stream() - .map(PegoutsWaitingForConfirmations.Entry::getBtcTransaction) - .filter(release -> release.getInputs().stream().anyMatch(input -> input.getOutpoint().getHash().equals(rejectedRelease.getHash()))) - .toList(); - assertEquals(1, refunds.size()); - BtcTransaction refund = refunds.get(0); - assertEquals(1, refund.getOutputs().size()); - assertEquals(spendingFederation.getAddress(), refund.getOutput(0).getScriptPubKey().getToAddress(rejectedRelease.getParams())); - } - public static void assertLegacyReleaseRejectionWasSettled( BridgeStorageProvider bridgeStorageProvider, List logs, diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java index 94ce0adad68..4d55ebab5eb 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java @@ -2549,203 +2549,4 @@ private static Stream activeAndRetiringFeds() { ); } } - - @Nested - class FederationsPendingBtcUTXOsGracePeriod { - private static final ActivationConfig.ForBlock allActivations = ActivationConfigsForTest.all().forBlock(0); - private static final ActivationConfig.ForBlock vetiverActivations = ActivationConfigsForTest.vetiver900().forBlock(0); - private static final int HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() - + bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); - // while in the grace period, releases created before RSKIP643 are still looked up in the pegout index - private static final int HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - 1; - - private BridgeStorageProvider bridgeStorageProvider; - - @BeforeEach - void setUp() { - activeFederation = P2shP2wshErpFederationBuilder.builder().build(); - } - - @Test - void getTransactionType_withPegoutInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(vetiverActivations); - FederationContext activeFederationContext = FederationContext.builder() - .withActiveFederation(activeFederation) - .build(); - BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); - savePegoutSigHashInPegoutIndex(pegout); - - // act - PegTxType pegTxType = PegUtils.getTransactionType( - vetiverActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - activeFederationContext, - pegout, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withPegoutInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(allActivations); - FederationContext activeFederationContext = FederationContext.builder() - .withActiveFederation(activeFederation) - .build(); - BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); - savePegoutSigHashInPegoutIndex(pegout); - - // act - PegTxType pegTxType = PegUtils.getTransactionType( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - activeFederationContext, - pegout, - HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - ); - - // assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withPegoutInPegoutIndex_afterGracePeriod_shouldBePegin() { - // arrange - setUpBridgeStorageProvider(allActivations); - FederationContext activeFederationContext = FederationContext.builder() - .withActiveFederation(activeFederation) - .build(); - BtcTransaction pegout = buildPegoutWithChangeFromActiveFed(); - savePegoutSigHashInPegoutIndex(pegout); - - // act - PegTxType pegTxType = PegUtils.getTransactionType( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - activeFederationContext, - pegout, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PegTxType.PEGIN, pegTxType); - } - - @Test - void getTransactionType_withMigrationInPegoutIndex_forVetiver_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(vetiverActivations); - FederationContext activeAndRetiringFederationContext = FederationContext.builder() - .withActiveFederation(activeFederation) - .withRetiringFederation(retiringFederation) - .build(); - BtcTransaction migration = buildMigrationTransaction(); - savePegoutSigHashInPegoutIndex(migration); - - // act - PegTxType pegTxType = PegUtils.getTransactionType( - vetiverActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - activeAndRetiringFederationContext, - migration, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withMigrationInPegoutIndex_withinGracePeriod_shouldBePegoutOrMigration() { - // arrange - setUpBridgeStorageProvider(allActivations); - FederationContext activeAndRetiringFederationContext = FederationContext.builder() - .withActiveFederation(activeFederation) - .withRetiringFederation(retiringFederation) - .build(); - BtcTransaction migration = buildMigrationTransaction(); - savePegoutSigHashInPegoutIndex(migration); - - // act - PegTxType pegTxType = PegUtils.getTransactionType( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - activeAndRetiringFederationContext, - migration, - HEIGHT_WITHIN_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD - ); - - // assert - assertEquals(PegTxType.PEGOUT_OR_MIGRATION, pegTxType); - } - - @Test - void getTransactionType_withMigrationInPegoutIndex_afterGracePeriod_shouldBePegin() { - // arrange - setUpBridgeStorageProvider(allActivations); - FederationContext activeAndRetiringFederationContext = FederationContext.builder() - .withActiveFederation(activeFederation) - .withRetiringFederation(retiringFederation) - .build(); - BtcTransaction migration = buildMigrationTransaction(); - savePegoutSigHashInPegoutIndex(migration); - - // act - PegTxType pegTxType = PegUtils.getTransactionType( - allActivations, - bridgeStorageProvider, - bridgeMainnetConstants, - activeAndRetiringFederationContext, - migration, - HEIGHT_AT_WHICH_TO_START_USING_FEDERATIONS_PENDING_BTC_UTXOS - ); - - // assert - assertEquals(PegTxType.PEGIN, pegTxType); - } - - private void setUpBridgeStorageProvider(ActivationConfig.ForBlock activations) { - bridgeStorageProvider = new BridgeStorageProvider( - createRepository(), - btcMainnetParams, - activations - ); - } - - private BtcTransaction buildPegoutWithChangeFromActiveFed() { - return PegoutTransactionBuilder.builder() - .withNetworkParameters(btcMainnetParams) - .withActiveFederation(activeFederation) - .withInput(BitcoinTestUtils.createHash(1), FIRST_OUTPUT_INDEX, Coin.COIN) - .withOutput(Coin.COIN, userAddress) - .withChangeAmount(Coin.COIN) - .build(); - } - - private BtcTransaction buildMigrationTransaction() { - return MigrationTransactionBuilder.builder() - .withNetworkParameters(btcMainnetParams) - .withRetiringFederation(retiringFederation) - .withActiveFederation(activeFederation) - .withOutput(Coin.COIN) - .build(); - } - - private void savePegoutSigHashInPegoutIndex(BtcTransaction releaseTransaction) { - // the same sighash the bridge saves in the pegout index when creating the release - Sha256Hash pegoutTxSigHash = BitcoinUtils.getSigHashForPegoutIndex(releaseTransaction).orElseThrow(); - bridgeStorageProvider.setPegoutTxSigHash(pegoutTxSigHash); - // the sighash is only buffered until saved, while the lookup reads it from the repository - bridgeStorageProvider.save(); - } - } } diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java index 245cc0b6e6d..fa6181f95f1 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java @@ -41,8 +41,6 @@ class PegUtilsTest { private static final FederationConstants federationMainNetConstants = bridgeMainnetConstants.getFederationConstants(); private static final Context context = new Context(bridgeMainnetConstants.getBtcParams()); private static final ActivationConfig.ForBlock allActivations = ActivationConfigsForTest.all().forBlock(0); - private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = bridgeMainnetConstants.getBtcHeightWhenPegoutTxIndexActivates() - + bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); private static final int FIRST_OUTPUT_INDEX = 0; private static final int FIRST_INPUT_INDEX = 0; @@ -184,10 +182,8 @@ void test_getTransactionType_before_rskip379() { PegUtils.getTransactionTypeUsingPegoutIndex( fingerrootActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX - 1 + btcTransaction ) ); @@ -209,10 +205,8 @@ void test_getTransactionType_tx_sending_funds_to_unknown_address() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -233,10 +227,8 @@ void test_getTransactionType_pegin_below_minimum_active_fed() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -256,10 +248,8 @@ void test_getTransactionType_pegin_active_fed() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -282,10 +272,8 @@ void test_getTransactionType_pegin_output_to_active_fed_and_other_addresses() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -308,10 +296,8 @@ void test_getTransactionType_pegin_multiple_outputs_to_active_fed() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -343,10 +329,8 @@ void test_getTransactionType_pegin_output_to_retiring_fed_and_other_addresses() PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -366,10 +350,8 @@ void test_getTransactionType_pegin_retiring_fed() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -392,10 +374,8 @@ void test_getTransactionType_pegin_multiple_outputs_to_retiring_fed() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -417,10 +397,8 @@ void test_getTransactionType_pegin_outputs_to_active_and_retiring_fed() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -444,10 +422,8 @@ void test_getTransactionType_pegin_outputs_to_active_and_retiring_fed_and_other_ PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -481,10 +457,8 @@ void test_getTransactionType_pegout_no_change_output() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -509,10 +483,8 @@ void test_getTransactionType_pegout_no_change_output_sighash_no_exists_in_provid PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -547,10 +519,8 @@ void test_getTransactionType_standard_pegout() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -576,10 +546,8 @@ void test_getTransactionType_standard_pegout_sighash_no_exists_in_provider() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -614,10 +582,8 @@ void test_getTransactionType_migration() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -644,10 +610,8 @@ void test_getTransactionType_migration_sighash_no_exists_in_provider() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -682,10 +646,8 @@ void test_getTransactionType_migration_from_retired_fed() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -728,10 +690,8 @@ void test_getTransactionType_flyover() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert @@ -764,10 +724,8 @@ void test_getTransactionType_flyover_segwit() { PegTxType pegTxType = PegUtils.getTransactionTypeUsingPegoutIndex( allActivations, provider, - bridgeMainnetConstants, liveFederationWallet, - btcTransaction, - HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + btcTransaction ); // Assert diff --git a/rskj-core/src/test/java/co/rsk/peg/constants/BridgeConstantsTest.java b/rskj-core/src/test/java/co/rsk/peg/constants/BridgeConstantsTest.java index 3bf8146cb15..34727a5f6ee 100644 --- a/rskj-core/src/test/java/co/rsk/peg/constants/BridgeConstantsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/constants/BridgeConstantsTest.java @@ -197,25 +197,6 @@ void getPegoutTxIndexGracePeriodInBtcBlocks(BridgeConstants bridgeConstants, int assertEquals(expectedValue, pegoutTxIndexGracePeriodInBtcBlocks); } - private static Stream getBtcHeightWhenFederationsPendingBtcUTXOsActivatesArgProvider() { - return Stream.of( - Arguments.of(BridgeMainNetConstants.getInstance(), 10_000_000), - Arguments.of(BridgeTestNetConstants.getInstance(), 10_000_000), - Arguments.of(BridgeTestNet2Constants.getInstance(), 10_000_000), - Arguments.of(new BridgeRegTestConstants(), 260) - ); - } - - @ParameterizedTest - @MethodSource("getBtcHeightWhenFederationsPendingBtcUTXOsActivatesArgProvider") - void getBtcHeightWhenFederationsPendingBtcUTXOsActivates_shouldReturnNetworkValue(BridgeConstants bridgeConstants, int expectedValue) { - // act - int btcHeightWhenFederationsPendingBtcUTXOsActivates = bridgeConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates(); - - // assert - assertEquals(expectedValue, btcHeightWhenFederationsPendingBtcUTXOsActivates); - } - private static Stream getBtcHeightWhenBlockIndexActivatesArgProvider() { return Stream.of( Arguments.of(BridgeMainNetConstants.getInstance(), 696_022), From 7beb02ea9c5f08e18030c97ff74838695045a975 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Fri, 23 Oct 2026 11:53:06 -0300 Subject: [PATCH 22/23] refactor: remove btcHeightWhenFederationsPendingBtcUTXOsActivates bridge constant --- .../co/rsk/peg/constants/BridgeConstants.java | 5 - .../peg/constants/BridgeMainNetConstants.java | 2 - .../peg/constants/BridgeRegTestConstants.java | 2 - .../constants/BridgeTestNet2Constants.java | 2 - .../peg/constants/BridgeTestNetConstants.java | 2 - ...idgeSupportRegisterBtcTransactionTest.java | 99 +++++++++---------- .../java/co/rsk/peg/BridgeSupportSvpTest.java | 65 ++++++------ 7 files changed, 81 insertions(+), 96 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java index e95346d27ef..1e1b0d51650 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java @@ -72,7 +72,6 @@ public abstract class BridgeConstants { protected int btcHeightWhenPegoutTxIndexActivates; protected int pegoutTxIndexGracePeriodInBtcBlocks; - protected int btcHeightWhenFederationsPendingBtcUTXOsActivates; protected int blockWithTooMuchChainWorkHeight; public NetworkParameters getBtcParams() { @@ -154,9 +153,5 @@ public int getPegoutTxIndexGracePeriodInBtcBlocks() { return pegoutTxIndexGracePeriodInBtcBlocks; } - public int getBtcHeightWhenFederationsPendingBtcUTXOsActivates() { - return btcHeightWhenFederationsPendingBtcUTXOsActivates; - } - public int getBlockWithTooMuchChainWorkHeight() { return blockWithTooMuchChainWorkHeight; } } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java index 540619b3304..68207e1e49d 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java @@ -48,8 +48,6 @@ private BridgeMainNetConstants() { btcHeightWhenPegoutTxIndexActivates = 837_589; // Estimated date Wed, 03 Apr 2024 15:00:00 GMT. 832,430 was the block number at time of calculation pegoutTxIndexGracePeriodInBtcBlocks = THIRTY_DAYS_IN_BTC_BLOCKS; - // TODO: estimate the BTC height for the RSKIP643 activation date once it is scheduled - btcHeightWhenFederationsPendingBtcUTXOsActivates = 10_000_000; blockWithTooMuchChainWorkHeight = 849_138; } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java index d84bc752323..6792592521b 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java @@ -83,8 +83,6 @@ public BridgeRegTestConstants(List federationPublicKeys) { btcHeightWhenPegoutTxIndexActivates = 250; pegoutTxIndexGracePeriodInBtcBlocks = 100; - // TODO: estimate the BTC height for the RSKIP643 activation date once it is scheduled - btcHeightWhenFederationsPendingBtcUTXOsActivates = btcHeightWhenPegoutTxIndexActivates + 10; blockWithTooMuchChainWorkHeight = Integer.MAX_VALUE; } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNet2Constants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNet2Constants.java index ec010621ea4..c42c0171248 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNet2Constants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNet2Constants.java @@ -73,8 +73,6 @@ public class BridgeTestNet2Constants extends BridgeConstants { // Pegout tx index active since genesis btcHeightWhenPegoutTxIndexActivates = 0; pegoutTxIndexGracePeriodInBtcBlocks = 0; - // TODO: estimate the BTC height for the RSKIP643 activation date once it is scheduled - btcHeightWhenFederationsPendingBtcUTXOsActivates = 10_000_000; blockWithTooMuchChainWorkHeight = Integer.MAX_VALUE; } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java index 65f3737792c..724f9883a52 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java @@ -66,8 +66,6 @@ public class BridgeTestNetConstants extends BridgeConstants { btcHeightWhenPegoutTxIndexActivates = 2_589_553; // Estimated date Wed, 20 Mar 2024 15:00:00 GMT. 2,579,823 was the block number at time of calculation pegoutTxIndexGracePeriodInBtcBlocks = 1_440; // 10 days in BTC blocks (considering 1 block every 10 minutes) - // TODO: estimate the BTC height for the RSKIP643 activation date once it is scheduled - btcHeightWhenFederationsPendingBtcUTXOsActivates = 10_000_000; blockWithTooMuchChainWorkHeight = Integer.MAX_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 3dad682f255..785fa947f8a 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -89,9 +89,8 @@ class BridgeSupportRegisterBtcTransactionTest { private static final int BTC_HEIGHT_WHEN_PEGOUT_TX_INDEX_ACTIVATES = bridgeMainnetConstants.getBtcHeightWhenPegoutTxIndexActivates(); private static final int PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS = bridgeMainnetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = BTC_HEIGHT_WHEN_PEGOUT_TX_INDEX_ACTIVATES + PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS; - // past the pegout index start, so releases are not identified by their inputs as legacy releases are - private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainnetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() - + PEGOUT_TX_INDEX_GRACE_PERIOD_IN_BTC_BLOCKS; + private static final int BTC_BLOCKS_BETWEEN_PEGOUT_INDEX_AND_FEDERATIONS_PENDING_BTC_UTXOS = 100; + private static final int HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS = HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + BTC_BLOCKS_BETWEEN_PEGOUT_INDEX_AND_FEDERATIONS_PENDING_BTC_UTXOS; private static final int HEIGHT_BEFORE_USING_PEGOUT_INDEX = 1; private static final int UTXO_HEIGHT_BEFORE_CARDAMOM = 0; private static final Address userAddress = BitcoinTestUtils.createP2PKHAddress(btcMainnetParams, "userAddress"); @@ -3090,7 +3089,7 @@ void registerBtcTransaction_withNoChangeOutput_withoutRetiringFed_withSegwitActi // with no output sent to the live federations, no federations pending utxos are saved // act - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert assertReleaseTxWasNotProcessed(btcTransaction); @@ -3160,7 +3159,7 @@ void registerBtcTransaction_notInPegoutTxIndexWithChangeOutputFromFederation_wit BtcTransaction btcTransaction = getPegoutTxWithOneInputAndOutputWithChange(); // act - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert assertLogRejectedPegin(logs, btcTransaction, LEGACY_PEGIN_MULTISIG_SENDER); @@ -3337,13 +3336,13 @@ void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withRetiring registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3377,13 +3376,13 @@ void registerBtcTransaction_withManyOutputsAndInputsAndChangeOutput_withoutRetir registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3547,13 +3546,13 @@ void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withRetiri registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3587,13 +3586,13 @@ void registerBtcTransaction_withManyOutputsAndOneInputAndChangeOutput_withoutRet registerPegoutTxInFederationsPendingBtcUtxos(btcTransaction); // act - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( btcTransaction, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertPegoutWithChangeWasProcessed(btcTransaction, expectedUtxosRegistered); assertLogUtxosRegisteredForPegoutChange(btcTransaction); @@ -3716,7 +3715,7 @@ void registerBtcTransaction_withNoChangeOutputAndManyInputs_withRetiringFed_with // act // with no output sent to the live federations, no federations pending utxos are saved - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert assertReleaseTxWasNotProcessed(btcTransaction); @@ -3745,7 +3744,7 @@ void registerBtcTransaction_withNoChangeOutputAndManyInputs_withoutRetiringFed_w // act // with no output sent to the live federations, no federations pending utxos are saved - registerReleaseTransaction(btcTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(btcTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert assertReleaseTxWasNotProcessed(btcTransaction); @@ -3979,13 +3978,13 @@ void registerBtcTransaction_withOneInputAndOutput_withSegwitActiveAndRetiringFed registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(migrationTx, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertMigrationTxWasProcessed( migrationTx, @@ -4168,13 +4167,13 @@ void registerBtcTransaction_withManyOutputsAndInputs_withSegwitActiveAndRetiring registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(migrationTx, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertMigrationTxWasProcessed( migrationTx, @@ -4307,13 +4306,13 @@ void registerBtcTransaction_withManyOutputsAndOneInput_withSegwitActiveAndRetiri registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(migrationTx, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertMigrationTxWasProcessed( migrationTx, @@ -4446,13 +4445,13 @@ void registerBtcTransaction_withOneOutputAndManyInputs_withSegwitActiveAndRetiri registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(migrationTx, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertMigrationTxWasProcessed( migrationTx, @@ -4586,13 +4585,13 @@ void registerBtcTransaction_withFlyoverUtxoWithOneInputAndOutput_withSegwitActiv registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(migrationTx, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertMigrationTxWasProcessed( migrationTx, @@ -4844,13 +4843,13 @@ void registerBtcTransaction_fromRetiredFederationNotInStorage_withSegwitActiveFe registerPegoutTxInFederationsPendingBtcUtxos(migrationTx); // act - registerReleaseTransaction(migrationTx, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + registerReleaseTransaction(migrationTx, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( migrationTx, activeFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertMigrationTxWasProcessed( migrationTx, @@ -5432,14 +5431,14 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_shouldRegister pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( pegout, segwitActiveFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); assertReleaseWasRegistered( @@ -5455,7 +5454,7 @@ void registerBtcTransaction_withPegoutWithChangeCreatedForVetiver_shouldRegister } @Test - void registerBtcTransaction_withPegoutWithChange_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withPegoutWithChangeCreatedForCardamom_shouldRegisterChangeInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange BtcTransaction pegout = createPegoutFromActiveFedPayingToUser(PEGOUT_REQUEST_VALUE); setUpBridgeAndFederationSupport(PEGOUT_REGISTRATION_BLOCK_NUMBER); @@ -5465,14 +5464,14 @@ void registerBtcTransaction_withPegoutWithChange_shouldRegisterChangeInActiveFed pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( pegout, segwitActiveFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getActiveFederationBtcUTXOs()); assertReleaseWasRegistered( @@ -5488,7 +5487,7 @@ void registerBtcTransaction_withPegoutWithChange_shouldRegisterChangeInActiveFed } @Test - void registerBtcTransaction_withPegoutWithoutChange_shouldNotRegister() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withPegoutWithoutChangeCreatedForCardamom_shouldNotRegister() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange // with no output sent to the live federations, no federations pending utxos are saved // requesting the whole input value leaves no change @@ -5500,7 +5499,7 @@ void registerBtcTransaction_withPegoutWithoutChange_shouldNotRegister() throws B pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); // assert @@ -5524,7 +5523,7 @@ void registerBtcTransaction_withPegoutWithoutChangeCreatedForVetiver_shouldMarkA pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // assert @@ -5550,14 +5549,14 @@ void registerBtcTransaction_withPegoutToActiveFed_afterChangingToRetiringFed_sho pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); // assert List expectedUtxosRegistered = buildExpectedUtxosRegistered( pegout, segwitActiveFederation, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); assertUtxosAreEqual(expectedUtxosRegistered, federationSupport.getRetiringFederationBtcUTXOs()); assertTrue(federationSupport.getActiveFederationBtcUTXOs().isEmpty()); @@ -5586,7 +5585,7 @@ void registerBtcTransaction_withPegoutToActiveFed_afterChangingToRetiredFed_shou pegout, segwitActiveFederation, segwitActiveFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); // assert @@ -5614,7 +5613,7 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran PartialMerkleTree pmtWithWitness = buildPMTAndRecreateChainForSegwitTransactionRegistration( bridgeStorageProvider, bridgeMainnetConstants, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS, pegout, btcBlockStore ); @@ -5622,7 +5621,7 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran PartialMerkleTree pmtWithTxId = createValidPmtForTransactionsHashes(List.of(pegout.getHash()), btcMainnetParams); bridgeSupport.registerPegoutTransaction( pegout.getHash(), - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS, pmtWithTxId.bitcoinSerialize() ); bridgeSupport.save(); @@ -5637,7 +5636,7 @@ void registerBtcTransaction_withPegoutAlreadyRegisteredThroughRegisterPegoutTran bridgeSupport.registerBtcTransaction( rskTx, pegout.bitcoinSerialize(), - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD, + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS, pmtWithWitness.bitcoinSerialize() ); bridgeSupport.save(); @@ -5662,7 +5661,7 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_shouldRe migrationTransaction, retiringFederation, retiringFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); // assert @@ -5670,12 +5669,12 @@ void registerBtcTransaction_withMigrationWithOneOutputCreatedForVetiver_shouldRe assertMigrationWasRegisteredInActiveFed( migrationTransaction, List.of(0L), - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX ); } @Test - void registerBtcTransaction_withMigrationWithOneOutput_shouldRegisterMigratedUtxosInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { + void registerBtcTransaction_withMigrationWithOneOutputCreatedForCardamom_shouldRegisterMigratedUtxosInActiveFed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange BtcTransaction migrationTransaction = createMigrationFromRetiringFedToActiveFed(INPUT_VALUE); setUpBridgeAndFederationSupport(MIGRATION_REGISTRATION_BLOCK_NUMBER); @@ -5685,7 +5684,7 @@ void registerBtcTransaction_withMigrationWithOneOutput_shouldRegisterMigratedUtx migrationTransaction, retiringFederation, retiringFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); // assert @@ -5693,7 +5692,7 @@ void registerBtcTransaction_withMigrationWithOneOutput_shouldRegisterMigratedUtx assertMigrationWasRegisteredInActiveFed( migrationTransaction, List.of(0L), - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); } @@ -5708,7 +5707,7 @@ void registerBtcTransaction_withMigrationWithFixedValueOutputs_shouldRegisterMig migrationTransaction, retiringFederation, retiringFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); // assert @@ -5716,7 +5715,7 @@ void registerBtcTransaction_withMigrationWithFixedValueOutputs_shouldRegisterMig assertMigrationWasRegisteredInActiveFed( migrationTransaction, List.of(0L, 1L, 2L), - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); } @@ -5732,7 +5731,7 @@ void registerBtcTransaction_withMigrationWithEvenlyDistributedOutputs_withMaximu migrationTransaction, retiringFederation, retiringFederationKeys, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); // assert @@ -5744,7 +5743,7 @@ void registerBtcTransaction_withMigrationWithEvenlyDistributedOutputs_withMaximu assertMigrationWasRegisteredInActiveFed( migrationTransaction, expectedOutputIndexes, - HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD + HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS ); } 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 e53b9b5abb3..7ed6252483a 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSvpTest.java @@ -70,12 +70,11 @@ class BridgeSupportSvpTest { private static final RskAddress bridgeContractAddress = PrecompiledContracts.BRIDGE_ADDR; private static final BridgeConstants bridgeMainNetConstants = BridgeMainNetConstants.getInstance(); private static final NetworkParameters btcMainnetParams = bridgeMainNetConstants.getBtcParams(); - // releases created before RSKIP643 are identified through the pegout index from this height on - private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = bridgeMainNetConstants.getBtcHeightWhenPegoutTxIndexActivates() - + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); // past the pegout index start, so releases are not identified by their inputs as legacy releases are - private static final int HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD = bridgeMainNetConstants.getBtcHeightWhenFederationsPendingBtcUTXOsActivates() + private static final int HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX = bridgeMainNetConstants.getBtcHeightWhenPegoutTxIndexActivates() + bridgeMainNetConstants.getPegoutTxIndexGracePeriodInBtcBlocks(); + private static final int BTC_BLOCKS_BETWEEN_PEGOUT_INDEX_AND_FEDERATIONS_PENDING_BTC_UTXOS = 100; + private static final int HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS = HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX + BTC_BLOCKS_BETWEEN_PEGOUT_INDEX_AND_FEDERATIONS_PENDING_BTC_UTXOS; private static final FederationConstants federationMainNetConstants = bridgeMainNetConstants.getFederationConstants(); private static final BtcLockSenderProvider btcLockSenderProvider = new BtcLockSenderProvider(); private static final PeginInstructionsProvider peginInstructionsProvider = new PeginInstructionsProvider(); @@ -787,7 +786,7 @@ class FundTxRegistrationTests { @Test void registerBtcTransaction_forSvpFundTransactionChange_whenProposedFederationDoesNotExist_shouldRegisterTransactionButNotUpdateSvpFundTransactionValues() throws Exception { // arrange - arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered(); + arrangeSvpFundTransactionCreatedForCardamomFromSegwitActiveFederationToBeRegistered(); federationStorageProvider.setProposedFederation(null); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -833,7 +832,7 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenValidationPeriodEnde void registerBtcTransaction_forSvpFundTransactionChange_whenValidationPeriodEnded_shouldRegisterChangeUtxoButNotUpdateSvpFundTransactionValues() throws Exception { // arrange arrangeExecutionBlockIsAfterValidationPeriodEnded(); - arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered(); + arrangeSvpFundTransactionCreatedForCardamomFromSegwitActiveFederationToBeRegistered(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -845,10 +844,10 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenValidationPeriodEnde } @Test - void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_shouldRegisterChangeUtxo() throws Exception { + void registerBtcTransaction_forSvpFundTransactionChange_whenSvpValuesWereCleared_withFundTxCreatedForCardamom_shouldRegisterChangeUtxo() throws Exception { // arrange arrangeExecutionBlockIsAfterValidationPeriodEnded(); - arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered(); + arrangeSvpFundTransactionCreatedForCardamomFromSegwitActiveFederationToBeRegistered(); arrangeSvpValuesWereClearedAfterValidationPeriodEnded(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -942,7 +941,7 @@ void registerBtcTransaction_forNormalPegout_whenSvpPeriodIsOngoing_shouldRegiste FEDERATIONS_PENDING_UTXO_HEIGHT ); federationSupport.storeFederationsPendingBtcUTXOs(pegout.getHash(), pegoutChangeUtxos); - setUpForTransactionRegistration(pegout, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(pegout, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -969,7 +968,7 @@ void registerBtcTransaction_forSvpFundTransactionWithoutChangeOutput_whenSvpPeri saveSvpFundTransactionHashUnsigned(svpFundTransaction.getHash()); signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); - setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -1015,9 +1014,9 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpPeriodIsOngoing_f } @Test - void registerBtcTransaction_forSvpFundTransactionChange_whenSvpPeriodIsOngoing_shouldRegisterTransactionAndUpdateSvpFundTransactionValues() throws Exception { + void registerBtcTransaction_forSvpFundTransactionChange_whenSvpPeriodIsOngoing_withFundTxCreatedForCardamom_shouldRegisterTransactionAndUpdateSvpFundTransactionValues() throws Exception { // arrange - arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered(); + arrangeSvpFundTransactionCreatedForCardamomFromSegwitActiveFederationToBeRegistered(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); // act @@ -1029,7 +1028,7 @@ void registerBtcTransaction_forSvpFundTransactionChange_whenSvpPeriodIsOngoing_s } @Test - void registerBtcTransaction_forSvpFundTransactionChange_withFundTxCreatedBeforeRSKIP643_shouldRegisterTransactionAndUpdateSvpFundTransactionValues() throws Exception { + void registerBtcTransaction_forSvpFundTransactionChange_whenSvpPeriodIsOngoing_withFundTxCreatedForVetiver_shouldRegisterTransactionAndUpdateSvpFundTransactionValues() throws Exception { // arrange arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered(); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1042,13 +1041,13 @@ void registerBtcTransaction_forSvpFundTransactionChange_withFundTxCreatedBeforeR assertSvpFundTransactionValuesWereUpdated(); } - private void arrangeSvpFundTransactionFromSegwitActiveFederationToBeRegistered() throws BlockStoreException { + private void arrangeSvpFundTransactionCreatedForCardamomFromSegwitActiveFederationToBeRegistered() throws BlockStoreException { setupSegwitActiveFederationWithUtxos(); arrangeSvpFundTransactionUnsigned(); assertTrue(federationSupport.hasFederationsPendingBtcUTXOs(svpFundTransaction.getHash())); signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); - setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); } private void arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederationToBeRegistered() throws BlockStoreException { @@ -1059,7 +1058,7 @@ private void arrangeSvpFundTransactionCreatedForVetiverFromSegwitActiveFederatio signInputs(segwitActiveFederation, segwitActiveFederationKeys, svpFundTransaction); // and it is registered after RSKIP643 - setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpFundTransaction, HEIGHT_AT_WHICH_TO_START_USING_PEGOUT_INDEX); } private void arrangeSvpFundTransactionToBeRegisteredForVetiver() throws BlockStoreException { @@ -1477,7 +1476,7 @@ void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_shouldProcessAndR // arrange setupSegwitActiveFederationWithUtxos(); arrangeSvpSpendTransactionFromSegwitActiveFederation(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); BtcTransaction pegout = PegoutTransactionBuilder.builder() .withActiveFederation(segwitActiveFederation) @@ -1492,7 +1491,7 @@ void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_shouldProcessAndR FEDERATIONS_PENDING_UTXO_HEIGHT ); federationSupport.storeFederationsPendingBtcUTXOs(pegout.getHash(), pegoutChangeUtxos); - setUpForTransactionRegistration(pegout, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(pegout, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1529,7 +1528,7 @@ void registerBtcTransaction_forPegout_whenWaitingForSvpSpendTx_shouldProcessAndR void registerBtcTransaction_forLegacyPeginFromP2pkh_whenWaitingForSvpSpendTx_shouldProcessAndRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); BtcECKey senderPubKey = getBtcEcKeyFromSeed("legacy_pegin_sender"); @@ -1537,7 +1536,7 @@ void registerBtcTransaction_forLegacyPeginFromP2pkh_whenWaitingForSvpSpendTx_sho pegin.addInput(BitcoinTestUtils.createHash(1), 0, scriptSig); Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(pegin, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1574,7 +1573,7 @@ void registerBtcTransaction_forLegacyPeginFromP2pkh_whenWaitingForSvpSpendTx_sho void registerBtcTransaction_forLegacyPeginFromP2shP2wpkh_whenWaitingForSvpSpendTx_shouldProcessAndRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); BtcECKey senderPubKey = getBtcEcKeyFromSeed("legacy_pegin_p2shp2wpkh_sender"); @@ -1592,7 +1591,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wpkh_whenWaitingForSvpSpendT Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(pegin, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1629,7 +1628,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wpkh_whenWaitingForSvpSpendT void registerBtcTransaction_forLegacyPeginFromP2shMultisig_whenWaitingForSvpSpendTx_shouldProcessButNotRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); List pubKeys = Arrays.asList( @@ -1642,7 +1641,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shMultisig_whenWaitingForSvpSpen Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(pegin, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1680,7 +1679,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shMultisig_whenWaitingForSvpSpen void registerBtcTransaction_forLegacyPeginFromP2shP2wsh_whenWaitingForSvpSpendTx_shouldProcessButNotRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); List pubKeys = Arrays.asList( @@ -1702,7 +1701,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wsh_whenWaitingForSvpSpendTx Coin amountToSend = Coin.COIN; pegin.addOutput(amountToSend, activeFederation.getAddress()); - setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(pegin, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1740,7 +1739,7 @@ void registerBtcTransaction_forLegacyPeginFromP2shP2wsh_whenWaitingForSvpSpendTx void registerBtcTransaction_forPeginV1_whenWaitingForSvpSpendTx_shouldProcessAndRegisterPegin_shouldNotProcessNorRegisterSpendTx() throws BlockStoreException, BridgeIllegalArgumentException, IOException, PeginInstructionsException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); BtcTransaction pegin = new BtcTransaction(btcMainnetParams); BtcECKey senderPubKey = getBtcEcKeyFromSeed("legacy_pegin_sender"); @@ -1750,7 +1749,7 @@ void registerBtcTransaction_forPeginV1_whenWaitingForSvpSpendTx_shouldProcessAnd pegin.addOutput(amountToSend, activeFederation.getAddress()); Script opReturnScript = PegTestUtils.createOpReturnScriptForRsk(1, bridgeContractAddress, Optional.empty()); pegin.addOutput(Coin.ZERO, opReturnScript); - setUpForTransactionRegistration(pegin, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(pegin, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1792,7 +1791,7 @@ void registerBtcTransaction_forPeginV1_whenWaitingForSvpSpendTx_shouldProcessAnd void registerBtcTransaction_whenSpendTransactionHashIsNotSaved_shouldBeIdentifiedAsRejectedPeginAndMarkAsProcessed() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange recreateSvpSpendTransactionUnsigned(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); int activeFederationUtxosSizeBeforeRegisteringTx = federationSupport.getActiveFederationBtcUTXOs().size(); Federation activeFederationBeforeRegisteringTx = federationSupport.getActiveFederation(); @@ -1826,7 +1825,7 @@ private void assertProposedFederationExists() { void registerBtcTransaction_whenIsTheSpendTransaction_shouldProcessSpendTxAndSvpSuccess() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1875,7 +1874,7 @@ void registerBtcTransaction_evenIfValidationPeriodEnded_shouldRegisterSpendTxAnd arrangeExecutionBlockIsAfterValidationPeriodEnded(); arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1903,7 +1902,7 @@ void registerBtcTransaction_whenIsTheSpendTransaction_withAmountBelowMinPeginVal addSpendTransactionOutput(amountToSend); saveSvpSpendTransactionValues(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); @@ -1925,7 +1924,7 @@ void registerBtcTransaction_whenIsTheSpendTransaction_withAmountBelowMinPeginVal void registerBtcTransaction_twice_whenIsTheSpendTransaction_shouldRegisterItJustOnce() throws BlockStoreException, BridgeIllegalArgumentException, IOException { // arrange arrangeSvpSpendTransaction(); - setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_AFTER_FEDERATIONS_PENDING_BTC_UTXOS_GRACE_PERIOD); + setUpForTransactionRegistration(svpSpendTransaction, HEIGHT_TO_USE_FEDERATIONS_PENDING_BTC_UTXOS); List activeFederationUtxosBeforeRegisteringTx = new ArrayList<>(federationSupport.getActiveFederationBtcUTXOs()); From 3377eb2d12c14dd9cf20b86174be5a5c73af62c8 Mon Sep 17 00:00:00 2001 From: Julian Len Date: Fri, 23 Oct 2026 12:01:41 -0300 Subject: [PATCH 23/23] fix: deleted unused imports --- .../test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java b/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java index 4d55ebab5eb..9b54bd5f9cb 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java @@ -39,8 +39,6 @@ import co.rsk.peg.federation.constants.FederationConstants; import co.rsk.peg.storage.InMemoryStorage; import co.rsk.peg.storage.StorageAccessor; -import co.rsk.test.builders.MigrationTransactionBuilder; -import co.rsk.test.builders.PegoutTransactionBuilder; import java.util.Arrays; import java.util.List; import java.util.Optional;