Repository: caravan-bitcoin/caravan
Pull request #229: fix: removed setters and added private functions to handle count updates
Author: login: krrish-sehgal
Created: 2025-04-08T12:22:37Z | Merged: 2025-04-18T22:28:22Z

fixes #141.

Linked issue #141: Remove setters from PsbtV2.PSBT_GLOBAL_INPUT_COUNT and PsbtV2.PSBT_GLOBAL_OUTPUT_COUNT
The psbtv2 key `PSBT_GLOBAL_INPUT_COUNT` and `PSBT_GLOBAL_OUTPUT_COUNT` represent the number of inputs or outputs on the psbt. On the `PsbtV2` class, these values have setters, however, because setters are public, they might cause these values to disagree with the real number of inputs or outputs tracked in the psbt.

The two values must remain in sync with the number of inputs or outputs being tracked in the map.

I think the easiest way to do this is to remove the setters and only allow the add and delete input/output methods to modify the value of these fields. However, this is a backward incompatible change for those that might require the existence of the setters.
Linked issue comments: user: login: krrish-sehgal
created_at: 2025-04-07T19:04:06Z
body: Hi @Shadouts and @bucko13 , So for this issue i was planning to remove the respective setters in the class, and replace it with helper functions that does the role of updating the count values using the actual number of inputs in the map. 

And then patching the code for any setter calls to use the helper function. 

I wanted to know : 
1. If i am on right track for this ?
2. this is marked major version change , but it doesnt seems like much of a version change to me , let me know if i am wrong. 
3. I see there are two psbtv2 classes , one in caravan-bitcoin and caravan-psbt , so does the change should be required to be done in both ? 
author_association: CONTRIBUTOR
user: login: krrish-sehgal
created_at: 2025-04-08T11:54:08Z
body: @CodeRabbit, can you answer my above comment ? 

author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-08T11:55:53Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
> [!TIP]
> For best results, initiate chat on the files or code changes.

<details>
<summary>🧩 Analysis chain</summary>

@krrish-sehgal Based on my analysis of the codebase:

1. **You're on the right track**: Removing the setters and replacing them with helper functions that update the count values based on the actual number of inputs/outputs in the map is the correct approach. This will prevent inconsistencies between the reported counts and the actual data structure.

2. **Major version change**: This is indeed a major version change according to semantic versioning principles. Removing public setters is a breaking change since any external code directly setting these properties would break. Even if the usage is limited, following semver requires a major version bump for any breaking API changes.

3. **Multiple implementations**: I couldn't find conclusive evidence of two separate PsbtV2 implementations in my searches. If they do exist in both caravan-bitcoin and caravan-psbt packages, you should apply the change to both for consistency. Look for implementations that:
   - Define `PSBT_GLOBAL_INPUT_COUNT` and `PSBT_GLOBAL_OUTPUT_COUNT` properties
   - Have setter methods for these properties

Your approach of updating add/delete input/output methods to maintain the count values automatically is the right solution to ensure data integrity within the PSBT structure.

---

🏁 Script executed:
```
#!/bin/bash
# Search for PsbtV2 class files
echo "Searching for files containing PsbtV2 class..."
fd -t f -e js -e ts "PsbtV2" --exec echo {}
fd -t f -e js -e ts "psbtv2" --exec echo {} --ignore-case

# Let's find files that might reference PSBT_GLOBAL_INPUT_COUNT and PSBT_GLOBAL_OUTPUT_COUNT
echo -e "\nSearching for files referencing PSBT_GLOBAL_INPUT_COUNT or PSBT_GLOBAL_OUTPUT_COUNT..."
rg "PSBT_GLOBAL_INPUT_COUNT|PSBT_GLOBAL_OUTPUT_COUNT" -l
```

Length of output: 1267

---

🏁 Script executed:
```
#!/bin/bash
# Let's look at the implementation of the PsbtV2 classes
echo "Looking for implementations of PsbtV2 class..."
rg "class PsbtV2" -A 10 -B 3

# Let's look at the setter methods for PSBT_GLOBAL_INPUT_COUNT and PSBT_GLOBAL_OUTPUT_COUNT
echo -e "\nLooking for setter methods for the count properties..."
rg "set PSBT_GLOBAL_INPUT_COUNT|set PSBT_GLOBAL_OUTPUT_COUNT" -A 10 -B 3

# Check how these properties are used in the codebase
echo -e "\nChecking usage of these properties..."
rg "\.PSBT_GLOBAL_INPUT_COUNT\s*=" 
rg "\.PSBT_GLOBAL_OUTPUT_COUNT\s*="
```

Length of output: 12340

---

🏁 Script executed:
```
#!/bin/bash
# Let's check the current class implementation more thoroughly
echo "Checking for PsbtV2 class implementation with more context..."
rg "class PsbtV2" -A 50

# Let's look for methods that add or remove inputs/outputs
echo -e "\nLooking for methods that add or remove inputs/outputs..."
rg "add(Input|Output)|delete(Input|Output)" --ignore-case -A 5 -B 5

# Let's check where these properties are being referenced
echo -e "\nChecking references to these properties in the codebase..."
rg "PSBT_GLOBAL_INPUT_COUNT|PSBT_GLOBAL_OUTPUT_COUNT" -A 3 -B 3
```

Length of output: 68593

---

🏁 Script executed:
```
#!/bin/bash
# Let's find the files containing PsbtV2 class
echo "Searching for files containing PsbtV2 class..."
fd "PsbtV2" --type file --exec grep -l "class PsbtV2" {} \;

# For each file found containing the class, let's examine its content
echo -e "\nExamining content of found files..."
fd "PsbtV2" --type file --exec grep -l "class PsbtV2" {} \; | xargs -I{} sh -c 'echo "\n=== File: {} ==="; cat {}'
```

Length of output: 372

---

🏁 Script executed:
```
#!/bin/bash
# Look for package.json files to understand project structure
echo "Checking for package.json files..."
fd "package.json" --type file --exec echo {} \;

# Let's examine the content of the most relevant package.json files
echo -e "\nExamining content of package.json files..."
fd "package.json" --type file | grep -i "psbt\|bitcoin" | xargs -I{} sh -c 'echo "\n=== File: {} ==="; cat {}'

# Let's check if there's any documentation or tests that use these setters
echo -e "\nChecking for tests or documentation that use these setters..."
rg "PSBT_GLOBAL_INPUT_COUNT.*=|PSBT_GLOBAL_OUTPUT_COUNT.*=" --type js --type ts
```

Length of output: 8863

---



</details>

@krrish-sehgal Based on the detailed code analysis:

1. **You are absolutely on the right track.** Removing the setters and replacing them with helper functions that update the count values based on the actual number of inputs/outputs in the maps is the correct approach. This will ensure the counts always stay in sync with the actual data.

2. **This is indeed a major version change.** Even though it might seem small, removing public API methods (the setters) is considered a breaking change according to semantic versioning principles. Any external code directly calling these setters would break after your change. Following semver rules requires a major version bump for any breaking API changes, regardless of how widely those APIs are used.

3. **Yes, both implementations need to be updated.** I've confirmed there are two separate implementations of the PsbtV2 class:
   - In `packages/caravan-psbt/src/psbtv2/psbtv2.ts`
   - In `packages/caravan-bitcoin/src/psbtv2.ts`

   Both have the same issue with setters for `PSBT_GLOBAL_INPUT_COUNT` and `PSBT_GLOBAL_OUTPUT_COUNT`, and both implementations need to be updated for consistency.

Based on the code, it seems these setters are only used internally within methods like `addInput()`, `addOutput()`, `deleteInput()`, and `deleteOutput()`. These methods already calculate the correct counts. Your approach of updating these methods to maintain the counts while removing the public setters is perfect.
author_association: NONE
user: login: krrish-sehgal
created_at: 2025-04-08T12:00:17Z
body: @coderabbitai , in the whole code do you find , any other implementatoin , where this needs to be changed 
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-08T12:00:59Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
> [!TIP]
> For best results, initiate chat on the files or code changes.

<details>
<summary>🧩 Analysis chain</summary>

@krrish-sehgal After thoroughly searching the codebase, I've confirmed that there are only two implementations where the setters need to be changed:

1. `packages/caravan-psbt/src/psbtv2/psbtv2.ts`
2. `packages/caravan-bitcoin/src/psbtv2.ts`

There are no other implementations with similar setter patterns that would need to be modified. Both implementations have the same issue with the setters for `PSBT_GLOBAL_INPUT_COUNT` and `PSBT_GLOBAL_OUTPUT_COUNT` that need to be removed to maintain consistency with the actual input/output counts.

When making these changes, you'll only need to focus on these two files. However, make sure to update the methods that currently use these setters (like `addInput()`, `addOutput()`, `deleteInput()`, and `deleteOutput()`) to directly maintain the count values without using the setters.

---

🏁 Script executed:
```
#!/bin/bash
# Search for all PsbtV2 class implementations in the codebase
echo "=== PsbtV2 Class Implementations ==="
rg "class\s+PsbtV2" -l

# Search for all files referencing PSBT_GLOBAL_INPUT_COUNT or PSBT_GLOBAL_OUTPUT_COUNT
echo -e "\n=== Files Referencing Count Properties ==="
rg "PSBT_GLOBAL_INPUT_COUNT|PSBT_GLOBAL_OUTPUT_COUNT" -l

# Look for setter implementations for these properties
echo -e "\n=== Setter Implementations ==="
rg "set\s+PSBT_GLOBAL_INPUT_COUNT|set\s+PSBT_GLOBAL_OUTPUT_COUNT" -A 5

# Check for similar patterns in other classes
echo -e "\n=== Similar Patterns in Other Classes ==="
rg "set\s+\w*INPUT_COUNT|set\s+\w*OUTPUT_COUNT" -l --ignore-case

# Look for direct assignments to these properties
echo -e "\n=== Direct Assignments ==="
rg "\.PSBT_GLOBAL_INPUT_COUNT\s*=|\.PSBT_GLOBAL_OUTPUT_COUNT\s*=" -A 2 -B 2
```

Length of output: 7420

---



</details>

@krrish-sehgal After doing a comprehensive search of the codebase, I've confirmed that there are only two implementations that need to be modified:

1. `packages/caravan-psbt/src/psbtv2/psbtv2.ts`
2. `packages/caravan-bitcoin/src/psbtv2.ts`

Both have identical setter implementations for `PSBT_GLOBAL_INPUT_COUNT` and `PSBT_GLOBAL_OUTPUT_COUNT` that need to be removed. The search did not find any other classes with similar patterns that would need modification.

I also found several places where these properties are directly assigned values:
- In constructors (setting them to 0)
- In `addInput()` methods 
- In `addOutput()` methods
- In `deleteInput()` methods
- In `deleteOutput()` methods

These assignments will need to be refactored to use private helper methods that properly maintain the counts based on the actual array lengths, as you suggested in your approach.
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-08T12:01:28Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
> [!TIP]
> For best results, initiate chat on the files or code changes.

<details>
<summary>🧩 Analysis chain</summary>

🏁 Script executed:
```
#!/bin/bash
# Search for all PsbtV2 class implementations
echo "=== All PsbtV2 class implementations ==="
rg "class PsbtV2" -l

# Look for definitions of PSBT_GLOBAL_INPUT_COUNT and PSBT_GLOBAL_OUTPUT_COUNT
echo -e "\n=== Property definitions ==="
rg "PSBT_GLOBAL_INPUT_COUNT|PSBT_GLOBAL_OUTPUT_COUNT" -A 2 -B 2

# Search for setter methods for these properties
echo -e "\n=== Setter methods ==="
rg "set PSBT_GLOBAL_INPUT_COUNT|set PSBT_GLOBAL_OUTPUT_COUNT" -A 5 -B 2

# Look for places where these properties are assigned values
echo -e "\n=== Direct assignments to these properties ==="
rg "\.PSBT_GLOBAL_INPUT_COUNT\s*=|\.PSBT_GLOBAL_OUTPUT_COUNT\s*=" -A 2 -B 2

# Check for any imports or references to PsbtV2
echo -e "\n=== References to PsbtV2 ==="
rg "import.*PsbtV2|from.*PsbtV2" -l

# Look for any similar patterns in other classes that might need updating
echo -e "\n=== Similar patterns in other classes ==="
rg "set\s+\w*INPUT_COUNT|set\s+\w*OUTPUT_COUNT" -l
```

Length of output: 46880

---



</details>

@krrish-sehgal Based on my thorough search of the codebase, I've confirmed that there are only two implementations that need to be changed:

1. **PsbtV2 class in packages/caravan-psbt/src/psbtv2/psbtv2.ts**
2. **PsbtV2 class in packages/caravan-bitcoin/src/psbtv2.ts**

Both implementations have the same pattern:
- They both define setters for `PSBT_GLOBAL_INPUT_COUNT` and `PSBT_GLOBAL_OUTPUT_COUNT`
- These setters are used internally in the same way in both classes - when adding/removing inputs and outputs

I haven't found any other implementations in the codebase that would need to be changed. All other references to these properties are read-only (using the getters), which will continue to work after you remove the setters.

The current usage pattern in both classes is identical:
- Init method sets both counts to 0
- addInput updates INPUT_COUNT using push (which returns new length)
- addOutput updates OUTPUT_COUNT using .length
- deleteInput/deleteOutput update counts using .length after modification

Your approach of removing the setters and using helper methods is exactly right for both implementations.
author_association: NONE

Diff:
diff --git a/.changeset/chilly-houses-count.md b/.changeset/chilly-houses-count.md
new file mode 100644
index 0000000000..58c4613c47
--- /dev/null
+++ b/.changeset/chilly-houses-count.md
@@ -0,0 +1,5 @@
+---
+"@caravan/psbt": patch
+---
+
+Replaced the setters with the private functions so that the output and input count always stays in sync with the actual counts in the PSBT.
diff --git a/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts b/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
index 1c3c97f738..550bdc1f6e 100644
--- a/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
+++ b/packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
@@ -1794,3 +1794,63 @@ describe("PsbtV2.toV0", () => {
     },
   );
 });
+
+describe("PsbtV2 addInput", () => {
+  let psbt: PsbtV2;
+  const updateGlobalInputCountSpy = vi.spyOn(
+    PsbtV2.prototype as any,
+    "updateGlobalInputCount",
+  );
+  beforeEach(() => {
+    vi.clearAllMocks();
+    psbt = new PsbtV2();
+  });
+  it("should call updateGlobalInputCount", () => {
+    // Add inputs to the PSBT
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 0), // Dummy txid
+      outputIndex: 0,
+    });
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 1), // Dummy txid
+      outputIndex: 1,
+    });
+    // Verify the global input count
+    const inputCount = psbt.PSBT_GLOBAL_INPUT_COUNT;
+    expect(inputCount).toBeDefined();
+    expect(inputCount).toBe(2);
+    // Once, for creation and once for each call to addInput
+    expect(updateGlobalInputCountSpy).toHaveBeenCalledTimes(3);
+  });
+});
+
+describe("PsbtV2 addOutput", () => {
+  let psbt: PsbtV2;
+  const updateGlobalOutputCountSpy = vi.spyOn(
+    PsbtV2.prototype as any,
+    "updateGlobalOutputCount",
+  );
+
+  beforeEach(() => {
+    vi.clearAllMocks();
+    psbt = new PsbtV2();
+  });
+
+  it("should call updateGlobalOutputCount", () => {
+    psbt.addOutput({
+      amount: 1000,
+      script: Buffer.alloc(25, 0),
+    });
+    psbt.addOutput({
+      amount: 2000,
+      script: Buffer.alloc(25, 1),
+    });
+
+    const outputCount = psbt.PSBT_GLOBAL_OUTPUT_COUNT;
+    expect(outputCount).toBeDefined();
+    expect(outputCount).toBe(2);
+    // Once during creation + once per addOutput
+    expect(updateGlobalOutputCountSpy).toHaveBeenCalledTimes(3);
+  });
+});
+
diff --git a/packages/caravan-psbt/src/psbtv2/psbtv2.ts b/packages/caravan-psbt/src/psbtv2/psbtv2.ts
index d2ce1c8f8a..54d0a0105d 100644
--- a/packages/caravan-psbt/src/psbtv2/psbtv2.ts
+++ b/packages/caravan-psbt/src/psbtv2/psbtv2.ts
@@ -111,12 +111,6 @@ export class PsbtV2 extends PsbtV2Maps {
     return val.readUInt8(0);
   }
 
-  set PSBT_GLOBAL_INPUT_COUNT(count: number) {
-    const bw = new BufferWriter();
-    bw.writeU8(count);
-    this.globalMap.set(KeyType.PSBT_GLOBAL_INPUT_COUNT, bw.render());
-  }
-
   get PSBT_GLOBAL_OUTPUT_COUNT() {
     const val = this.globalMap.get(KeyType.PSBT_GLOBAL_OUTPUT_COUNT);
 
@@ -127,12 +121,6 @@ export class PsbtV2 extends PsbtV2Maps {
     return val.readUInt8(0);
   }
 
-  set PSBT_GLOBAL_OUTPUT_COUNT(count: number) {
-    const bw = new BufferWriter();
-    bw.writeU8(count);
-    this.globalMap.set(KeyType.PSBT_GLOBAL_OUTPUT_COUNT, bw.render());
-  }
-
   get PSBT_GLOBAL_TX_MODIFIABLE() {
     const val =
       this.globalMap.get(KeyType.PSBT_GLOBAL_TX_MODIFIABLE)?.readUInt8(0) || 0;
@@ -728,9 +716,8 @@ export class PsbtV2 extends PsbtV2Maps {
   private create() {
     this.PSBT_GLOBAL_VERSION = 2;
     this.PSBT_GLOBAL_TX_VERSION = 2;
-    this.PSBT_GLOBAL_INPUT_COUNT = 0;
-    this.PSBT_GLOBAL_OUTPUT_COUNT = 0;
-
+    this.updateGlobalInputCount();
+    this.updateGlobalOutputCount();
     // TODO: Right now these values are setting a default. How can it be made to
     // accept values on the constructor method? The Creator role should be
     // allowed to configure these.
@@ -998,7 +985,9 @@ export class PsbtV2 extends PsbtV2Maps {
       map.set(KeyType.PSBT_IN_SIGHASH_TYPE, bw.render());
     }
 
-    this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.push(map);
+    this.inputMaps.push(map);
+    this.updateGlobalInputCount();
+    
   }
 
   public addOutput({
@@ -1055,7 +1044,7 @@ export class PsbtV2 extends PsbtV2Maps {
     }
 
     this.outputMaps.push(map);
-    this.PSBT_GLOBAL_OUTPUT_COUNT = this.outputMaps.length;
+    this.updateGlobalOutputCount();    
   }
 
   /**
@@ -1078,7 +1067,8 @@ export class PsbtV2 extends PsbtV2Maps {
     }
     const newInputs = this.inputMaps.filter((_, i) => i !== index);
     this.inputMaps = newInputs;
-    this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.length;
+    this.updateGlobalInputCount();
+
   }
 
   /**
@@ -1107,7 +1097,7 @@ export class PsbtV2 extends PsbtV2Maps {
     }
 
     this.outputMaps = newOutputs;
-    this.PSBT_GLOBAL_OUTPUT_COUNT = this.outputMaps.length;
+    this.updateGlobalOutputCount();
   }
 
   /**
@@ -1428,4 +1418,22 @@ export class PsbtV2 extends PsbtV2Maps {
     converterMap.convertToV0();
     return converterMap.serialize(format);
   }
-}
+
+  /**
+   * Updates the PSBT_GLOBAL_INPUT_COUNT field in the global map.
+   */
+  private updateGlobalInputCount() {
+    const bw = new BufferWriter();
+    bw.writeU8(this.inputMaps.length);
+    this.globalMap.set(KeyType.PSBT_GLOBAL_INPUT_COUNT, bw.render());
+  }
+  
+  /**
+   * Updates the PSBT_GLOBAL_OUTPUT_COUNT field in the global map.
+   */
+  private updateGlobalOutputCount() {
+    const bw = new BufferWriter();
+    bw.writeU8(this.outputMaps.length);
+    this.globalMap.set(KeyType.PSBT_GLOBAL_OUTPUT_COUNT, bw.render());
+  }
+}
\ No newline at end of file


Reviews:
user: login: Shadouts
body: Overall, looks good, but the new methods should be tested.

Although this is technically a major version increment, which is why I originally refrained from making the change myself, I don't think it's likely that anyone relied on these setters since doing so would have resulted in a mostly-broken PSBT. Even the PSBT protocol allows for this breakage, but I imagine actual consumers of the PSBT probably iterate through actual inputs/outputs and don't rely on the count fields due to this possibility.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T17:25:08Z
user: login: krrish-sehgal
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T19:39:10Z
user: login: krrish-sehgal
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T04:25:17Z
user: login: Shadouts
body: Please revert to a patch version. That was fine. I think I wasn't being clear.

Not as important, but I think the tests could be expanded upon since I don't think the test was sufficiently covering new behavior, but let me know what you think. I've provided a couple of examples. I don't want it to become a burden since this is surely a good change to have merged.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T17:12:42Z
user: login: krrish-sehgal
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T20:46:40Z
user: login: krrish-sehgal
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T20:47:07Z
user: login: krrish-sehgal
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T20:47:27Z
user: login: krrish-sehgal
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T20:47:49Z
user: login: Shadouts
body: Great work!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T22:24:16Z

Review comments:
path: packages/caravan-bitcoin/src/psbtv2.ts
user: login: Shadouts
body: Don't update this module. `PsbtV2` from caravan-bitcoin is deprecated.
created_at: 2025-04-09T17:19:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1428,4 +1418,23 @@ export class PsbtV2 extends PsbtV2Maps {
     converterMap.convertToV0();
     return converterMap.serialize(format);
   }
-}
+
+  /**
+   * Updates the PSBT_GLOBAL_INPUT_COUNT and PSBT_GLOBAL_OUTPUT_COUNT fields
+   * in the global map.
+   */
+  private updateGlobalInputCount() {
+    const bw = new BufferWriter();
+    bw.writeU8(this.inputMaps.length); // or `.size` if inputMaps is a Map
path: packages/caravan-psbt/src/psbtv2/psbtv2.ts
user: login: Shadouts
body: Concerning the comment, `inputMaps` is actually an array of maps. Are you suggesting it might be converted to a map?
created_at: 2025-04-09T17:20:23Z
author_association: CONTRIBUTOR
path: packages/caravan-bitcoin/src/psbtv2.ts
user: login: krrish-sehgal
body: noted.
created_at: 2025-04-09T19:39:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1428,4 +1418,23 @@ export class PsbtV2 extends PsbtV2Maps {
     converterMap.convertToV0();
     return converterMap.serialize(format);
   }
-}
+
+  /**
+   * Updates the PSBT_GLOBAL_INPUT_COUNT and PSBT_GLOBAL_OUTPUT_COUNT fields
+   * in the global map.
+   */
+  private updateGlobalInputCount() {
+    const bw = new BufferWriter();
+    bw.writeU8(this.inputMaps.length); // or `.size` if inputMaps is a Map
path: packages/caravan-psbt/src/psbtv2/psbtv2.ts
user: login: krrish-sehgal
body: Apologies, the comment was just helper , while i was understanding it. Not needed now.
created_at: 2025-04-10T04:25:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,5 @@
+---
+"@caravan/psbt": major
path: .changeset/chilly-houses-count.md
user: login: Shadouts
body: I'm sorry if I wasn't clear. I think even though the change is technically a major increment, we can keep it as a patch version (as you originally had it) since anyone using these setters was using the class in a broken way.
created_at: 2025-04-16T16:20:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1794,3 +1794,51 @@ describe("PsbtV2.toV0", () => {
     },
   );
 });
+
+describe("PsbtV2 private methods", () => {
+  let psbt: PsbtV2;
+
+  beforeEach(() => {
+    psbt = new PsbtV2();
+  });
+
+  it("should correctly update PSBT_GLOBAL_INPUT_COUNT", () => {
+    // Add inputs to the PSBT
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 0), // Dummy txid
+      outputIndex: 0,
+    });
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 1), // Dummy txid
+      outputIndex: 1,
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalInputCount();
+
+    // Verify the global input count
+    const inputCount = psbt.PSBT_GLOBAL_INPUT_COUNT;
+    expect(inputCount).toBeDefined();
+    expect(inputCount).toBe(2);
+  });
+
+  it("should correctly update PSBT_GLOBAL_OUTPUT_COUNT", () => {
+    // Add outputs to the PSBT
+    psbt.addOutput({
+      amount: 1000,
+      script: Buffer.alloc(25, 0), // Dummy script
+    });
+    psbt.addOutput({
+      amount: 2000,
+      script: Buffer.alloc(25, 1), // Dummy script
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalOutputCount();
+
+    // Verify the global output count
+    const outputCount = psbt.PSBT_GLOBAL_OUTPUT_COUNT;
+    expect(outputCount).toBeDefined();
+    expect(outputCount).toBe(2);
+  });
+});
path: packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
user: login: Shadouts
body: nit: end the doc with a newline
created_at: 2025-04-16T16:40:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1794,3 +1794,51 @@ describe("PsbtV2.toV0", () => {
     },
   );
 });
+
+describe("PsbtV2 private methods", () => {
+  let psbt: PsbtV2;
+
+  beforeEach(() => {
+    psbt = new PsbtV2();
+  });
+
+  it("should correctly update PSBT_GLOBAL_INPUT_COUNT", () => {
+    // Add inputs to the PSBT
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 0), // Dummy txid
+      outputIndex: 0,
+    });
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 1), // Dummy txid
+      outputIndex: 1,
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalInputCount();
path: packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
user: login: Shadouts
body: This isn't helping since `addInput` is already calling this method.
created_at: 2025-04-16T16:58:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1794,3 +1794,51 @@ describe("PsbtV2.toV0", () => {
     },
   );
 });
+
+describe("PsbtV2 private methods", () => {
+  let psbt: PsbtV2;
+
+  beforeEach(() => {
+    psbt = new PsbtV2();
+  });
+
+  it("should correctly update PSBT_GLOBAL_INPUT_COUNT", () => {
+    // Add inputs to the PSBT
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 0), // Dummy txid
+      outputIndex: 0,
+    });
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 1), // Dummy txid
+      outputIndex: 1,
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalInputCount();
+
+    // Verify the global input count
+    const inputCount = psbt.PSBT_GLOBAL_INPUT_COUNT;
+    expect(inputCount).toBeDefined();
+    expect(inputCount).toBe(2);
+  });
path: packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
user: login: Shadouts
body: I'm not sure this test is properly formulated. The expected results of this test would have occurred even before your change (your removing of the setters and adding of the updater method). So, it's not necessarily testing your newly added behavior.

Here is a test that specifically checks to see if `updateGlobalInputCount` functions as expected:
```
describe("PsbtV2.updateGlobalInputCount (private)", () => {
  let psbt: PsbtV2;

  beforeEach(() => {
    psbt = new PsbtV2();
  });

  it("Properly updates the input count", () => {
    (psbt as any).inputMaps.push(new Map());
    (psbt as any).inputMaps.push(new Map());
    (psbt as any).updateGlobalInputCount();
    expect(psbt.PSBT_GLOBAL_INPUT_COUNT).toBe(2);
  });
});
```

And your test could be modified to check that `addInput` calls `updateGlobalInputCount` as expected:
```suggestion
describe("PsbtV2 addInput", () => {
  let psbt: PsbtV2;
  const updateGlobalInputCountSpy = vi.spyOn(
    PsbtV2.prototype as any,
    "updateGlobalInputCount",
  );

  beforeEach(() => {
    vi.clearAllMocks();
    psbt = new PsbtV2();
  });

  it("should call updateGlobalInputCount", () => {
    // Add inputs to the PSBT
    psbt.addInput({
      previousTxId: Buffer.alloc(32, 0), // Dummy txid
      outputIndex: 0,
    });
    psbt.addInput({
      previousTxId: Buffer.alloc(32, 1), // Dummy txid
      outputIndex: 1,
    });

    // Verify the global input count
    const inputCount = psbt.PSBT_GLOBAL_INPUT_COUNT;
    expect(inputCount).toBeDefined();
    expect(inputCount).toBe(2);
    // Once, for creation and once for each call to addInput
    expect(updateGlobalInputCountSpy).toHaveBeenCalledTimes(3);
  });
```

Of course, both would need to also be configured to test for output count. What do you think?
created_at: 2025-04-16T17:09:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1794,3 +1794,51 @@ describe("PsbtV2.toV0", () => {
     },
   );
 });
+
+describe("PsbtV2 private methods", () => {
+  let psbt: PsbtV2;
+
+  beforeEach(() => {
+    psbt = new PsbtV2();
+  });
+
+  it("should correctly update PSBT_GLOBAL_INPUT_COUNT", () => {
+    // Add inputs to the PSBT
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 0), // Dummy txid
+      outputIndex: 0,
+    });
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 1), // Dummy txid
+      outputIndex: 1,
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalInputCount();
+
+    // Verify the global input count
+    const inputCount = psbt.PSBT_GLOBAL_INPUT_COUNT;
+    expect(inputCount).toBeDefined();
+    expect(inputCount).toBe(2);
+  });
path: packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
user: login: krrish-sehgal
body: Yes sir , sorry bout that , I have fixed the tests for both, according to your inputs. 
created_at: 2025-04-18T20:46:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1794,3 +1794,51 @@ describe("PsbtV2.toV0", () => {
     },
   );
 });
+
+describe("PsbtV2 private methods", () => {
+  let psbt: PsbtV2;
+
+  beforeEach(() => {
+    psbt = new PsbtV2();
+  });
+
+  it("should correctly update PSBT_GLOBAL_INPUT_COUNT", () => {
+    // Add inputs to the PSBT
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 0), // Dummy txid
+      outputIndex: 0,
+    });
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 1), // Dummy txid
+      outputIndex: 1,
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalInputCount();
+
+    // Verify the global input count
+    const inputCount = psbt.PSBT_GLOBAL_INPUT_COUNT;
+    expect(inputCount).toBeDefined();
+    expect(inputCount).toBe(2);
+  });
+
+  it("should correctly update PSBT_GLOBAL_OUTPUT_COUNT", () => {
+    // Add outputs to the PSBT
+    psbt.addOutput({
+      amount: 1000,
+      script: Buffer.alloc(25, 0), // Dummy script
+    });
+    psbt.addOutput({
+      amount: 2000,
+      script: Buffer.alloc(25, 1), // Dummy script
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalOutputCount();
+
+    // Verify the global output count
+    const outputCount = psbt.PSBT_GLOBAL_OUTPUT_COUNT;
+    expect(outputCount).toBeDefined();
+    expect(outputCount).toBe(2);
+  });
+});
path: packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
user: login: krrish-sehgal
body: fixed in the latest commit.
created_at: 2025-04-18T20:47:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,5 @@
+---
+"@caravan/psbt": major
path: .changeset/chilly-houses-count.md
user: login: krrish-sehgal
body: fixed (reverted back to patch , in the latest commit).
created_at: 2025-04-18T20:47:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1794,3 +1794,51 @@ describe("PsbtV2.toV0", () => {
     },
   );
 });
+
+describe("PsbtV2 private methods", () => {
+  let psbt: PsbtV2;
+
+  beforeEach(() => {
+    psbt = new PsbtV2();
+  });
+
+  it("should correctly update PSBT_GLOBAL_INPUT_COUNT", () => {
+    // Add inputs to the PSBT
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 0), // Dummy txid
+      outputIndex: 0,
+    });
+    psbt.addInput({
+      previousTxId: Buffer.alloc(32, 1), // Dummy txid
+      outputIndex: 1,
+    });
+
+    // Use reflection to call the private method
+    (psbt as any).updateGlobalInputCount();
path: packages/caravan-psbt/src/psbtv2/psbtv2.test.ts
user: login: krrish-sehgal
body: fixed. Thank you. 
created_at: 2025-04-18T20:47:49Z
author_association: CONTRIBUTOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-04-08T12:22:41Z
body: ###  🦋  Changeset detected

Latest commit: bbb03938519b176555000b48ddb8e8e3c64b4dc4

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name          | Type  |
| ------------- | ----- |
| @caravan/psbt | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/krrish-sehgal/caravan/new/remove-setters?filename=.changeset/lemon-tomatoes-push.md&value=---%0A%22%40caravan%2Fpsbt%22%3A%20patch%0A---%0A%0Afix%3A%20removed%20setters%20and%20added%20private%20functions%20to%20handle%20count%20updates%0A)


author_association: NONE
user: login: vercel[bot]
created_at: 2025-04-08T12:22:41Z
body: [vc]: #tMcJtRKJDLctgpnxeu7IkvSwbXvO8//ah6kHnDLaEC0=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJjYXJhdmFuLWNvb3JkaW5hdG9yIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvY29vcmRpbmF0b3IiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vdW5jaGFpbmVkL2NhcmF2YW4tY29vcmRpbmF0b3IvQkg0cTloZ2VndGl1TlVuaHFOaXlBZ0NaY3JKRCIsInByZXZpZXdVcmwiOiJjYXJhdmFuLWNvb3JkaW5hdG9yLWdpdC1mb3JrLWtycmlzaC1zZWhnYWwtcmVtLTY2ZWVjZi11bmNoYWluZWQudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJjYXJhdmFuLWNvb3JkaW5hdG9yLWdpdC1mb3JrLWtycmlzaC1zZWhnYWwtcmVtLTY2ZWVjZi11bmNoYWluZWQudmVyY2VsLmFwcCJ9fV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **caravan-coordinator** | ✅ Ready ([Inspect](https://vercel.com/unchained/caravan-coordinator/BH4q9hgegtiuNUnhqNiyAgCZcrJD)) | [Visit Preview](https://caravan-coordinator-git-fork-krrish-sehgal-rem-66eecf-unchained.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/caravan-coordinator-git-fork-krrish-sehgal-rem-66eecf-unchained.vercel.app?via=pr-comment-feedback-link) | Apr 18, 2025 10:28pm |


author_association: NONE
user: login: krrish-sehgal
created_at: 2025-04-08T12:23:11Z
body: @coderabbitai , can you review the PR and see if i have missed anything or it breaks certain code? 
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-08T12:27:05Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
<details>
<summary>🧩 Analysis chain</summary>

I'll review this PR for you. Let me gather some information about the changes first.

---

🏁 Script executed:
```
#!/bin/bash
# Get information about the PR
gh pr view 229 --json title,body,files,additions,deletions,changedFiles

# Get information about the linked issue
gh issue view 141 --json title,body,url

# Get the list of files modified in the PR
gh pr view 229 --json files -q '.files[].path'
```

Length of output: 1433

---

Now, let me check the actual code changes in the PR to understand what's being modified.

---

🏁 Script executed:
```
#!/bin/bash
# Get the diff of each modified file
echo "Diff for packages/caravan-bitcoin/src/psbtv2.ts:"
git diff origin/master...HEAD -- packages/caravan-bitcoin/src/psbtv2.ts

echo -e "\n\nDiff for packages/caravan-psbt/src/psbtv2/psbtv2.ts:"
git diff origin/master...HEAD -- packages/caravan-psbt/src/psbtv2/psbtv2.ts

# Check the overall structure of the files to understand context
echo -e "\n\nStructure of packages/caravan-bitcoin/src/psbtv2.ts:"
cat packages/caravan-bitcoin/src/psbtv2.ts | grep -E "class|function|export|interface"

echo -e "\n\nStructure of packages/caravan-psbt/src/psbtv2/psbtv2.ts:"
cat packages/caravan-psbt/src/psbtv2/psbtv2.ts | grep -E "class|function|export|interface"
```

Length of output: 2314

---

Let me get the full file content and proper diffs to understand the changes better.

---

🏁 Script executed:
```
#!/bin/bash
# Get the full file content
echo "Content of packages/caravan-bitcoin/src/psbtv2.ts:"
cat packages/caravan-bitcoin/src/psbtv2.ts

echo -e "\n\nContent of packages/caravan-psbt/src/psbtv2/psbtv2.ts:"
cat packages/caravan-psbt/src/psbtv2/psbtv2.ts

# Try to get the diff using different git command syntax
echo -e "\n\nDiff for packages/caravan-bitcoin/src/psbtv2.ts:"
git diff HEAD^ HEAD -- packages/caravan-bitcoin/src/psbtv2.ts

echo -e "\n\nDiff for packages/caravan-psbt/src/psbtv2/psbtv2.ts:"
git diff HEAD^ HEAD -- packages/caravan-psbt/src/psbtv2/psbtv2.ts
```

Length of output: 85713

---



</details>

@krrish-sehgal I've reviewed your PR that removes setters and adds private functions to handle count updates. Here's my analysis:

## Overview
The PR addresses issue #141 by removing public setters for `PSBT_GLOBAL_INPUT_COUNT` and `PSBT_GLOBAL_OUTPUT_COUNT` and adding private functions to keep these values in sync with the actual number of inputs/outputs.

## Findings

### What looks good:
- You've added appropriate private helper methods (`updateGlobalInputCount()` and `updateGlobalOutputCount()`) to update the counts based on the actual length of input/output maps
- These helper methods are called in all the right places:
  - When creating a new PSBT
  - When adding/removing inputs
  - When adding/removing outputs

### Issues found:
1. **Inconsistency between files**: 
   - In `packages/caravan-bitcoin/src/psbtv2.ts`, you've commented out the setter for `PSBT_GLOBAL_INPUT_COUNT`, but the setter for `PSBT_GLOBAL_OUTPUT_COUNT` is still present
   - In `packages/caravan-psbt/src/psbtv2/psbtv2.ts`, both setters have been properly removed

This inconsistency could cause problems because users can still directly set the output count in one implementation but not the other.

## Recommendation
You should remove the `PSBT_GLOBAL_OUTPUT_COUNT` setter from `packages/caravan-bitcoin/src/psbtv2.ts` to maintain consistency between both implementations. This ensures that counts can only be modified through the appropriate add/delete methods.

Overall, the approach looks correct, and this change will prevent potential bugs where the count values could get out of sync with the actual number of inputs/outputs.

<details>
<summary>:white_check_mark: Actions performed</summary>

Review triggered.

> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

</details>
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-08T12:30:18Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
The pull request refactors how the PsbtV2 class manages global input and output counts. The previous implementation used setter methods to directly assign count values; these setters have been removed. In their place, two new private methods—`updateGlobalInputCount` and `updateGlobalOutputCount`—have been introduced. These methods recalculate and update the counts in the global map, using a `BufferWriter`, by assessing the current state of the input and output maps. The update methods are called in the `create`, `addInput`, `addOutput`, `deleteInput`, and `deleteOutput` functions wherever relevant changes to the counts are needed. This change standardizes the updating process for the count values, ensuring that any modifications to the input or output maps are consistently reflected in the global count properties across the affected packages.

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> <details>
> <summary>packages/caravan-bitcoin/src/psbtv2.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 7.32.0
> 
> ESLint couldn't find the plugin "@typescript-eslint/eslint-plugin".
> 
> (The package "@typescript-eslint/eslint-plugin" was not found when loaded as a Node module from the directory "/packages/caravan-bitcoin".)
> 
> It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
> 
>     npm install @typescript-eslint/eslint-plugin@latest --save-dev
> 
> The plugin "@typescript-eslint/eslint-plugin" was referenced from the config file in "packages/caravan-bitcoin/.eslintrc.js » @caravan/eslint-config/library.js".
> 
> If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> <details>
> <summary>packages/caravan-psbt/src/psbtv2/psbtv2.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 7.32.0
> 
> ESLint couldn't find the plugin "@typescript-eslint/eslint-plugin".
> 
> (The package "@typescript-eslint/eslint-plugin" was not found when loaded as a Node module from the directory "/packages/caravan-psbt".)
> 
> It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
> 
>     npm install @typescript-eslint/eslint-plugin@latest --save-dev
> 
> The plugin "@typescript-eslint/eslint-plugin" was referenced from the config file in "packages/caravan-psbt/.eslintrc.cjs » @caravan/eslint-config/library.js".
> 
> If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 6472c00fc0dda5709964a60a1eca934b52a095c4 and f04f1f5a5e18d54d3605bf0881d35f98ca6b9617.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `packages/caravan-bitcoin/src/psbtv2.ts` (7 hunks)
* `packages/caravan-psbt/src/psbtv2/psbtv2.ts` (6 hunks)

</details>

<details>
<summary>🔇 Additional comments (13)</summary><blockquote>

<details>
<summary>packages/caravan-psbt/src/psbtv2/psbtv2.ts (6)</summary>

`719-720`: **Improvement: Using private update methods instead of direct setters.**

The code now uses the private helper methods `updateGlobalInputCount()` and `updateGlobalOutputCount()` to maintain the global counts, which ensures better encapsulation and count accuracy.

---

`988-990`: **Proper update to input count after adding an input.**

The `updateGlobalInputCount()` is correctly called after adding a new input to ensure the count stays synchronized with the actual number of inputs.

---

`1046-1047`: **Proper update to output count after adding an output.**

The `updateGlobalOutputCount()` is correctly called after adding a new output to ensure the count stays synchronized with the actual number of outputs.

---

`1069-1071`: **Proper update to input count after deleting an input.**

The `updateGlobalInputCount()` is correctly called after removing an input to ensure the count stays synchronized with the actual number of inputs.

---

`1099-1101`: **Proper update to output count after deleting an output.**

The `updateGlobalOutputCount()` is correctly called after removing an output to ensure the count stays synchronized with the actual number of outputs.

---

`1421-1440`: **Well-implemented private update methods for global counts.**

The new private methods `updateGlobalInputCount()` and `updateGlobalOutputCount()` ensure that the global map counts are always in sync with the actual number of inputs and outputs by calculating the length directly from the respective maps. This is a more robust approach than relying on setters.

</details>
<details>
<summary>packages/caravan-bitcoin/src/psbtv2.ts (7)</summary>

`415-419`: **Good: Input count setter has been commented out.**

Commenting out the setter for `PSBT_GLOBAL_INPUT_COUNT` is aligned with the PR objective to remove direct setters and use private helper methods instead.

---

`837-838`: **Proper initialization of global counts in create method.**

The `create` method now correctly calls the private methods `updateGlobalInputCount()` and `updateGlobalOutputCount()` to initialize the counts.

---

`989-990`: **Proper update to input count after adding an input.**

The `updateGlobalInputCount()` is correctly called after adding a new input to ensure the count stays synchronized with the actual number of inputs.

---

`1041-1042`: **Proper update to output count after adding an output.**

The `updateGlobalOutputCount()` is correctly called after adding a new output to ensure the count stays synchronized with the actual number of outputs.

---

`1057-1058`: **Proper update to input count after deleting an input.**

The `updateGlobalInputCount()` is correctly called after removing an input to ensure the count stays synchronized with the actual number of inputs.

---

`1079-1080`: **Proper update to output count after deleting an output.**

The `updateGlobalOutputCount()` is correctly called after removing an output to ensure the count stays synchronized with the actual number of outputs.

---

`1277-1294`: **Well-implemented private update methods for global counts.**

The new private methods `updateGlobalInputCount()` and `updateGlobalOutputCount()` ensure that the global map counts are always in sync with the actual number of inputs and outputs by calculating the length directly from the respective maps. This is a more robust approach than relying on setters.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpADK2VmgqyjcEj2wAbb5AokAI7Y0riQABS2AJSQ4rjedJAARABm8AAeXAHM+FL0iCS4NBTImPRotEr0vJLUninYGGLw+BjIBJCwZQkKjWHY3LR1iEmQAO5oyAwBdfRykNgFfADWFBRIsGAFsERofmUoyPBKGOJpiZPWdhhOApSQAEwPAJz8WADi6gAS2AIaMLBPDVmC55IIRM0pPwUrEEMhbIdYvh0JUAogjuiQpAzABGAAsOMg82yuXgGCIXgE3ngDEgBSKlGQKXwfAABlZ7AAhaAAfXeABkAPKcgCC/J5AEkAHJWACqvIAwoLZVLoKz0Bh6OyubyBcKxTzldA5YrlarWf8JW0aBUADSwzwIsm4CiKbAMaQ8dYSOqQBpNcStZBKRDwIjkegdEEYNCkBaDYZIh0FXqnRD2siIbDrckO+TZbRYRCyJqwV0YeAAL0SY3UsAd6DE2D2kBuzDufHwMLJ3DwpU1/DwvdwRywuEBdNkiBozH+HkYXXJnu0zCTZEXHobzpIRHWuDBMPHniYSiJ8l4JCkpzJFNo8ACYkg0fgve81BaWC7yeP+D6kB93ghIgGjmJYCosGwaYOE4IKuEYVoNkwrDsMgBTNK00INrY9qrOsiCbNsux+AEwShBc/iXvAJBjH6rqrkeCxLJArInsoqjqNo6odJm2aeOO1Ctvg443uMly5JQ3j4PgywXAO/FhAxDCLqQwbHIJYQCDMywavIJDpEg4i5qx/wilgaB4CwswUYg3BBvUdHMaxVDsbgnEoJqNJWfJ6AURIVE0WMv7eHMP6au6NC0PaBxoHSlBUcgX6INML4juMlCeHpoh4IkHS7EefBksyFAgoGZkCL+CkTgiBwMdSGAyfQSBZiQIEGPOAR+dRXqklUZ6OYobFqK58DqggRCwNS40RbFUhUH4MnnvgzqIBwRg4v8ABUG2CrNnU0V+CrKdIW1cPOCIkCkKSiOIUjePmJA5FIyC9lSNKxQyJR+iyW4YMOGr0BVf1MH0/aNacrq0O6no1D6NCdCQ3jcPcbDjooyDhKyAxDDQ7ySQIexWsO4F9OEUTqgcmMJjjeN7IKQ54MTpyk6yMQdFjvpHimwNQfjBQA2OE5oE2LYJOS44Jd2v14P9g64H9ILcMBALSJ4KOwGj6ABO5EjSRc3C8PgNR1HdkCQzmFKKTMpWYTF5A0Ry3Iy2MgJYD2fb8J29OpS4ngVL130knkrUPJtG1WPgoY3Z4Io2ddiAncrvn+fcGBCTlXSVb7lTqB+mEw76gKI8jhTq7QyATKUkBEFJ5T666QuwFFRxhDxaKwgJim/lBPvxtjiRMGs10m7WqPS3ptmhrm9LFO0yIMS91K0tuFApELLVGAAzKHEonGcVH0BKmLHRtXAinSYYVmkDCYGEZJMG0BlkAw8gV19jQhbgYwkGQDaf8iaQJFHDrbweR3JYRsKtSAUCoAIVZNwIWyxYzSAAPTXyoD6DAYAhpMDJMgxAFAGDIMVgIXAEgQ4jlZPaBi097hFWYg7XUQpRTimlCaHkSoVRqlElMCC7BEgVXtAIaW1DCjFC+myBhfImEGiNGwjh5oKIgjJIkC8BRTggSgboSACF74ukmLgQRQl6w0M+l/LWBskYUBNoHRIZJmLwIYIglSqCXBoAwWAYhuA8EEKIYgEhZDfH+PIYgC0AJUB3yDI/Jo8hgbBUgAkCoSZbI0GvC2JqQEm6MUZE+MMsAwjTngL4IkvsqR8WRPSBsgNpbczCHeB88R5B2NaJ4eAzBuAJEgq5a2ztCmeDuCJNELoaTTTsZgIxlBWp4lDjYUQvDNTvlaAndqlFqL3AfHM3q3kREfXEfQnUUj9TilkfKdhZouF3EUeJegKQHJwIQUgxALj0GYCweoHBGBvGEM8WQjQFC1xtF4goB+04n7yCFq6dERIjEoDaR09gCy2hzjhAuTAcZAo+HoIXbgXpLzsCJNgIgyAAhvmmh0Gp/49hAWKUhESFVMLFiaOMOsDYha4GbH4NsHZMJu29gOKpI5Wo7WUL4KhE4Or+SBQwQCmyM4srrvgBusQ0AyVdgLR0dhX4D3qVFOSE4sxEBUtNJSqLPTorieuTAm4GKuiEdOcgkKvydyUK1fQxhwBQDIADGE5kCDEDIMoI1czOBen4MIa6khPTzCcioIaWgdCupMFAOA4T+w4F9aQcgVBA3IVOFkNANEszOFcH1aNLk426DAIYN1pgDAOKcSgtBbiXnYKWh8/BXy/GkOCatJIvaDAWEgCKCUfrM1WULbBA8KKlyIHcBOY106wEMXZJ2gAag8dUUrJhAPwCAviYqHq5BbI6vVoji6o2ud9bU3IDnMMlDKE58iuE1QnM6CG4Vc6OsCq2Lq+c4ZqzRlwSmfdcaCAJlLXAjNcDkwHEBuoIH8beDpnLBmXcoNIs8CY3ZV7GGHLvXIs56pX4Xj8r+RA1jpC2QfqU3ZYw9wiQYjy1MCk54TlZEQGm3gACyaBuDqkWCJGKrJOTYEupQAA6nuSgoTk2oVPXwLoMhv5YCQp0/heAMyichAjeQd5EAqDqhSdQTJGjoRjNSfcrUEJLumCQOo6p/2RR+jnPYVYEWYWwzeg0rCH0EZlh5vUt7jmmk4aNS4dwf4BHaWvegI96zX18LPBsdsnwlzRvaHpSle4c33bHLTTGZCTH4Wqxg2YAinDpF0zwX5WQ8u44raDWp+V1ZCeh5iftCZ4Aa21yoSHhz2dS2XTobjfbeEQMicLWAch3nOJGZENjTb3muugdEF9OmJf89Ilh97gsKIppIgLMj5T4ZC/aMkILEnxYM0lrq7M/0DdKCkMRU34ApFkPRicCslbzlZEoBINAOtQb879woJBeudZS+e1CrTCkuBNqnGil2Gy3dVvdpMAQUgJEfPOlSi652oeAkYIVc1vCiuPEdVCLpbPMDqnu1WmAkGdMwgx8DMt+X5ZLewOaVZ3ueEkkQN6zpkRVE8tNBz6ZIAWqaCJJRpxCwqEKeoWQrVQKDu8MUBFiWGJKE3Vmj8EsJfpFshQaa30F5vXYDnaQRgoD2Dk5cvIgGKn7c23hnznDwg1K4JyygZMwGbshcukha71R2LuY4h5Tym2YJbbg9tgSu2/JCQYKAnGBsoiqIB39nhkfwbA0TVDzM/dvgD1YVd66wFh/rY8xt7iY9tp8d84JrJk+QFT+e9PdBM/el9DnjjYOIMF993Y/3yBA+4GDxXutEea/Nrea2z58efkUIML2pI1ua1T+cTPzBniF+N8X92lffaB1DpHQGxI47QSYWx1btqE5pswnwvgMY7R92PSPY/u3YusPO9w95nbT6MGv+gWR2buCidiS6peQe5eI+6WCAmWxGLQiwJsewkkX89AdSS208tKh4gIKYFilA4g0glo1otmjmtU+A/OtIdCt2POXM+OQ2imP8T8PGWYJKNYdYEBX6yWWeEOpcK0zEveoG3gAOkGXWsG1Mwh/eYh6GKY3+PcZIOsDUYCPo6wpGPAb4Ho5cgIWszOf0BwbOn2msqsigL2+8GYAK5s7cmcVcHG7OPcyO5QFkJUnkvgL8LsuKBU4GCUnsyG3sWsfs/CfANitArWJiyAXQUIE2FEUWHoMWzKl2mueBngyWYucBNI9Yi4tAPQDEtGOcuYx62eVM/cDBHQS67GwhdWfGk8FIgmwmomFAEm6gUmSKqAN+jAnOLm1Yr+vOlBb0NBVMPO9hA4CM0OMYNAPRC29ST4mAL4PgbmhRTG3UliRBBOd+VWs0qBfoJmpULm+4iihYo4rkYggiwigs8qiqUY9O/OuYDEFRCG7k+hfKXs7OCmxSEWF0rKLIiQdCdwOyLBis8x1sBwMuw0MYag5mSuRgKuIoauAaeuSYWuogb4uuQYmE48LIJufAZutIFuqx1ureaeIRjuhQ1g+yB2W2x2qoHuqGXutwPuIeymxeo+UB4+5eoem+Dari7iu+ce++jeiezeKeRJB6DuzETu5JLuQWpy7unurY9JFAQ+TJW69CZejJ9i9yW+3JLyvJDenaASApy+wp7egRtAXetQcMQhCGohg+6pI+qp0B6ple0+2pO+nae++pDwB+gpLebepcHeZp9i3elpxRueiGXskGhew+zJDpbJTpnJ1erpHi7pfJnp3py+q+6+VaiaEufK3qFkZ+WaJROawaVABaMEV+UaA0zksa2gFahgOZKm6gPIxwiAPI4qqytAPI04LgYQrqBgOZKQAADHiCkDiCkAAKxoATkkA4gAActAE5eItAG8AAbEOROQIMOXOXOTiCuROSkM8HOdfKuQIM8KuTiAAOz1nVpQBNm4AtllztkrLoE8ier1lAA -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=caravan-bitcoin/caravan&utm_content=229):

> ‼️ **IMPORTANT**
> Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: krrish-sehgal
created_at: 2025-04-09T20:31:54Z
body: > Overall, looks good, but the new methods should be tested.
> 
> Although this is technically a major version increment, which is why I originally refrained from making the change myself, I don't think it's likely that anyone relied on these setters since doing so would have resulted in a mostly-broken PSBT. Even the PSBT protocol allows for this breakage, but I imagine actual consumers of the PSBT probably iterate through actual inputs/outputs and don't rely on the count fields due to this possibility.

Thanks for the feedback , I have made the necessary changes , let me know if the changeset needs to be updated to major. 
Yes sir, you are correct i thought of it as well, but i think it would be a good practice to not expose the setters like that. 
author_association: CONTRIBUTOR
user: login: krrish-sehgal
created_at: 2025-04-18T20:08:50Z
body: Thank you so much @Shadouts  and @bucko13 for your inputs , I'll have made the changes and resolved all your points.
Will wait for a review. 

author_association: CONTRIBUTOR