Add check for spending more than you have
This commit is contained in:
parent
0f76aa935a
commit
ba33f0317f
2 changed files with 36 additions and 45 deletions
36
src/psbt.js
36
src/psbt.js
|
@ -167,8 +167,7 @@ class Psbt extends bip174_1.Psbt {
|
||||||
}
|
}
|
||||||
if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
|
if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
|
||||||
const tx = c.__TX.clone();
|
const tx = c.__TX.clone();
|
||||||
inputFinalizeGetAmts(this.inputs, tx, c, true, false);
|
inputFinalizeGetAmts(this.inputs, tx, c, true);
|
||||||
c.__EXTRACTED_TX = tx;
|
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
getFeeRate() {
|
getFeeRate() {
|
||||||
|
@ -184,18 +183,7 @@ class Psbt extends bip174_1.Psbt {
|
||||||
} else {
|
} else {
|
||||||
tx = c.__TX.clone();
|
tx = c.__TX.clone();
|
||||||
}
|
}
|
||||||
const inputAmount = inputFinalizeGetAmts(
|
inputFinalizeGetAmts(this.inputs, tx, c, mustFinalize);
|
||||||
this.inputs,
|
|
||||||
tx,
|
|
||||||
c,
|
|
||||||
mustFinalize,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
c.__EXTRACTED_TX = tx;
|
|
||||||
const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0);
|
|
||||||
const fee = inputAmount - outputAmount;
|
|
||||||
const bytes = tx.virtualSize();
|
|
||||||
c.__FEE_RATE = Math.floor(fee / bytes);
|
|
||||||
return c.__FEE_RATE;
|
return c.__FEE_RATE;
|
||||||
}
|
}
|
||||||
finalizeAllInputs() {
|
finalizeAllInputs() {
|
||||||
|
@ -830,7 +818,7 @@ function addNonWitnessTxCache(cache, input, inputIndex) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize, getAmounts) {
|
function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) {
|
||||||
let inputAmount = 0;
|
let inputAmount = 0;
|
||||||
inputs.forEach((input, idx) => {
|
inputs.forEach((input, idx) => {
|
||||||
if (mustFinalize && input.finalScriptSig)
|
if (mustFinalize && input.finalScriptSig)
|
||||||
|
@ -840,22 +828,30 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize, getAmounts) {
|
||||||
input.finalScriptWitness,
|
input.finalScriptWitness,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (getAmounts && input.witnessUtxo) {
|
if (input.witnessUtxo) {
|
||||||
inputAmount += input.witnessUtxo.value;
|
inputAmount += input.witnessUtxo.value;
|
||||||
} else if (getAmounts && input.nonWitnessUtxo) {
|
} else if (input.nonWitnessUtxo) {
|
||||||
const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
|
const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
|
||||||
const vout = tx.ins[idx].index;
|
const vout = tx.ins[idx].index;
|
||||||
const out = nwTx.outs[vout];
|
const out = nwTx.outs[vout];
|
||||||
inputAmount += out.value;
|
inputAmount += out.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return inputAmount;
|
const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0);
|
||||||
|
const fee = inputAmount - outputAmount;
|
||||||
|
if (fee < 0) {
|
||||||
|
throw new Error('Outputs are spending more than Inputs');
|
||||||
|
}
|
||||||
|
const bytes = tx.virtualSize();
|
||||||
|
cache.__EXTRACTED_TX = tx;
|
||||||
|
cache.__FEE_RATE = Math.floor(fee / bytes);
|
||||||
}
|
}
|
||||||
function nonWitnessUtxoTxFromCache(cache, input, inputIndex) {
|
function nonWitnessUtxoTxFromCache(cache, input, inputIndex) {
|
||||||
if (!cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex]) {
|
const c = cache.__NON_WITNESS_UTXO_TX_CACHE;
|
||||||
|
if (!c[inputIndex]) {
|
||||||
addNonWitnessTxCache(cache, input, inputIndex);
|
addNonWitnessTxCache(cache, input, inputIndex);
|
||||||
}
|
}
|
||||||
return cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex];
|
return c[inputIndex];
|
||||||
}
|
}
|
||||||
function classifyScript(script) {
|
function classifyScript(script) {
|
||||||
if (isP2WPKH(script)) return 'witnesspubkeyhash';
|
if (isP2WPKH(script)) return 'witnesspubkeyhash';
|
||||||
|
|
|
@ -212,8 +212,7 @@ export class Psbt extends PsbtBase {
|
||||||
}
|
}
|
||||||
if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
|
if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
|
||||||
const tx = c.__TX.clone();
|
const tx = c.__TX.clone();
|
||||||
inputFinalizeGetAmts(this.inputs, tx, c, true, false);
|
inputFinalizeGetAmts(this.inputs, tx, c, true);
|
||||||
c.__EXTRACTED_TX = tx;
|
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,22 +229,8 @@ export class Psbt extends PsbtBase {
|
||||||
} else {
|
} else {
|
||||||
tx = c.__TX.clone();
|
tx = c.__TX.clone();
|
||||||
}
|
}
|
||||||
const inputAmount = inputFinalizeGetAmts(
|
inputFinalizeGetAmts(this.inputs, tx, c, mustFinalize);
|
||||||
this.inputs,
|
return c.__FEE_RATE!;
|
||||||
tx,
|
|
||||||
c,
|
|
||||||
mustFinalize,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
c.__EXTRACTED_TX = tx;
|
|
||||||
const outputAmount = (tx.outs as Output[]).reduce(
|
|
||||||
(total, o) => total + o.value,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
const fee = inputAmount - outputAmount;
|
|
||||||
const bytes = tx.virtualSize();
|
|
||||||
c.__FEE_RATE = Math.floor(fee / bytes);
|
|
||||||
return c.__FEE_RATE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finalizeAllInputs(): {
|
finalizeAllInputs(): {
|
||||||
|
@ -1031,8 +1016,7 @@ function inputFinalizeGetAmts(
|
||||||
tx: Transaction,
|
tx: Transaction,
|
||||||
cache: PsbtCache,
|
cache: PsbtCache,
|
||||||
mustFinalize: boolean,
|
mustFinalize: boolean,
|
||||||
getAmounts: boolean,
|
): void {
|
||||||
): number {
|
|
||||||
let inputAmount = 0;
|
let inputAmount = 0;
|
||||||
inputs.forEach((input, idx) => {
|
inputs.forEach((input, idx) => {
|
||||||
if (mustFinalize && input.finalScriptSig)
|
if (mustFinalize && input.finalScriptSig)
|
||||||
|
@ -1042,16 +1026,26 @@ function inputFinalizeGetAmts(
|
||||||
input.finalScriptWitness,
|
input.finalScriptWitness,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (getAmounts && input.witnessUtxo) {
|
if (input.witnessUtxo) {
|
||||||
inputAmount += input.witnessUtxo.value;
|
inputAmount += input.witnessUtxo.value;
|
||||||
} else if (getAmounts && input.nonWitnessUtxo) {
|
} else if (input.nonWitnessUtxo) {
|
||||||
const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
|
const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
|
||||||
const vout = tx.ins[idx].index;
|
const vout = tx.ins[idx].index;
|
||||||
const out = nwTx.outs[vout] as Output;
|
const out = nwTx.outs[vout] as Output;
|
||||||
inputAmount += out.value;
|
inputAmount += out.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return inputAmount;
|
const outputAmount = (tx.outs as Output[]).reduce(
|
||||||
|
(total, o) => total + o.value,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
const fee = inputAmount - outputAmount;
|
||||||
|
if (fee < 0) {
|
||||||
|
throw new Error('Outputs are spending more than Inputs');
|
||||||
|
}
|
||||||
|
const bytes = tx.virtualSize();
|
||||||
|
cache.__EXTRACTED_TX = tx;
|
||||||
|
cache.__FEE_RATE = Math.floor(fee / bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function nonWitnessUtxoTxFromCache(
|
function nonWitnessUtxoTxFromCache(
|
||||||
|
@ -1059,10 +1053,11 @@ function nonWitnessUtxoTxFromCache(
|
||||||
input: PsbtInput,
|
input: PsbtInput,
|
||||||
inputIndex: number,
|
inputIndex: number,
|
||||||
): Transaction {
|
): Transaction {
|
||||||
if (!cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex]) {
|
const c = cache.__NON_WITNESS_UTXO_TX_CACHE;
|
||||||
|
if (!c[inputIndex]) {
|
||||||
addNonWitnessTxCache(cache, input, inputIndex);
|
addNonWitnessTxCache(cache, input, inputIndex);
|
||||||
}
|
}
|
||||||
return cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex];
|
return c[inputIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
function classifyScript(script: Buffer): string {
|
function classifyScript(script: Buffer): string {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue