diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java index db4398c1560..e1ce72eeb48 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -17,6 +17,7 @@ */ package co.rsk.peg; +import static co.rsk.peg.PegUtils.getFlyoverAddress; import static co.rsk.peg.BridgeUtils.getRegularPegoutTxSize; import static co.rsk.peg.ReleaseTransactionBuilder.BTC_TX_VERSION_2; import static co.rsk.peg.bitcoin.UtxoUtils.extractOutpointValues; @@ -996,7 +997,8 @@ private BtcTransaction createSvpFundTransaction(Federation proposedFederation, C // add outputs to proposed fed and proposed fed with flyover prefix svpFundTransaction.addOutput(spendableValueFromProposedFederation, proposedFederation.getAddress()); - Address proposedFederationWithFlyoverPrefixAddress = getProposedFederationWithFlyoverPrefixAddress(proposedFederation.getRedeemScript()); + Address proposedFederationWithFlyoverPrefixAddress = + getFlyoverAddress(networkParameters, bridgeConstants.getProposedFederationFlyoverPrefix(), proposedFederation.getRedeemScript()); svpFundTransaction.addOutput(spendableValueFromProposedFederation, proposedFederationWithFlyoverPrefixAddress); // complete tx with input and change output @@ -1006,16 +1008,6 @@ private BtcTransaction createSvpFundTransaction(Federation proposedFederation, C return svpFundTransaction; } - private Address getProposedFederationWithFlyoverPrefixAddress(Script federationRedeemScript) { - Script federationWithFlyoverPrefixRedeemScript = FlyoverRedeemScriptBuilderImpl.builder().of( - bridgeConstants.getProposedFederationFlyoverPrefix(), - federationRedeemScript - ); - Script federationWithFlyoverPrefixP2SHScript = ScriptBuilder.createP2SHOutputScript(federationWithFlyoverPrefixRedeemScript); - - return Address.fromP2SHScript(networkParameters, federationWithFlyoverPrefixP2SHScript); - } - private SendRequest createSvpFundTransactionSendRequest(BtcTransaction transaction) { SendRequest sendRequest = SendRequest.forTx(transaction); sendRequest.changeAddress = getActiveFederationAddress(); diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java b/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java index 6e854f8c88a..39bddc7ac2d 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java @@ -19,11 +19,8 @@ import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.crypto.TransactionSignature; -import co.rsk.bitcoinj.script.RedeemScriptParser; +import co.rsk.bitcoinj.script.*; import co.rsk.bitcoinj.script.RedeemScriptParser.MultiSigType; -import co.rsk.bitcoinj.script.RedeemScriptParserFactory; -import co.rsk.bitcoinj.script.Script; -import co.rsk.bitcoinj.script.ScriptChunk; import co.rsk.bitcoinj.wallet.Wallet; import co.rsk.peg.constants.BridgeConstants; import co.rsk.core.RskAddress; 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 f03ffc0b2af..74b04f90281 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PegUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/PegUtils.java @@ -5,14 +5,12 @@ import static co.rsk.peg.pegin.RejectedPeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; import static co.rsk.peg.pegin.RejectedPeginReason.PEGIN_V1_INVALID_PAYLOAD; -import co.rsk.bitcoinj.core.Address; -import co.rsk.bitcoinj.core.BtcTransaction; -import co.rsk.bitcoinj.core.Coin; -import co.rsk.bitcoinj.core.Context; -import co.rsk.bitcoinj.core.Sha256Hash; -import co.rsk.bitcoinj.core.TransactionOutput; +import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.script.Script; +import co.rsk.bitcoinj.script.ScriptBuilder; import co.rsk.bitcoinj.wallet.Wallet; +import co.rsk.crypto.Keccak256; +import co.rsk.peg.bitcoin.FlyoverRedeemScriptBuilderImpl; import co.rsk.peg.constants.BridgeConstants; import co.rsk.peg.bitcoin.BitcoinUtils; import co.rsk.peg.btcLockSender.BtcLockSender.TxSenderAddressType; @@ -198,4 +196,19 @@ private static PeginEvaluationResult evaluateLegacyPeginSender(TxSenderAddressTy return new PeginEvaluationResult(PeginProcessAction.CANNOT_BE_PROCESSED, LEGACY_PEGIN_UNDETERMINED_SENDER); } } + + public static Address getFlyoverAddress(NetworkParameters networkParameters, Keccak256 flyoverDerivationHash, Script redeemScript) { + Script flyoverScriptPubKey = getFlyoverScriptPubKey(flyoverDerivationHash, redeemScript); + + return Address.fromP2SHScript(networkParameters, flyoverScriptPubKey); + } + + public static Script getFlyoverScriptPubKey(Keccak256 flyoverDerivationHash, Script redeemScript) { + Script flyoverRedeemScript = FlyoverRedeemScriptBuilderImpl.builder().of( + flyoverDerivationHash, + redeemScript + ); + + return ScriptBuilder.createP2SHOutputScript(flyoverRedeemScript); + } } diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index 131e7485a57..4ea6d74bc80 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -721,13 +721,8 @@ private void assertOneOutputIsToProposedFederationWithExpectedAmount(List svpFundTransactionUnsignedOutputs) { - Script redeemScriptWithFlyoverPrefix = FlyoverRedeemScriptBuilderImpl.builder().of( - bridgeMainNetConstants.getProposedFederationFlyoverPrefix(), - proposedFederation.getRedeemScript() - ); - Script proposedFederationWithFlyoverPrefixScriptPubKey = ScriptBuilder.createP2SHOutputScript( - redeemScriptWithFlyoverPrefix - ); + Script proposedFederationWithFlyoverPrefixScriptPubKey = + PegUtils.getFlyoverScriptPubKey(bridgeMainNetConstants.getProposedFederationFlyoverPrefix(), proposedFederation.getRedeemScript()); Optional outputToProposedFederationWithFlyoverPrefixOpt = searchForOutput( svpFundTransactionUnsignedOutputs, 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 4f11f52cda9..5b3e27e1513 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsTest.java @@ -18,16 +18,21 @@ import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.time.Instant; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import static co.rsk.peg.PegTestUtils.createFederation; +import static co.rsk.peg.PegUtils.getFlyoverAddress; +import static co.rsk.peg.PegUtils.getFlyoverScriptPubKey; import static co.rsk.peg.federation.FederationTestUtils.createP2shErpFederation; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -61,6 +66,34 @@ void init() { activeFederation = createP2shErpFederation(federationMainNetConstants, activeFedSigners); } + @ParameterizedTest + @MethodSource("derivationHashAndRedeemScriptArgs") + void getFlyoverScriptPubKey_fromRealValues_shouldReturnSameRealOutputScript(Keccak256 flyoverDerivationHash, Script redeemScript) { + Script scriptPubKey = getFlyoverScriptPubKey(flyoverDerivationHash, redeemScript); // OP_HASH160 outputScript OP_EQUAL + byte[] outputScript = Hex.decode("18fc3b52a5b7d5277f41b9765719b45bfa427730"); + + assertArrayEquals(outputScript, scriptPubKey.getPubKeyHash()); + } + + @ParameterizedTest + @MethodSource("derivationHashAndRedeemScriptArgs") + void getFlyoverAddress_fromRealValues_shouldReturnSameRealAddress(Keccak256 flyoverDerivationHash, Script redeemScript) { + Address flyoverAddress = Address.fromBase58(btcMainnetParams, "33y8JWrSe4byp3DKmy2Mkyykz2dzP8Lmvn"); + + assertEquals(flyoverAddress, getFlyoverAddress(btcMainnetParams, flyoverDerivationHash, redeemScript)); + } + + private static Stream derivationHashAndRedeemScriptArgs() { + // reference from https://mempool.space/tx/ffaebdabce5b1cc1b2ab95657cf087a67ade6a29ecc9ca7d4e2089e346a3e1b3 + + Keccak256 flyoverDerivationHash = new Keccak256("fc2bb93810d3d2332fed0b291c03822100a813eceaa0665896e0c82a8d500439"); + Script redeemScript = new Script(Hex.decode("645521020ace50bab1230f8002a0bfe619482af74b338cc9e4c956add228df47e6adae1c21025093f439fb8006fd29ab56605ffec9cdc840d16d2361004e1337a2f86d8bd2db210275d473555de2733c47125f9702b0f870df1d817379f5587f09b6c40ed2c6c9492102a95f095d0ce8cb3b9bf70cc837e3ebe1d107959b1fa3f9b2d8f33446f9c8cbdb2103250c11be0561b1d7ae168b1f59e39cbc1fd1ba3cf4d2140c1a365b2723a2bf9321034851379ec6b8a701bd3eef8a0e2b119abb4bdde7532a3d6bcbff291b0daf3f25210350179f143a632ce4e6ac9a755b82f7f4266cfebb116a42cadb104c2c2a3350f92103b04fbd87ef5e2c0946a684c8c93950301a45943bbe56d979602038698facf9032103b58a5da144f5abab2e03e414ad044b732300de52fa25c672a7f7b3588877190659ae670350cd00b275532102370a9838e4d15708ad14a104ee5606b36caaaaf739d833e67770ce9fd9b3ec80210257c293086c4d4fe8943deda5f890a37d11bebd140e220faa76258a41d077b4d42103c2660a46aa73078ee6016dee953488566426cf55fc8011edd0085634d75395f92103cd3e383ec6e12719a6c69515e5559bcbe037d0aa24c187e1e26ce932e22ad7b354ae68")); + + return Stream.of( + Arguments.of(flyoverDerivationHash, redeemScript) + ); + } + @Test void test_getTransactionType_before_tbd_600() { // Arrange