Add getFee and getVSize

This commit is contained in:
junderw 2019-08-26 19:15:05 +09:00
parent 0d10a4d68e
commit 139197e545
No known key found for this signature in database
GPG key ID: B256185D3A971908
4 changed files with 107 additions and 28 deletions

View file

@ -153,6 +153,8 @@ class Psbt {
if (input.nonWitnessUtxo) {
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
}
c.__FEE = undefined;
c.__VSIZE = undefined;
c.__FEE_RATE = undefined;
c.__EXTRACTED_TX = undefined;
return this;
@ -171,6 +173,8 @@ class Psbt {
}
const c = this.__CACHE;
this.data.addOutput(outputData);
c.__FEE = undefined;
c.__VSIZE = undefined;
c.__FEE_RATE = undefined;
c.__EXTRACTED_TX = undefined;
return this;
@ -187,20 +191,23 @@ class Psbt {
return tx;
}
getFeeRate() {
if (!this.data.inputs.every(isFinalized))
throw new Error('PSBT must be finalized to calculate fee rate');
const c = this.__CACHE;
if (c.__FEE_RATE) return c.__FEE_RATE;
let tx;
let mustFinalize = true;
if (c.__EXTRACTED_TX) {
tx = c.__EXTRACTED_TX;
mustFinalize = false;
} else {
tx = c.__TX.clone();
return getTxCacheValue(
'__FEE_RATE',
'fee rate',
this.data.inputs,
this.__CACHE,
);
}
inputFinalizeGetAmts(this.data.inputs, tx, c, mustFinalize);
return c.__FEE_RATE;
getFee() {
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
}
getVSize() {
return getTxCacheValue(
'__VSIZE',
'virtual size',
this.data.inputs,
this.__CACHE,
);
}
finalizeAllInputs() {
utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
@ -724,6 +731,25 @@ const checkWitnessScript = scriptCheckerFactory(
payments.p2wsh,
'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(
script,
scriptType,
@ -1124,6 +1150,8 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) {
throw new Error('Outputs are spending more than Inputs');
}
const bytes = tx.virtualSize();
cache.__VSIZE = bytes;
cache.__FEE = fee;
cache.__EXTRACTED_TX = tx;
cache.__FEE_RATE = Math.floor(fee / bytes);
}

View file

@ -149,6 +149,16 @@ describe(`Psbt`, () => {
const fr1 = psbt5.getFeeRate()
const fr2 = psbt5.getFeeRate()
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)
})
})
})

View file

@ -194,6 +194,8 @@ export class Psbt {
if (input.nonWitnessUtxo) {
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
}
c.__FEE = undefined;
c.__VSIZE = undefined;
c.__FEE_RATE = undefined;
c.__EXTRACTED_TX = undefined;
return this;
@ -214,6 +216,8 @@ export class Psbt {
}
const c = this.__CACHE;
this.data.addOutput(outputData);
c.__FEE = undefined;
c.__VSIZE = undefined;
c.__FEE_RATE = undefined;
c.__EXTRACTED_TX = undefined;
return this;
@ -232,20 +236,25 @@ export class Psbt {
}
getFeeRate(): number {
if (!this.data.inputs.every(isFinalized))
throw new Error('PSBT must be finalized to calculate fee rate');
const c = this.__CACHE;
if (c.__FEE_RATE) return c.__FEE_RATE;
let tx: Transaction;
let mustFinalize = true;
if (c.__EXTRACTED_TX) {
tx = c.__EXTRACTED_TX;
mustFinalize = false;
} else {
tx = c.__TX.clone();
return getTxCacheValue(
'__FEE_RATE',
'fee rate',
this.data.inputs,
this.__CACHE,
)!;
}
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 {
@ -610,6 +619,8 @@ interface PsbtCache {
__TX_IN_CACHE: { [index: string]: number };
__TX: Transaction;
__FEE_RATE?: number;
__FEE?: number;
__VSIZE?: number;
__EXTRACTED_TX?: Transaction;
}
@ -920,6 +931,32 @@ const checkWitnessScript = scriptCheckerFactory(
'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(
script: Buffer,
scriptType: string,
@ -1398,6 +1435,8 @@ function inputFinalizeGetAmts(
throw new Error('Outputs are spending more than Inputs');
}
const bytes = tx.virtualSize();
cache.__VSIZE = bytes;
cache.__FEE = fee;
cache.__EXTRACTED_TX = tx;
cache.__FEE_RATE = Math.floor(fee / bytes);
}

2
types/psbt.d.ts vendored
View file

@ -57,6 +57,8 @@ export declare class Psbt {
addOutput(outputData: PsbtOutputExtended): this;
extractTransaction(disableFeeCheck?: boolean): Transaction;
getFeeRate(): number;
getFee(): number;
getVSize(): number;
finalizeAllInputs(): this;
finalizeInput(inputIndex: number): this;
validateSignaturesOfAllInputs(): boolean;