Repository: rsksmart/rskj
Pull request #3045: Transaction witness extraction method
Author: login: julianlen
Created: 2025-03-20T13:27:50Z | Merged: 2025-04-07T19:43:00Z

…tures


<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes in detail -->

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, tests ran to see how -->
<!--- your change affects other areas of the code, etc. -->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Requires Activation Code (Hard Fork)


* **Other information**:



Diff:
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 9af27b9dcb9..0c067665a61 100644
--- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java
+++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java
@@ -2,6 +2,7 @@
 
 import static co.rsk.peg.BridgeSupportTestUtil.*;
 import static co.rsk.peg.PegTestUtils.*;
+import static co.rsk.peg.bitcoin.BitcoinTestUtils.createBaseWitnessThatSpendsFromRedeemScript;
 import static co.rsk.peg.bitcoin.UtxoUtils.extractOutpointValues;
 import static co.rsk.peg.pegin.RejectedPeginReason.*;
 import static co.rsk.peg.utils.NonRefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER;
@@ -2401,10 +2402,8 @@ void flyover_segwit_as_migration_utxo(
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        TransactionWitness txWitness = createBaseWitnessThatSpendsFromRedeemScript(retiringFederation.getRedeemScript());
+        btcTransaction.setWitness(FIRST_INPUT_INDEX, txWitness);
 
         createPmtAndMockBlockStore(btcTransaction, height);
 
@@ -2487,10 +2486,8 @@ void flyover_segwit_as_migration_utxo_with_many_outputs_and_inputs(
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        TransactionWitness txWitness = createBaseWitnessThatSpendsFromRedeemScript(retiringFederation.getRedeemScript());
+        btcTransaction.setWitness(FIRST_INPUT_INDEX, txWitness);
 
         createPmtAndMockBlockStore(btcTransaction, height);
 
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 e2d82b7c895..27693a9c536 100644
--- a/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java
+++ b/rskj-core/src/test/java/co/rsk/peg/PegUtilsGetTransactionTypeTest.java
@@ -1,6 +1,7 @@
 package co.rsk.peg;
 
 import static co.rsk.peg.PegTestUtils.*;
+import static co.rsk.peg.bitcoin.BitcoinTestUtils.createBaseWitnessThatSpendsFromRedeemScript;
 import static co.rsk.peg.federation.FederationTestUtils.createP2shErpFederation;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -1872,10 +1873,9 @@ void flyover_segwit_migration(
         migrationTx.addInput(fundingTx.getOutput(FIRST_OUTPUT_INDEX)).setScriptSig(createBaseInputScriptThatSpendsFromTheFederation(retiringFederation));
         migrationTx.addOutput(Coin.COIN, activeFederation.getAddress());
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        migrationTx.setWitness(0, txWitness);
+        TransactionWitness txWitness = createBaseWitnessThatSpendsFromRedeemScript(retiringFederation.getRedeemScript());
+        migrationTx.setWitness(FIRST_INPUT_INDEX, txWitness);
+
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, migrationTx);
 
@@ -1957,10 +1957,8 @@ void flyover_segwit_with_other_inputs_migration(
             migrationTx.addInput(btcTx.getOutput(0)).setScriptSig(createBaseInputScriptThatSpendsFromTheFederation(retiringFederation));
         }
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        migrationTx.setWitness(0, txWitness);
+        TransactionWitness txWitness = createBaseWitnessThatSpendsFromRedeemScript(retiringFederation.getRedeemScript());
+        migrationTx.setWitness(FIRST_INPUT_INDEX, txWitness);
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, migrationTx);
 
         Sha256Hash firstInputSigHash = migrationTx.hashForSignature(
@@ -2042,10 +2040,9 @@ void flyover_segwit_with_many_inputs_and_outputs_migration(
             btcTransaction.addOutput(Coin.COIN, activeFederation.getAddress());
         }
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        TransactionWitness txWitness = createBaseWitnessThatSpendsFromRedeemScript(retiringFederation.getRedeemScript());
+        btcTransaction.setWitness(FIRST_INPUT_INDEX, txWitness);
+
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
         Sha256Hash firstInputSigHash = btcTransaction.hashForSignature(
diff --git a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
index 4a59a45ebc9..b6d3770a758 100644
--- a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
+++ b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
@@ -256,4 +256,20 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness createBaseWitnessThatSpendsFromRedeemScript(Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        int redeemScriptIndex = witnessSize - 1;
+        txWitness.setPush(redeemScriptIndex, redeemScript.getProgram());
+        return txWitness;
+    }
 }


Reviews:
user: login: julia-zack
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T06:36:52Z
user: login: julia-zack
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T06:37:26Z
user: login: julia-zack
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T06:39:02Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T16:35:28Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T16:36:04Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T16:37:47Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T16:45:31Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T18:07:09Z
user: login: julia-zack
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T11:24:03Z
user: login: julia-zack
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T11:24:34Z
user: login: nathanieliov
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T14:36:20Z
user: login: nathanieliov
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T14:43:19Z
user: login: julia-zack
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T14:50:59Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:04:53Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:46:00Z
user: login: julia-zack
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T19:21:04Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T19:26:48Z
user: login: julianlen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T19:27:17Z
user: login: julia-zack
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T19:34:10Z

Review comments:
diff_hunk: @@ -256,4 +256,26 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static void addWitnessToBtcTxInputWithEmptySignatures(BtcTransaction btcTx, int inputIndex, Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        txWitness.setPush(witnessSize - 1, redeemScript.getProgram());
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julia-zack
body: ```suggestion
        redeemScriptIndex = witnessSize - 1;
        txWitness.setPush(redeemScriptIndex, redeemScript.getProgram());
```
created_at: 2025-03-31T06:36:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2401,10 +2402,7 @@ void flyover_segwit_as_migration_utxo(
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        addWitnessToBtcTxInputWithEmptySignatures(btcTransaction, FIRST_INPUT_INDEX, retiringFederation.getRedeemScript());
path: rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java
user: login: julia-zack
body: ```suggestion
        addBaseWitnessToBtcTxInputThatSpendsFromRedeemScript(btcTransaction, FIRST_INPUT_INDEX, retiringFederation.getRedeemScript());
```
wdyt? A bit more descriptive (i think saying _base_ witness implies you are adding the rs but no signatures)
created_at: 2025-03-31T06:37:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,26 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static void addWitnessToBtcTxInputWithEmptySignatures(BtcTransaction btcTx, int inputIndex, Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        txWitness.setPush(witnessSize - 1, redeemScript.getProgram());
+        btcTx.setWitness(inputIndex, txWitness);
+    }
+
+    public static void addWitnessToBtcTx(BtcTransaction btcTx, int inputIndex, List<byte[]> witness) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julia-zack
body: if we are not using this yet i'd remove it
created_at: 2025-03-31T06:39:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,26 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static void addWitnessToBtcTxInputWithEmptySignatures(BtcTransaction btcTx, int inputIndex, Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        txWitness.setPush(witnessSize - 1, redeemScript.getProgram());
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julianlen
body: done
created_at: 2025-04-03T16:35:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2401,10 +2402,7 @@ void flyover_segwit_as_migration_utxo(
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        addWitnessToBtcTxInputWithEmptySignatures(btcTransaction, FIRST_INPUT_INDEX, retiringFederation.getRedeemScript());
path: rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java
user: login: julianlen
body: agree! done
created_at: 2025-04-03T16:36:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,26 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static void addWitnessToBtcTxInputWithEmptySignatures(BtcTransaction btcTx, int inputIndex, Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        txWitness.setPush(witnessSize - 1, redeemScript.getProgram());
+        btcTx.setWitness(inputIndex, txWitness);
+    }
+
+    public static void addWitnessToBtcTx(BtcTransaction btcTx, int inputIndex, List<byte[]> witness) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julianlen
body: Regarding this, I think part of this "refactor" is to extract the repeating piece of code.

```
TransactionWitness txWitness = new TransactionWitness(1);
txWitness.setPush(0, new byte[]{ 0x1 });
btcTx.setWitness(0, txWitness);
```
Instead we can create a method that given a script it returns the TxWitness
created_at: 2025-04-03T16:37:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,26 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static void addWitnessToBtcTxInputWithEmptySignatures(BtcTransaction btcTx, int inputIndex, Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        txWitness.setPush(witnessSize - 1, redeemScript.getProgram());
+        btcTx.setWitness(inputIndex, txWitness);
+    }
+
+    public static void addWitnessToBtcTx(BtcTransaction btcTx, int inputIndex, List<byte[]> witness) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julianlen
body:     public static TransactionWitness createWitness(List<byte[]> witness) {
        TransactionWitness txWitness = new TransactionWitness(witness.size());
        for (int i = 0; i < witness.size(); i++) {
            txWitness.setPush(i, witness.get(i));
        }
        return txWitness;
    }
created_at: 2025-04-03T16:45:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,26 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static void addWitnessToBtcTxInputWithEmptySignatures(BtcTransaction btcTx, int inputIndex, Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        txWitness.setPush(witnessSize - 1, redeemScript.getProgram());
+        btcTx.setWitness(inputIndex, txWitness);
+    }
+
+    public static void addWitnessToBtcTx(BtcTransaction btcTx, int inputIndex, List<byte[]> witness) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julianlen
body: For the sake of this PR I deleted it but I would consider creating a method to replace all of the 

```
        TransactionWitness txWit = new TransactionWitness(1);
        txWit.setPush(0, new byte[]{});
```

around the code
created_at: 2025-04-03T18:07:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,21 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness addBaseWitnessToBtcTxInputThatSpendsFromRedeemScript(Script redeemScript) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julia-zack
body: ```suggestion
    public static TransactionWitness createBaseWitnessThatSpendsFromRedeemScript(Script redeemScript) {
```

you are not actually adding the witness to the input, right?
created_at: 2025-04-07T11:24:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,21 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness addBaseWitnessToBtcTxInputThatSpendsFromRedeemScript(Script redeemScript) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julia-zack
body: we could have two methods, this one and one also receiving the input index and the tx, wdyt?
created_at: 2025-04-07T11:24:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2401,10 +2402,7 @@ void flyover_segwit_as_migration_utxo(
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        addWitnessToBtcTxInputWithEmptySignatures(btcTransaction, FIRST_INPUT_INDEX, retiringFederation.getRedeemScript());
path: rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java
user: login: nathanieliov
body: I think `addBaseWitnessToBtcTxInput` should be enough. I don't see the need to add this part "ThatSpendsFromRedeemScript".

created_at: 2025-04-07T14:36:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,21 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness addBaseWitnessToBtcTxInputThatSpendsFromRedeemScript(Script redeemScript) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: nathanieliov
body: This is not adding, this is creating/building a TxWitness. I would call it `createBaseWitnessFromRedeemScript` or something similar. This is alike to what we do for normal input scripts [here](https://github.com/rsksmart/bitcoinj-thin/blob/9ad1ce9447dbc1d617c63c38855f9bf45962ab7f/src/main/java/co/rsk/bitcoinj/script/Script.java#L418)
created_at: 2025-04-07T14:43:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2401,10 +2402,7 @@ void flyover_segwit_as_migration_utxo(
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        addWitnessToBtcTxInputWithEmptySignatures(btcTransaction, FIRST_INPUT_INDEX, retiringFederation.getRedeemScript());
path: rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java
user: login: julia-zack
body: using the same name pattern as [here](https://github.com/rsksmart/rskj/blob/master/rskj-core/src/main/java/co/rsk/peg/bitcoin/BitcoinUtils.java#L97)
created_at: 2025-04-07T14:50:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,21 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness addBaseWitnessToBtcTxInputThatSpendsFromRedeemScript(Script redeemScript) {
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julianlen
body: > you are not actually adding the witness to the input, right?

done! beforehand we added the witness, but to separate responsibilities I left this method so it only creates the witness
created_at: 2025-04-07T16:04:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2401,10 +2402,7 @@ void flyover_segwit_as_migration_utxo(
 
         FederationTestUtils.addSignatures(retiringFederation, retiringFedSigners, btcTransaction);
 
-        TransactionWitness txWitness = new TransactionWitness(1);
-        txWitness.setPush(0, new byte[72]); // push for signatures
-        txWitness.setPush(1, retiringFederation.getRedeemScript().getProgram());
-        btcTransaction.setWitness(0, txWitness);
+        addWitnessToBtcTxInputWithEmptySignatures(btcTransaction, FIRST_INPUT_INDEX, retiringFederation.getRedeemScript());
path: rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java
user: login: julianlen
body: I will change it for "create..." because it doesn't add any redeemScripts but builds it
created_at: 2025-04-07T16:46:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,21 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness createBaseWitnessThatSpendsFromRedeemScript(Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        int redeemScriptIndex = witnessSize - 1;
+        txWitness.setPush(redeemScriptIndex, redeemScript.getProgram());
+        return txWitness;
+
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julia-zack
body: extra blank like :D
created_at: 2025-04-07T19:21:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,21 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness createBaseWitnessThatSpendsFromRedeemScript(Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        int redeemScriptIndex = witnessSize - 1;
+        txWitness.setPush(redeemScriptIndex, redeemScript.getProgram());
+        return txWitness;
+
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julianlen
body: done
created_at: 2025-04-07T19:26:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -256,4 +256,21 @@ public static void addInputFromMatchingOutputScript(BtcTransaction transaction,
         searchForOutput(outputs, expectedOutputScript)
             .ifPresent(transaction::addInput);
     }
+
+    public static TransactionWitness createBaseWitnessThatSpendsFromRedeemScript(Script redeemScript) {
+        int pushForOpNotif = 1;
+        int pushForRedeemScript = 1;
+        int witnessSize = pushForOpNotif + pushForRedeemScript + redeemScript.getNumberOfSignaturesRequiredToSpend();
+
+        TransactionWitness txWitness = new TransactionWitness(witnessSize);
+
+        for (int i = 0; i < witnessSize - 1; i++) {
+            txWitness.setPush(i, new byte[72]);
+        }
+
+        int redeemScriptIndex = witnessSize - 1;
+        txWitness.setPush(redeemScriptIndex, redeemScript.getProgram());
+        return txWitness;
+
+    }
 }
path: rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java
user: login: julianlen
body: no extra line 😄 
created_at: 2025-04-07T19:27:17Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-20T13:28:08Z
body: <h1>Dependency Review</h1>
✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.<h2>OpenSSF Scorecard</h2>
<table><tr><th>Package</th><th>Version</th><th>Score</th><th>Details</th></tr>
</table><h2>Scanned Files</h2>
<ul>


<!-- dependency-review-pr-comment-marker -->
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-07T19:37:49Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=rskj&pullRequest=3045) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=rskj&pullRequest=3045&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=rskj&pullRequest=3045&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=rskj&pullRequest=3045&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=rskj&pullRequest=3045&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=rskj&pullRequest=3045&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=rskj&pullRequest=3045)


author_association: NONE