Skip to content

Commit 139197e

Browse files
committed
Add getFee and getVSize
1 parent 0d10a4d commit 139197e

File tree

4 files changed

+107
-28
lines changed

4 files changed

+107
-28
lines changed

src/psbt.js

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ class Psbt {
153153
if (input.nonWitnessUtxo) {
154154
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
155155
}
156+
c.__FEE = undefined;
157+
c.__VSIZE = undefined;
156158
c.__FEE_RATE = undefined;
157159
c.__EXTRACTED_TX = undefined;
158160
return this;
@@ -171,6 +173,8 @@ class Psbt {
171173
}
172174
const c = this.__CACHE;
173175
this.data.addOutput(outputData);
176+
c.__FEE = undefined;
177+
c.__VSIZE = undefined;
174178
c.__FEE_RATE = undefined;
175179
c.__EXTRACTED_TX = undefined;
176180
return this;
@@ -187,20 +191,23 @@ class Psbt {
187191
return tx;
188192
}
189193
getFeeRate() {
190-
if (!this.data.inputs.every(isFinalized))
191-
throw new Error('PSBT must be finalized to calculate fee rate');
192-
const c = this.__CACHE;
193-
if (c.__FEE_RATE) return c.__FEE_RATE;
194-
let tx;
195-
let mustFinalize = true;
196-
if (c.__EXTRACTED_TX) {
197-
tx = c.__EXTRACTED_TX;
198-
mustFinalize = false;
199-
} else {
200-
tx = c.__TX.clone();
201-
}
202-
inputFinalizeGetAmts(this.data.inputs, tx, c, mustFinalize);
203-
return c.__FEE_RATE;
194+
return getTxCacheValue(
195+
'__FEE_RATE',
196+
'fee rate',
197+
this.data.inputs,
198+
this.__CACHE,
199+
);
200+
}
201+
getFee() {
202+
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
203+
}
204+
getVSize() {
205+
return getTxCacheValue(
206+
'__VSIZE',
207+
'virtual size',
208+
this.data.inputs,
209+
this.__CACHE,
210+
);
204211
}
205212
finalizeAllInputs() {
206213
utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
@@ -724,6 +731,25 @@ const checkWitnessScript = scriptCheckerFactory(
724731
payments.p2wsh,
725732
'Witness script',
726733
);
734+
function getTxCacheValue(key, name, inputs, c) {
735+
if (!inputs.every(isFinalized))
736+
throw new Error(`PSBT must be finalized to calculate ${name}`);
737+
if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
738+
if (key === '__FEE' && c.__FEE) return c.__FEE;
739+
if (key === '__VSIZE' && c.__VSIZE) return c.__VSIZE;
740+
let tx;
741+
let mustFinalize = true;
742+
if (c.__EXTRACTED_TX) {
743+
tx = c.__EXTRACTED_TX;
744+
mustFinalize = false;
745+
} else {
746+
tx = c.__TX.clone();
747+
}
748+
inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
749+
if (key === '__FEE_RATE') return c.__FEE_RATE;
750+
else if (key === '__FEE') return c.__FEE;
751+
else if (key === '__VSIZE') return c.__VSIZE;
752+
}
727753
function getFinalScripts(
728754
script,
729755
scriptType,
@@ -1124,6 +1150,8 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) {
11241150
throw new Error('Outputs are spending more than Inputs');
11251151
}
11261152
const bytes = tx.virtualSize();
1153+
cache.__VSIZE = bytes;
1154+
cache.__FEE = fee;
11271155
cache.__EXTRACTED_TX = tx;
11281156
cache.__FEE_RATE = Math.floor(fee / bytes);
11291157
}

test/psbt.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,16 @@ describe(`Psbt`, () => {
149149
const fr1 = psbt5.getFeeRate()
150150
const fr2 = psbt5.getFeeRate()
151151
assert.strictEqual(fr1, fr2)
152+
153+
const psbt6 = Psbt.fromBase64(f.psbt)
154+
const f1 = psbt6.getFee()
155+
const f2 = psbt6.getFee()
156+
assert.strictEqual(f1, f2)
157+
158+
const psbt7 = Psbt.fromBase64(f.psbt)
159+
const vs1 = psbt7.getVSize()
160+
const vs2 = psbt7.getVSize()
161+
assert.strictEqual(vs1, vs2)
152162
})
153163
})
154164
})

ts_src/psbt.ts

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ export class Psbt {
194194
if (input.nonWitnessUtxo) {
195195
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
196196
}
197+
c.__FEE = undefined;
198+
c.__VSIZE = undefined;
197199
c.__FEE_RATE = undefined;
198200
c.__EXTRACTED_TX = undefined;
199201
return this;
@@ -214,6 +216,8 @@ export class Psbt {
214216
}
215217
const c = this.__CACHE;
216218
this.data.addOutput(outputData);
219+
c.__FEE = undefined;
220+
c.__VSIZE = undefined;
217221
c.__FEE_RATE = undefined;
218222
c.__EXTRACTED_TX = undefined;
219223
return this;
@@ -232,20 +236,25 @@ export class Psbt {
232236
}
233237

234238
getFeeRate(): number {
235-
if (!this.data.inputs.every(isFinalized))
236-
throw new Error('PSBT must be finalized to calculate fee rate');
237-
const c = this.__CACHE;
238-
if (c.__FEE_RATE) return c.__FEE_RATE;
239-
let tx: Transaction;
240-
let mustFinalize = true;
241-
if (c.__EXTRACTED_TX) {
242-
tx = c.__EXTRACTED_TX;
243-
mustFinalize = false;
244-
} else {
245-
tx = c.__TX.clone();
246-
}
247-
inputFinalizeGetAmts(this.data.inputs, tx, c, mustFinalize);
248-
return c.__FEE_RATE!;
239+
return getTxCacheValue(
240+
'__FEE_RATE',
241+
'fee rate',
242+
this.data.inputs,
243+
this.__CACHE,
244+
)!;
245+
}
246+
247+
getFee(): number {
248+
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE)!;
249+
}
250+
251+
getVSize(): number {
252+
return getTxCacheValue(
253+
'__VSIZE',
254+
'virtual size',
255+
this.data.inputs,
256+
this.__CACHE,
257+
)!;
249258
}
250259

251260
finalizeAllInputs(): this {
@@ -610,6 +619,8 @@ interface PsbtCache {
610619
__TX_IN_CACHE: { [index: string]: number };
611620
__TX: Transaction;
612621
__FEE_RATE?: number;
622+
__FEE?: number;
623+
__VSIZE?: number;
613624
__EXTRACTED_TX?: Transaction;
614625
}
615626

@@ -920,6 +931,32 @@ const checkWitnessScript = scriptCheckerFactory(
920931
'Witness script',
921932
);
922933

934+
type TxCacheNumberKey = '__FEE_RATE' | '__FEE' | '__VSIZE';
935+
function getTxCacheValue(
936+
key: TxCacheNumberKey,
937+
name: string,
938+
inputs: PsbtInput[],
939+
c: PsbtCache,
940+
): number | undefined {
941+
if (!inputs.every(isFinalized))
942+
throw new Error(`PSBT must be finalized to calculate ${name}`);
943+
if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
944+
if (key === '__FEE' && c.__FEE) return c.__FEE;
945+
if (key === '__VSIZE' && c.__VSIZE) return c.__VSIZE;
946+
let tx: Transaction;
947+
let mustFinalize = true;
948+
if (c.__EXTRACTED_TX) {
949+
tx = c.__EXTRACTED_TX;
950+
mustFinalize = false;
951+
} else {
952+
tx = c.__TX.clone();
953+
}
954+
inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
955+
if (key === '__FEE_RATE') return c.__FEE_RATE!;
956+
else if (key === '__FEE') return c.__FEE!;
957+
else if (key === '__VSIZE') return c.__VSIZE!;
958+
}
959+
923960
function getFinalScripts(
924961
script: Buffer,
925962
scriptType: string,
@@ -1398,6 +1435,8 @@ function inputFinalizeGetAmts(
13981435
throw new Error('Outputs are spending more than Inputs');
13991436
}
14001437
const bytes = tx.virtualSize();
1438+
cache.__VSIZE = bytes;
1439+
cache.__FEE = fee;
14011440
cache.__EXTRACTED_TX = tx;
14021441
cache.__FEE_RATE = Math.floor(fee / bytes);
14031442
}

types/psbt.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export declare class Psbt {
5757
addOutput(outputData: PsbtOutputExtended): this;
5858
extractTransaction(disableFeeCheck?: boolean): Transaction;
5959
getFeeRate(): number;
60+
getFee(): number;
61+
getVSize(): number;
6062
finalizeAllInputs(): this;
6163
finalizeInput(inputIndex: number): this;
6264
validateSignaturesOfAllInputs(): boolean;

0 commit comments

Comments
 (0)