Refactor getMeaningfulScript

This commit is contained in:
junderw 2020-04-28 14:41:48 +09:00
parent e3bf997d64
commit 97074f8a64
No known key found for this signature in database
GPG key ID: B256185D3A971908
3 changed files with 84 additions and 93 deletions

View file

@ -1235,7 +1235,7 @@ function pubkeyInInput(pubkey, input, inputIndex, cache) {
} else { } else {
throw new Error("Can't find pubkey in input without Utxo data"); throw new Error("Can't find pubkey in input without Utxo data");
} }
const meaningfulScript = checkScripts( const meaningfulScript = getMeaningfulScript(
script, script,
input.redeemScript, input.redeemScript,
input.witnessScript, input.witnessScript,
@ -1244,55 +1244,49 @@ function pubkeyInInput(pubkey, input, inputIndex, cache) {
} }
function pubkeyInOutput(pubkey, output, outputIndex, cache) { function pubkeyInOutput(pubkey, output, outputIndex, cache) {
const script = cache.__TX.outs[outputIndex].script; const script = cache.__TX.outs[outputIndex].script;
const meaningfulScript = checkScripts( const meaningfulScript = getMeaningfulScript(
script, script,
output.redeemScript, output.redeemScript,
output.witnessScript, output.witnessScript,
); );
return pubkeyInScript(pubkey, meaningfulScript); return pubkeyInScript(pubkey, meaningfulScript);
} }
function checkScripts(script, redeemScript, witnessScript) { function getMeaningfulScript(script, redeemScript, witnessScript) {
let fail = false; const { p2sh, p2wsh } = payments;
if (isP2SHScript(script)) { const isP2SH = isP2SHScript(script);
if (redeemScript === undefined) { const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
fail = true; const isP2WSH = isP2WSHScript(script);
} else if (isP2WSHScript(redeemScript)) { if (isP2SH && redeemScript === undefined)
if (witnessScript === undefined) { throw new Error('scriptPubkey is P2SH but redeemScript missing');
fail = true; if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
} else { throw new Error(
fail = !payments 'scriptPubkey or redeemScript is P2WSH but witnessScript missing',
.p2sh({ );
redeem: payments.p2wsh({ let payment;
redeem: { output: witnessScript }, let meaningfulScript;
}), if (isP2SHP2WSH) {
}) meaningfulScript = witnessScript;
.output.equals(script); payment = p2sh({ redeem: p2wsh({ redeem: { output: meaningfulScript } }) });
if (!fail) return witnessScript; if (!payment.redeem.output.equals(redeemScript))
} throw new Error('P2SHP2WSH witnessScript and redeemScript do not match');
} else { if (!payment.output.equals(script))
fail = !payments throw new Error(
.p2sh({ 'P2SHP2WSH witnessScript+redeemScript and scriptPubkey do not match',
redeem: { output: redeemScript }, );
}) } else if (isP2WSH) {
.output.equals(script); meaningfulScript = witnessScript;
if (!fail) return redeemScript; payment = p2wsh({ redeem: { output: meaningfulScript } });
} if (!payment.output.equals(script))
} else if (isP2WSHScript(script)) { throw new Error('P2WSH witnessScript and scriptPubkey do not match');
if (witnessScript === undefined) { } else if (isP2SH) {
fail = true; meaningfulScript = redeemScript;
} else { payment = p2sh({ redeem: { output: meaningfulScript } });
fail = !payments if (!payment.output.equals(script))
.p2wsh({ throw new Error('P2SH redeemScript and scriptPubkey do not match');
redeem: { output: witnessScript }, } else {
}) meaningfulScript = script;
.output.equals(script);
if (!fail) return witnessScript;
}
} }
if (fail) { return meaningfulScript;
throw new Error('Incomplete script information');
}
return script;
} }
function pubkeyInScript(pubkey, script) { function pubkeyInScript(pubkey, script) {
const pubkeyHash = crypto_1.hash160(pubkey); const pubkeyHash = crypto_1.hash160(pubkey);

View file

@ -566,7 +566,7 @@ describe(`Psbt`, () => {
assert.throws(() => { assert.throws(() => {
psbt.inputHasPubkey(0, Buffer.from([])); psbt.inputHasPubkey(0, Buffer.from([]));
}, new RegExp('Incomplete script information')); }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
delete psbt.data.inputs[0].witnessUtxo; delete psbt.data.inputs[0].witnessUtxo;
@ -581,7 +581,7 @@ describe(`Psbt`, () => {
assert.throws(() => { assert.throws(() => {
psbt.inputHasPubkey(0, Buffer.from([])); psbt.inputHasPubkey(0, Buffer.from([]));
}, new RegExp('Incomplete script information')); }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
delete psbt.data.inputs[0].witnessUtxo; delete psbt.data.inputs[0].witnessUtxo;
@ -601,7 +601,7 @@ describe(`Psbt`, () => {
assert.throws(() => { assert.throws(() => {
psbt.inputHasPubkey(0, Buffer.from([])); psbt.inputHasPubkey(0, Buffer.from([]));
}, new RegExp('Incomplete script information')); }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
psbt.updateInput(0, { psbt.updateInput(0, {
witnessScript: Buffer.from([0x51]), witnessScript: Buffer.from([0x51]),
@ -631,7 +631,7 @@ describe(`Psbt`, () => {
assert.throws(() => { assert.throws(() => {
psbt.outputHasPubkey(0, Buffer.from([])); psbt.outputHasPubkey(0, Buffer.from([]));
}, new RegExp('Incomplete script information')); }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
(psbt as any).__CACHE.__TX.outs[0].script = payments.p2wsh({ (psbt as any).__CACHE.__TX.outs[0].script = payments.p2wsh({
redeem: { output: Buffer.from([0x51]) }, redeem: { output: Buffer.from([0x51]) },
@ -639,7 +639,7 @@ describe(`Psbt`, () => {
assert.throws(() => { assert.throws(() => {
psbt.outputHasPubkey(0, Buffer.from([])); psbt.outputHasPubkey(0, Buffer.from([]));
}, new RegExp('Incomplete script information')); }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
(psbt as any).__CACHE.__TX.outs[0].script = payments.p2sh({ (psbt as any).__CACHE.__TX.outs[0].script = payments.p2sh({
redeem: payments.p2wsh({ redeem: payments.p2wsh({
@ -655,7 +655,7 @@ describe(`Psbt`, () => {
assert.throws(() => { assert.throws(() => {
psbt.outputHasPubkey(0, Buffer.from([])); psbt.outputHasPubkey(0, Buffer.from([]));
}, new RegExp('Incomplete script information')); }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
delete psbt.data.outputs[0].redeemScript; delete psbt.data.outputs[0].redeemScript;
@ -665,7 +665,7 @@ describe(`Psbt`, () => {
assert.throws(() => { assert.throws(() => {
psbt.outputHasPubkey(0, Buffer.from([])); psbt.outputHasPubkey(0, Buffer.from([]));
}, new RegExp('Incomplete script information')); }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
psbt.updateOutput(0, { psbt.updateOutput(0, {
redeemScript: payments.p2wsh({ redeemScript: payments.p2wsh({

View file

@ -1587,7 +1587,7 @@ function pubkeyInInput(
} else { } else {
throw new Error("Can't find pubkey in input without Utxo data"); throw new Error("Can't find pubkey in input without Utxo data");
} }
const meaningfulScript = checkScripts( const meaningfulScript = getMeaningfulScript(
script, script,
input.redeemScript, input.redeemScript,
input.witnessScript, input.witnessScript,
@ -1602,7 +1602,7 @@ function pubkeyInOutput(
cache: PsbtCache, cache: PsbtCache,
): boolean { ): boolean {
const script = cache.__TX.outs[outputIndex].script; const script = cache.__TX.outs[outputIndex].script;
const meaningfulScript = checkScripts( const meaningfulScript = getMeaningfulScript(
script, script,
output.redeemScript, output.redeemScript,
output.witnessScript, output.witnessScript,
@ -1610,52 +1610,49 @@ function pubkeyInOutput(
return pubkeyInScript(pubkey, meaningfulScript); return pubkeyInScript(pubkey, meaningfulScript);
} }
function checkScripts( function getMeaningfulScript(
script: Buffer, script: Buffer,
redeemScript?: Buffer, redeemScript?: Buffer,
witnessScript?: Buffer, witnessScript?: Buffer,
): Buffer { ): Buffer {
let fail = false; const { p2sh, p2wsh } = payments;
if (isP2SHScript(script)) { const isP2SH = isP2SHScript(script);
if (redeemScript === undefined) { const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
fail = true; const isP2WSH = isP2WSHScript(script);
} else if (isP2WSHScript(redeemScript)) {
if (witnessScript === undefined) { if (isP2SH && redeemScript === undefined)
fail = true; throw new Error('scriptPubkey is P2SH but redeemScript missing');
} else { if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
fail = !payments throw new Error(
.p2sh({ 'scriptPubkey or redeemScript is P2WSH but witnessScript missing',
redeem: payments.p2wsh({ );
redeem: { output: witnessScript },
}), let payment: payments.Payment;
}) let meaningfulScript: Buffer;
.output!.equals(script);
if (!fail) return witnessScript; if (isP2SHP2WSH) {
} meaningfulScript = witnessScript!;
} else { payment = p2sh({ redeem: p2wsh({ redeem: { output: meaningfulScript } }) });
fail = !payments if (!payment.redeem!.output!.equals(redeemScript!))
.p2sh({ throw new Error('P2SHP2WSH witnessScript and redeemScript do not match');
redeem: { output: redeemScript }, if (!payment.output!.equals(script!))
}) throw new Error(
.output!.equals(script); 'P2SHP2WSH witnessScript+redeemScript and scriptPubkey do not match',
if (!fail) return redeemScript; );
} } else if (isP2WSH) {
} else if (isP2WSHScript(script)) { meaningfulScript = witnessScript!;
if (witnessScript === undefined) { payment = p2wsh({ redeem: { output: meaningfulScript } });
fail = true; if (!payment.output!.equals(script!))
} else { throw new Error('P2WSH witnessScript and scriptPubkey do not match');
fail = !payments } else if (isP2SH) {
.p2wsh({ meaningfulScript = redeemScript!;
redeem: { output: witnessScript }, payment = p2sh({ redeem: { output: meaningfulScript } });
}) if (!payment.output!.equals(script!))
.output!.equals(script); throw new Error('P2SH redeemScript and scriptPubkey do not match');
if (!fail) return witnessScript; } else {
} meaningfulScript = script;
} }
if (fail) { return meaningfulScript;
throw new Error('Incomplete script information');
}
return script;
} }
function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean { function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {