Add discouraged unsafe nonsegwit signing
This commit is contained in:
parent
7d09fe5dcb
commit
0c52803ba1
2 changed files with 68 additions and 3 deletions
35
src/psbt.js
35
src/psbt.js
|
@ -69,6 +69,14 @@ class Psbt {
|
||||||
__NON_WITNESS_UTXO_BUF_CACHE: [],
|
__NON_WITNESS_UTXO_BUF_CACHE: [],
|
||||||
__TX_IN_CACHE: {},
|
__TX_IN_CACHE: {},
|
||||||
__TX: this.data.globalMap.unsignedTx.tx,
|
__TX: this.data.globalMap.unsignedTx.tx,
|
||||||
|
// Old TransactionBuilder behavior was to not confirm input values
|
||||||
|
// before signing. Even though we highly encourage people to get
|
||||||
|
// the full parent transaction to verify values, the ability to
|
||||||
|
// sign non-segwit inputs without the full transaction was often
|
||||||
|
// requested. So the only way to activate is to use @ts-ignore.
|
||||||
|
// We will disable exporting the Psbt when unsafe sign is active.
|
||||||
|
// because it is not BIP174 compliant.
|
||||||
|
__UNSAFE_SIGN_NONSEGWIT: false,
|
||||||
};
|
};
|
||||||
if (this.data.inputs.length === 0) this.setVersion(2);
|
if (this.data.inputs.length === 0) this.setVersion(2);
|
||||||
// Make data hidden when enumerating
|
// Make data hidden when enumerating
|
||||||
|
@ -313,6 +321,7 @@ class Psbt {
|
||||||
inputIndex,
|
inputIndex,
|
||||||
Object.assign({}, input, { sighashType: sig.hashType }),
|
Object.assign({}, input, { sighashType: sig.hashType }),
|
||||||
this.__CACHE,
|
this.__CACHE,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
: { hash: hashCache, script: scriptCache };
|
: { hash: hashCache, script: scriptCache };
|
||||||
sighashCache = sig.hashType;
|
sighashCache = sig.hashType;
|
||||||
|
@ -513,12 +522,15 @@ class Psbt {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
toBuffer() {
|
toBuffer() {
|
||||||
|
checkCache(this.__CACHE);
|
||||||
return this.data.toBuffer();
|
return this.data.toBuffer();
|
||||||
}
|
}
|
||||||
toHex() {
|
toHex() {
|
||||||
|
checkCache(this.__CACHE);
|
||||||
return this.data.toHex();
|
return this.data.toHex();
|
||||||
}
|
}
|
||||||
toBase64() {
|
toBase64() {
|
||||||
|
checkCache(this.__CACHE);
|
||||||
return this.data.toBase64();
|
return this.data.toBase64();
|
||||||
}
|
}
|
||||||
updateGlobal(updateData) {
|
updateGlobal(updateData) {
|
||||||
|
@ -626,6 +638,11 @@ function canFinalize(input, script, scriptType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function checkCache(cache) {
|
||||||
|
if (cache.__UNSAFE_SIGN_NONSEGWIT !== false) {
|
||||||
|
throw new Error('Not BIP174 compliant, can not export');
|
||||||
|
}
|
||||||
|
}
|
||||||
function hasSigs(neededSigs, partialSig, pubkeys) {
|
function hasSigs(neededSigs, partialSig, pubkeys) {
|
||||||
if (!partialSig) return false;
|
if (!partialSig) return false;
|
||||||
let sigs;
|
let sigs;
|
||||||
|
@ -857,6 +874,7 @@ function getHashAndSighashType(
|
||||||
inputIndex,
|
inputIndex,
|
||||||
input,
|
input,
|
||||||
cache,
|
cache,
|
||||||
|
false,
|
||||||
sighashTypes,
|
sighashTypes,
|
||||||
);
|
);
|
||||||
checkScriptForPubkey(pubkey, script, 'sign');
|
checkScriptForPubkey(pubkey, script, 'sign');
|
||||||
|
@ -865,7 +883,7 @@ function getHashAndSighashType(
|
||||||
sighashType,
|
sighashType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function getHashForSig(inputIndex, input, cache, sighashTypes) {
|
function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
|
||||||
const unsignedTx = cache.__TX;
|
const unsignedTx = cache.__TX;
|
||||||
const sighashType =
|
const sighashType =
|
||||||
input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
|
input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
|
||||||
|
@ -925,11 +943,24 @@ function getHashForSig(inputIndex, input, cache, sighashTypes) {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// non-segwit
|
// non-segwit
|
||||||
if (input.nonWitnessUtxo === undefined)
|
if (
|
||||||
|
input.nonWitnessUtxo === undefined &&
|
||||||
|
cache.__UNSAFE_SIGN_NONSEGWIT === false
|
||||||
|
)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
|
`Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
|
||||||
`${meaningfulScript.toString('hex')}`,
|
`${meaningfulScript.toString('hex')}`,
|
||||||
);
|
);
|
||||||
|
if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false)
|
||||||
|
console.warn(
|
||||||
|
'Warning: Signing non-segwit inputs without the full parent transaction ' +
|
||||||
|
'means there is a chance that a miner could feed you incorrect information ' +
|
||||||
|
'to trick you into paying large fees. This behavior is the same as the old ' +
|
||||||
|
'TransactionBuilder class when signing non-segwit scripts. You are not ' +
|
||||||
|
'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
|
||||||
|
'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
|
||||||
|
'*********************',
|
||||||
|
);
|
||||||
hash = unsignedTx.hashForSignature(
|
hash = unsignedTx.hashForSignature(
|
||||||
inputIndex,
|
inputIndex,
|
||||||
meaningfulScript,
|
meaningfulScript,
|
||||||
|
|
|
@ -115,6 +115,14 @@ export class Psbt {
|
||||||
__NON_WITNESS_UTXO_BUF_CACHE: [],
|
__NON_WITNESS_UTXO_BUF_CACHE: [],
|
||||||
__TX_IN_CACHE: {},
|
__TX_IN_CACHE: {},
|
||||||
__TX: (this.data.globalMap.unsignedTx as PsbtTransaction).tx,
|
__TX: (this.data.globalMap.unsignedTx as PsbtTransaction).tx,
|
||||||
|
// Old TransactionBuilder behavior was to not confirm input values
|
||||||
|
// before signing. Even though we highly encourage people to get
|
||||||
|
// the full parent transaction to verify values, the ability to
|
||||||
|
// sign non-segwit inputs without the full transaction was often
|
||||||
|
// requested. So the only way to activate is to use @ts-ignore.
|
||||||
|
// We will disable exporting the Psbt when unsafe sign is active.
|
||||||
|
// because it is not BIP174 compliant.
|
||||||
|
__UNSAFE_SIGN_NONSEGWIT: false,
|
||||||
};
|
};
|
||||||
if (this.data.inputs.length === 0) this.setVersion(2);
|
if (this.data.inputs.length === 0) this.setVersion(2);
|
||||||
|
|
||||||
|
@ -386,6 +394,7 @@ export class Psbt {
|
||||||
inputIndex,
|
inputIndex,
|
||||||
Object.assign({}, input, { sighashType: sig.hashType }),
|
Object.assign({}, input, { sighashType: sig.hashType }),
|
||||||
this.__CACHE,
|
this.__CACHE,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
: { hash: hashCache!, script: scriptCache! };
|
: { hash: hashCache!, script: scriptCache! };
|
||||||
sighashCache = sig.hashType;
|
sighashCache = sig.hashType;
|
||||||
|
@ -619,14 +628,17 @@ export class Psbt {
|
||||||
}
|
}
|
||||||
|
|
||||||
toBuffer(): Buffer {
|
toBuffer(): Buffer {
|
||||||
|
checkCache(this.__CACHE);
|
||||||
return this.data.toBuffer();
|
return this.data.toBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
toHex(): string {
|
toHex(): string {
|
||||||
|
checkCache(this.__CACHE);
|
||||||
return this.data.toHex();
|
return this.data.toHex();
|
||||||
}
|
}
|
||||||
|
|
||||||
toBase64(): string {
|
toBase64(): string {
|
||||||
|
checkCache(this.__CACHE);
|
||||||
return this.data.toBase64();
|
return this.data.toBase64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,6 +693,7 @@ interface PsbtCache {
|
||||||
__FEE_RATE?: number;
|
__FEE_RATE?: number;
|
||||||
__FEE?: number;
|
__FEE?: number;
|
||||||
__EXTRACTED_TX?: Transaction;
|
__EXTRACTED_TX?: Transaction;
|
||||||
|
__UNSAFE_SIGN_NONSEGWIT: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PsbtOptsOptional {
|
interface PsbtOptsOptional {
|
||||||
|
@ -825,6 +838,12 @@ function canFinalize(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkCache(cache: PsbtCache): void {
|
||||||
|
if (cache.__UNSAFE_SIGN_NONSEGWIT !== false) {
|
||||||
|
throw new Error('Not BIP174 compliant, can not export');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function hasSigs(
|
function hasSigs(
|
||||||
neededSigs: number,
|
neededSigs: number,
|
||||||
partialSig?: any[],
|
partialSig?: any[],
|
||||||
|
@ -1130,6 +1149,7 @@ function getHashAndSighashType(
|
||||||
inputIndex,
|
inputIndex,
|
||||||
input,
|
input,
|
||||||
cache,
|
cache,
|
||||||
|
false,
|
||||||
sighashTypes,
|
sighashTypes,
|
||||||
);
|
);
|
||||||
checkScriptForPubkey(pubkey, script, 'sign');
|
checkScriptForPubkey(pubkey, script, 'sign');
|
||||||
|
@ -1143,6 +1163,7 @@ function getHashForSig(
|
||||||
inputIndex: number,
|
inputIndex: number,
|
||||||
input: PsbtInput,
|
input: PsbtInput,
|
||||||
cache: PsbtCache,
|
cache: PsbtCache,
|
||||||
|
forValidate: boolean,
|
||||||
sighashTypes?: number[],
|
sighashTypes?: number[],
|
||||||
): {
|
): {
|
||||||
script: Buffer;
|
script: Buffer;
|
||||||
|
@ -1213,11 +1234,24 @@ function getHashForSig(
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// non-segwit
|
// non-segwit
|
||||||
if (input.nonWitnessUtxo === undefined)
|
if (
|
||||||
|
input.nonWitnessUtxo === undefined &&
|
||||||
|
cache.__UNSAFE_SIGN_NONSEGWIT === false
|
||||||
|
)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
|
`Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
|
||||||
`${meaningfulScript.toString('hex')}`,
|
`${meaningfulScript.toString('hex')}`,
|
||||||
);
|
);
|
||||||
|
if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false)
|
||||||
|
console.warn(
|
||||||
|
'Warning: Signing non-segwit inputs without the full parent transaction ' +
|
||||||
|
'means there is a chance that a miner could feed you incorrect information ' +
|
||||||
|
'to trick you into paying large fees. This behavior is the same as the old ' +
|
||||||
|
'TransactionBuilder class when signing non-segwit scripts. You are not ' +
|
||||||
|
'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
|
||||||
|
'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
|
||||||
|
'*********************',
|
||||||
|
);
|
||||||
hash = unsignedTx.hashForSignature(
|
hash = unsignedTx.hashForSignature(
|
||||||
inputIndex,
|
inputIndex,
|
||||||
meaningfulScript,
|
meaningfulScript,
|
||||||
|
|
Loading…
Reference in a new issue