Merge pull request #1463 from bitcoinjs/addGetFeePsbt
Add getFee and getVSize
This commit is contained in:
commit
07a2769949
7 changed files with 79 additions and 30 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
# 5.1.5
|
||||||
|
__added__
|
||||||
|
- `Psbt` now has `getFee(): number` for use when all inputs are finalized. It returns the satoshi fee of the transaction. Calling getFee, getFeeRate, or extractTransaction will cache these values so if you call one after the other, the second call will return immediately.
|
||||||
|
|
||||||
# 5.1.4
|
# 5.1.4
|
||||||
__changed__
|
__changed__
|
||||||
- `Psbt` inputs using segwit scripts can now work with nonWitnessUtxo as well as the original witnessUtxo. The reasoning for this is that nonWitnessUtxo has all the information contained in the witnessUtxo, so rejecting signing even though we have all the info we need is unnecessary. Trying to sign a non-segwit script with a witnessUtxo will still throw an Error as it should.
|
- `Psbt` inputs using segwit scripts can now work with nonWitnessUtxo as well as the original witnessUtxo. The reasoning for this is that nonWitnessUtxo has all the information contained in the witnessUtxo, so rejecting signing even though we have all the info we need is unnecessary. Trying to sign a non-segwit script with a witnessUtxo will still throw an Error as it should.
|
||||||
|
|
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "bitcoinjs-lib",
|
"name": "bitcoinjs-lib",
|
||||||
"version": "5.1.4",
|
"version": "5.1.5",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "bitcoinjs-lib",
|
"name": "bitcoinjs-lib",
|
||||||
"version": "5.1.4",
|
"version": "5.1.5",
|
||||||
"description": "Client-side Bitcoin JavaScript library",
|
"description": "Client-side Bitcoin JavaScript library",
|
||||||
"main": "./src/index.js",
|
"main": "./src/index.js",
|
||||||
"types": "./types/index.d.ts",
|
"types": "./types/index.d.ts",
|
||||||
|
|
43
src/psbt.js
43
src/psbt.js
|
@ -153,6 +153,7 @@ class Psbt {
|
||||||
if (input.nonWitnessUtxo) {
|
if (input.nonWitnessUtxo) {
|
||||||
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
||||||
}
|
}
|
||||||
|
c.__FEE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -171,6 +172,7 @@ class Psbt {
|
||||||
}
|
}
|
||||||
const c = this.__CACHE;
|
const c = this.__CACHE;
|
||||||
this.data.addOutput(outputData);
|
this.data.addOutput(outputData);
|
||||||
|
c.__FEE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -187,20 +189,15 @@ 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;
|
getFee() {
|
||||||
mustFinalize = false;
|
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
|
||||||
} else {
|
|
||||||
tx = c.__TX.clone();
|
|
||||||
}
|
|
||||||
inputFinalizeGetAmts(this.data.inputs, tx, c, mustFinalize);
|
|
||||||
return c.__FEE_RATE;
|
|
||||||
}
|
}
|
||||||
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 +721,23 @@ 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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
function getFinalScripts(
|
function getFinalScripts(
|
||||||
script,
|
script,
|
||||||
scriptType,
|
scriptType,
|
||||||
|
@ -1124,6 +1138,7 @@ 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.__FEE = fee;
|
||||||
cache.__EXTRACTED_TX = tx;
|
cache.__EXTRACTED_TX = tx;
|
||||||
cache.__FEE_RATE = Math.floor(fee / bytes);
|
cache.__FEE_RATE = Math.floor(fee / bytes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,6 +149,11 @@ 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)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -194,6 +194,7 @@ export class Psbt {
|
||||||
if (input.nonWitnessUtxo) {
|
if (input.nonWitnessUtxo) {
|
||||||
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
addNonWitnessTxCache(this.__CACHE, input, inputIndex);
|
||||||
}
|
}
|
||||||
|
c.__FEE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -214,6 +215,7 @@ export class Psbt {
|
||||||
}
|
}
|
||||||
const c = this.__CACHE;
|
const c = this.__CACHE;
|
||||||
this.data.addOutput(outputData);
|
this.data.addOutput(outputData);
|
||||||
|
c.__FEE = undefined;
|
||||||
c.__FEE_RATE = undefined;
|
c.__FEE_RATE = undefined;
|
||||||
c.__EXTRACTED_TX = undefined;
|
c.__EXTRACTED_TX = undefined;
|
||||||
return this;
|
return this;
|
||||||
|
@ -232,20 +234,16 @@ 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;
|
getFee(): number {
|
||||||
} else {
|
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE)!;
|
||||||
tx = c.__TX.clone();
|
|
||||||
}
|
|
||||||
inputFinalizeGetAmts(this.data.inputs, tx, c, mustFinalize);
|
|
||||||
return c.__FEE_RATE!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finalizeAllInputs(): this {
|
finalizeAllInputs(): this {
|
||||||
|
@ -610,6 +608,7 @@ 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;
|
||||||
__EXTRACTED_TX?: Transaction;
|
__EXTRACTED_TX?: Transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,6 +919,30 @@ const checkWitnessScript = scriptCheckerFactory(
|
||||||
'Witness script',
|
'Witness script',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
type TxCacheNumberKey = '__FEE_RATE' | '__FEE';
|
||||||
|
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;
|
||||||
|
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!;
|
||||||
|
}
|
||||||
|
|
||||||
function getFinalScripts(
|
function getFinalScripts(
|
||||||
script: Buffer,
|
script: Buffer,
|
||||||
scriptType: string,
|
scriptType: string,
|
||||||
|
@ -1398,6 +1421,7 @@ 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.__FEE = fee;
|
||||||
cache.__EXTRACTED_TX = tx;
|
cache.__EXTRACTED_TX = tx;
|
||||||
cache.__FEE_RATE = Math.floor(fee / bytes);
|
cache.__FEE_RATE = Math.floor(fee / bytes);
|
||||||
}
|
}
|
||||||
|
|
1
types/psbt.d.ts
vendored
1
types/psbt.d.ts
vendored
|
@ -57,6 +57,7 @@ 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;
|
||||||
finalizeAllInputs(): this;
|
finalizeAllInputs(): this;
|
||||||
finalizeInput(inputIndex: number): this;
|
finalizeInput(inputIndex: number): this;
|
||||||
validateSignaturesOfAllInputs(): boolean;
|
validateSignaturesOfAllInputs(): boolean;
|
||||||
|
|
Loading…
Reference in a new issue