Fix p2sh and p2wsh not working

This commit is contained in:
junderw 2019-07-03 18:42:31 +09:00
parent 1c8fc69780
commit 48fc75c4f0
No known key found for this signature in database
GPG key ID: B256185D3A971908
2 changed files with 111 additions and 16 deletions

View file

@ -30,8 +30,9 @@ class Psbt extends bip174_1.Psbt {
this.inputs.forEach((input, idx) => { this.inputs.forEach((input, idx) => {
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig; if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
if (input.finalScriptWitness) { if (input.finalScriptWitness) {
const decompiled = bscript.decompile(input.finalScriptWitness); tx.ins[idx].witness = scriptWitnessToWitnessStack(
if (decompiled) tx.ins[idx].witness = bscript.toStack(decompiled); input.finalScriptWitness,
);
} }
}); });
return tx; return tx;
@ -148,23 +149,44 @@ function getFinalScripts(
finalScriptWitness = witnessStackToScriptWitness(payment.witness); finalScriptWitness = witnessStackToScriptWitness(payment.witness);
} }
if (p2sh) { if (p2sh) {
finalScriptSig = bscript.compile([p2sh.redeem.output]); finalScriptSig = p2sh.input;
} }
} else { } else {
finalScriptSig = payment.input; if (p2sh) {
finalScriptSig = p2sh.input;
} else {
finalScriptSig = payment.input;
}
} }
return { return {
finalScriptSig, finalScriptSig,
finalScriptWitness, finalScriptWitness,
}; };
} }
function getSortedSigs(script, partialSig) {
const p2ms = payments.p2ms({ output: script });
// for each pubkey in order of p2ms script
return p2ms.pubkeys
.map(pk => {
// filter partialSig array by pubkey being equal
return (
partialSig.filter(ps => {
return ps.pubkey.equals(pk);
})[0] || {}
).signature;
// Any pubkey without a match will return undefined
// this last filter removes all the undefined items in the array.
})
.filter(v => !!v);
}
function getPayment(script, scriptType, partialSig) { function getPayment(script, scriptType, partialSig) {
let payment; let payment;
switch (scriptType) { switch (scriptType) {
case 'multisig': case 'multisig':
const sigs = getSortedSigs(script, partialSig);
payment = payments.p2ms({ payment = payments.p2ms({
output: script, output: script,
signatures: partialSig.map(ps => ps.signature), signatures: sigs,
}); });
break; break;
case 'pubkey': case 'pubkey':
@ -283,7 +305,7 @@ const getHashForSig = (inputIndex, input, txBuf) => {
checkWitnessScript(inputIndex, _script, input.witnessScript); checkWitnessScript(inputIndex, _script, input.witnessScript);
hash = unsignedTx.hashForWitnessV0( hash = unsignedTx.hashForWitnessV0(
inputIndex, inputIndex,
_script, input.witnessScript,
input.witnessUtxo.value, input.witnessUtxo.value,
sighashType, sighashType,
); );
@ -363,11 +385,11 @@ function getScriptFromInput(inputIndex, input, _unsignedTx) {
if (input.witnessScript) { if (input.witnessScript) {
res.script = input.witnessScript; res.script = input.witnessScript;
} else if (input.redeemScript) { } else if (input.redeemScript) {
res.script = payments.p2pkh({ res.script = payments.p2wpkh({
hash: input.redeemScript.slice(2), hash: input.redeemScript.slice(2),
}).output; }).output;
} else { } else {
res.script = payments.p2pkh({ res.script = payments.p2wpkh({
hash: input.witnessUtxo.script.slice(2), hash: input.witnessUtxo.script.slice(2),
}).output; }).output;
} }
@ -401,4 +423,26 @@ function witnessStackToScriptWitness(witness) {
writeVector(witness); writeVector(witness);
return buffer; return buffer;
} }
function scriptWitnessToWitnessStack(buffer) {
let offset = 0;
function readSlice(n) {
offset += n;
return buffer.slice(offset - n, offset);
}
function readVarInt() {
const vi = varuint.decode(buffer, offset);
offset += varuint.decode.bytes;
return vi;
}
function readVarSlice() {
return readSlice(readVarInt());
}
function readVector() {
const count = readVarInt();
const vector = [];
for (let i = 0; i < count; i++) vector.push(readVarSlice());
return vector;
}
return readVector();
}
const range = n => [...Array(n).keys()]; const range = n => [...Array(n).keys()];

View file

@ -32,8 +32,9 @@ export class Psbt extends PsbtBase {
this.inputs.forEach((input, idx) => { this.inputs.forEach((input, idx) => {
if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig; if (input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig;
if (input.finalScriptWitness) { if (input.finalScriptWitness) {
const decompiled = bscript.decompile(input.finalScriptWitness); tx.ins[idx].witness = scriptWitnessToWitnessStack(
if (decompiled) tx.ins[idx].witness = bscript.toStack(decompiled); input.finalScriptWitness,
);
} }
}); });
return tx; return tx;
@ -181,10 +182,14 @@ function getFinalScripts(
finalScriptWitness = witnessStackToScriptWitness(payment.witness!); finalScriptWitness = witnessStackToScriptWitness(payment.witness!);
} }
if (p2sh) { if (p2sh) {
finalScriptSig = bscript.compile([p2sh.redeem!.output!]); finalScriptSig = p2sh.input;
} }
} else { } else {
finalScriptSig = payment.input; if (p2sh) {
finalScriptSig = p2sh.input;
} else {
finalScriptSig = payment.input;
}
} }
return { return {
finalScriptSig, finalScriptSig,
@ -192,6 +197,23 @@ function getFinalScripts(
}; };
} }
function getSortedSigs(script: Buffer, partialSig: PartialSig[]): Buffer[] {
const p2ms = payments.p2ms({ output: script });
// for each pubkey in order of p2ms script
return p2ms
.pubkeys!.map(pk => {
// filter partialSig array by pubkey being equal
return (
partialSig.filter(ps => {
return ps.pubkey.equals(pk);
})[0] || {}
).signature;
// Any pubkey without a match will return undefined
// this last filter removes all the undefined items in the array.
})
.filter(v => !!v);
}
function getPayment( function getPayment(
script: Buffer, script: Buffer,
scriptType: string, scriptType: string,
@ -200,9 +222,10 @@ function getPayment(
let payment: payments.Payment; let payment: payments.Payment;
switch (scriptType) { switch (scriptType) {
case 'multisig': case 'multisig':
const sigs = getSortedSigs(script, partialSig);
payment = payments.p2ms({ payment = payments.p2ms({
output: script, output: script,
signatures: partialSig.map(ps => ps.signature), signatures: sigs,
}); });
break; break;
case 'pubkey': case 'pubkey':
@ -343,7 +366,7 @@ const getHashForSig = (
checkWitnessScript(inputIndex, _script, input.witnessScript); checkWitnessScript(inputIndex, _script, input.witnessScript);
hash = unsignedTx.hashForWitnessV0( hash = unsignedTx.hashForWitnessV0(
inputIndex, inputIndex,
_script, input.witnessScript,
input.witnessUtxo.value, input.witnessUtxo.value,
sighashType, sighashType,
); );
@ -446,11 +469,11 @@ function getScriptFromInput(
if (input.witnessScript) { if (input.witnessScript) {
res.script = input.witnessScript; res.script = input.witnessScript;
} else if (input.redeemScript) { } else if (input.redeemScript) {
res.script = payments.p2pkh({ res.script = payments.p2wpkh({
hash: input.redeemScript.slice(2), hash: input.redeemScript.slice(2),
}).output!; }).output!;
} else { } else {
res.script = payments.p2pkh({ res.script = payments.p2wpkh({
hash: input.witnessUtxo.script.slice(2), hash: input.witnessUtxo.script.slice(2),
}).output!; }).output!;
} }
@ -494,4 +517,32 @@ function witnessStackToScriptWitness(witness: Buffer[]): Buffer {
return buffer; return buffer;
} }
function scriptWitnessToWitnessStack(buffer: Buffer): Buffer[] {
let offset = 0;
function readSlice(n: number): Buffer {
offset += n;
return buffer.slice(offset - n, offset);
}
function readVarInt(): number {
const vi = varuint.decode(buffer, offset);
offset += varuint.decode.bytes;
return vi;
}
function readVarSlice(): Buffer {
return readSlice(readVarInt());
}
function readVector(): Buffer[] {
const count = readVarInt();
const vector: Buffer[] = [];
for (let i = 0; i < count; i++) vector.push(readVarSlice());
return vector;
}
return readVector();
}
const range = (n: number): number[] => [...Array(n).keys()]; const range = (n: number): number[] => [...Array(n).keys()];