Add getFee and getVSize
This commit is contained in:
parent
0d10a4d68e
commit
139197e545
4 changed files with 107 additions and 28 deletions
54
src/psbt.js
54
src/psbt.js
|
@ -153,6 +153,8 @@ class Psbt {
|
||||||
if (input.nonWitnessUtxo) {
|
if (input.nonWitnessUtxo) {
|
||||||
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
||||||
}
|
}
|
||||||
|
c.__FEE = undefined;
|
||||||
|
c.__VSIZE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -171,6 +173,8 @@ class Psbt {
|
||||||
}
|
}
|
||||||
const c = this.__CACHE;
|
const c = this.__CACHE;
|
||||||
this.data.addOutput(outputData);
|
this.data.addOutput(outputData);
|
||||||
|
c.__FEE = undefined;
|
||||||
|
c.__VSIZE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -187,20 +191,23 @@ class Psbt {
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
getFeeRate() {
|
getFeeRate() {
|
||||||
if (!this.data.inputs.every(isFinalized))
|
return getTxCacheValue(
|
||||||
throw new Error('PSBT must be finalized to calculate fee rate');
|
'__FEE_RATE',
|
||||||
const c = this.__CACHE;
|
'fee rate',
|
||||||
if (c.__FEE_RATE) return c.__FEE_RATE;
|
this.data.inputs,
|
||||||
let tx;
|
this.__CACHE,
|
||||||
let mustFinalize = true;
|
);
|
||||||
if (c.__EXTRACTED_TX) {
|
|
||||||
tx = c.__EXTRACTED_TX;
|
|
||||||
mustFinalize = false;
|
|
||||||
} else {
|
|
||||||
tx = c.__TX.clone();
|
|
||||||
}
|
}
|
||||||
inputFinalizeGetAmts(this.data.inputs, tx, c, mustFinalize);
|
getFee() {
|
||||||
return c.__FEE_RATE;
|
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
|
||||||
|
}
|
||||||
|
getVSize() {
|
||||||
|
return getTxCacheValue(
|
||||||
|
'__VSIZE',
|
||||||
|
'virtual size',
|
||||||
|
this.data.inputs,
|
||||||
|
this.__CACHE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
finalizeAllInputs() {
|
finalizeAllInputs() {
|
||||||
utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
|
utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
|
||||||
|
@ -724,6 +731,25 @@ const checkWitnessScript = scriptCheckerFactory(
|
||||||
payments.p2wsh,
|
payments.p2wsh,
|
||||||
'Witness script',
|
'Witness script',
|
||||||
);
|
);
|
||||||
|
function getTxCacheValue(key, name, inputs, c) {
|
||||||
|
if (!inputs.every(isFinalized))
|
||||||
|
throw new Error(`PSBT must be finalized to calculate ${name}`);
|
||||||
|
if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
|
||||||
|
if (key === '__FEE' && c.__FEE) return c.__FEE;
|
||||||
|
if (key === '__VSIZE' && c.__VSIZE) return c.__VSIZE;
|
||||||
|
let tx;
|
||||||
|
let mustFinalize = true;
|
||||||
|
if (c.__EXTRACTED_TX) {
|
||||||
|
tx = c.__EXTRACTED_TX;
|
||||||
|
mustFinalize = false;
|
||||||
|
} else {
|
||||||
|
tx = c.__TX.clone();
|
||||||
|
}
|
||||||
|
inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
|
||||||
|
if (key === '__FEE_RATE') return c.__FEE_RATE;
|
||||||
|
else if (key === '__FEE') return c.__FEE;
|
||||||
|
else if (key === '__VSIZE') return c.__VSIZE;
|
||||||
|
}
|
||||||
function getFinalScripts(
|
function getFinalScripts(
|
||||||
script,
|
script,
|
||||||
scriptType,
|
scriptType,
|
||||||
|
@ -1124,6 +1150,8 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) {
|
||||||
throw new Error('Outputs are spending more than Inputs');
|
throw new Error('Outputs are spending more than Inputs');
|
||||||
}
|
}
|
||||||
const bytes = tx.virtualSize();
|
const bytes = tx.virtualSize();
|
||||||
|
cache.__VSIZE = bytes;
|
||||||
|
cache.__FEE = fee;
|
||||||
cache.__EXTRACTED_TX = tx;
|
cache.__EXTRACTED_TX = tx;
|
||||||
cache.__FEE_RATE = Math.floor(fee / bytes);
|
cache.__FEE_RATE = Math.floor(fee / bytes);
|
||||||
}
|
}
|
||||||
|
|
10
test/psbt.js
10
test/psbt.js
|
@ -149,6 +149,16 @@ describe(`Psbt`, () => {
|
||||||
const fr1 = psbt5.getFeeRate()
|
const fr1 = psbt5.getFeeRate()
|
||||||
const fr2 = psbt5.getFeeRate()
|
const fr2 = psbt5.getFeeRate()
|
||||||
assert.strictEqual(fr1, fr2)
|
assert.strictEqual(fr1, fr2)
|
||||||
|
|
||||||
|
const psbt6 = Psbt.fromBase64(f.psbt)
|
||||||
|
const f1 = psbt6.getFee()
|
||||||
|
const f2 = psbt6.getFee()
|
||||||
|
assert.strictEqual(f1, f2)
|
||||||
|
|
||||||
|
const psbt7 = Psbt.fromBase64(f.psbt)
|
||||||
|
const vs1 = psbt7.getVSize()
|
||||||
|
const vs2 = psbt7.getVSize()
|
||||||
|
assert.strictEqual(vs1, vs2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -194,6 +194,8 @@ export class Psbt {
|
||||||
if (input.nonWitnessUtxo) {
|
if (input.nonWitnessUtxo) {
|
||||||
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
||||||
}
|
}
|
||||||
|
c.__FEE = undefined;
|
||||||
|
c.__VSIZE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -214,6 +216,8 @@ export class Psbt {
|
||||||
}
|
}
|
||||||
const c = this.__CACHE;
|
const c = this.__CACHE;
|
||||||
this.data.addOutput(outputData);
|
this.data.addOutput(outputData);
|
||||||
|
c.__FEE = undefined;
|
||||||
|
c.__VSIZE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -232,20 +236,25 @@ export class Psbt {
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeeRate(): number {
|
getFeeRate(): number {
|
||||||
if (!this.data.inputs.every(isFinalized))
|
return getTxCacheValue(
|
||||||
throw new Error('PSBT must be finalized to calculate fee rate');
|
'__FEE_RATE',
|
||||||
const c = this.__CACHE;
|
'fee rate',
|
||||||
if (c.__FEE_RATE) return c.__FEE_RATE;
|
this.data.inputs,
|
||||||
let tx: Transaction;
|
this.__CACHE,
|
||||||
let mustFinalize = true;
|
)!;
|
||||||
if (c.__EXTRACTED_TX) {
|
|
||||||
tx = c.__EXTRACTED_TX;
|
|
||||||
mustFinalize = false;
|
|
||||||
} else {
|
|
||||||
tx = c.__TX.clone();
|
|
||||||
}
|
}
|
||||||
inputFinalizeGetAmts(this.data.inputs, tx, c, mustFinalize);
|
|
||||||
return c.__FEE_RATE!;
|
getFee(): number {
|
||||||
|
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
getVSize(): number {
|
||||||
|
return getTxCacheValue(
|
||||||
|
'__VSIZE',
|
||||||
|
'virtual size',
|
||||||
|
this.data.inputs,
|
||||||
|
this.__CACHE,
|
||||||
|
)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
finalizeAllInputs(): this {
|
finalizeAllInputs(): this {
|
||||||
|
@ -610,6 +619,8 @@ interface PsbtCache {
|
||||||
__TX_IN_CACHE: { [index: string]: number };
|
__TX_IN_CACHE: { [index: string]: number };
|
||||||
__TX: Transaction;
|
__TX: Transaction;
|
||||||
__FEE_RATE?: number;
|
__FEE_RATE?: number;
|
||||||
|
__FEE?: number;
|
||||||
|
__VSIZE?: number;
|
||||||
__EXTRACTED_TX?: Transaction;
|
__EXTRACTED_TX?: Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,6 +931,32 @@ const checkWitnessScript = scriptCheckerFactory(
|
||||||
'Witness script',
|
'Witness script',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
type TxCacheNumberKey = '__FEE_RATE' | '__FEE' | '__VSIZE';
|
||||||
|
function getTxCacheValue(
|
||||||
|
key: TxCacheNumberKey,
|
||||||
|
name: string,
|
||||||
|
inputs: PsbtInput[],
|
||||||
|
c: PsbtCache,
|
||||||
|
): number | undefined {
|
||||||
|
if (!inputs.every(isFinalized))
|
||||||
|
throw new Error(`PSBT must be finalized to calculate ${name}`);
|
||||||
|
if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
|
||||||
|
if (key === '__FEE' && c.__FEE) return c.__FEE;
|
||||||
|
if (key === '__VSIZE' && c.__VSIZE) return c.__VSIZE;
|
||||||
|
let tx: Transaction;
|
||||||
|
let mustFinalize = true;
|
||||||
|
if (c.__EXTRACTED_TX) {
|
||||||
|
tx = c.__EXTRACTED_TX;
|
||||||
|
mustFinalize = false;
|
||||||
|
} else {
|
||||||
|
tx = c.__TX.clone();
|
||||||
|
}
|
||||||
|
inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
|
||||||
|
if (key === '__FEE_RATE') return c.__FEE_RATE!;
|
||||||
|
else if (key === '__FEE') return c.__FEE!;
|
||||||
|
else if (key === '__VSIZE') return c.__VSIZE!;
|
||||||
|
}
|
||||||
|
|
||||||
function getFinalScripts(
|
function getFinalScripts(
|
||||||
script: Buffer,
|
script: Buffer,
|
||||||
scriptType: string,
|
scriptType: string,
|
||||||
|
@ -1398,6 +1435,8 @@ function inputFinalizeGetAmts(
|
||||||
throw new Error('Outputs are spending more than Inputs');
|
throw new Error('Outputs are spending more than Inputs');
|
||||||
}
|
}
|
||||||
const bytes = tx.virtualSize();
|
const bytes = tx.virtualSize();
|
||||||
|
cache.__VSIZE = bytes;
|
||||||
|
cache.__FEE = fee;
|
||||||
cache.__EXTRACTED_TX = tx;
|
cache.__EXTRACTED_TX = tx;
|
||||||
cache.__FEE_RATE = Math.floor(fee / bytes);
|
cache.__FEE_RATE = Math.floor(fee / bytes);
|
||||||
}
|
}
|
||||||
|
|
2
types/psbt.d.ts
vendored
2
types/psbt.d.ts
vendored
|
@ -57,6 +57,8 @@ export declare class Psbt {
|
||||||
addOutput(outputData: PsbtOutputExtended): this;
|
addOutput(outputData: PsbtOutputExtended): this;
|
||||||
extractTransaction(disableFeeCheck?: boolean): Transaction;
|
extractTransaction(disableFeeCheck?: boolean): Transaction;
|
||||||
getFeeRate(): number;
|
getFeeRate(): number;
|
||||||
|
getFee(): number;
|
||||||
|
getVSize(): number;
|
||||||
finalizeAllInputs(): this;
|
finalizeAllInputs(): this;
|
||||||
finalizeInput(inputIndex: number): this;
|
finalizeInput(inputIndex: number): this;
|
||||||
validateSignaturesOfAllInputs(): boolean;
|
validateSignaturesOfAllInputs(): boolean;
|
||||||
|
|
Loading…
Reference in a new issue