Browse Source

Add check for spending more than you have

psbt
junderw 6 years ago
parent
commit
ba33f0317f
No known key found for this signature in database GPG Key ID: B256185D3A971908
  1. 36
      src/psbt.js
  2. 45
      ts_src/psbt.ts

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';

45
ts_src/psbt.ts

@ -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…
Cancel
Save