Skip to content

Commit 7d09fe5

Browse files
committed
Refactor Psbt logic
1 parent 97074f8 commit 7d09fe5

File tree

2 files changed

+140
-187
lines changed

2 files changed

+140
-187
lines changed

src/psbt.js

Lines changed: 69 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -764,13 +764,13 @@ function checkTxInputCache(cache, input) {
764764
cache.__TX_IN_CACHE[key] = 1;
765765
}
766766
function scriptCheckerFactory(payment, paymentScriptName) {
767-
return (inputIndex, scriptPubKey, redeemScript) => {
767+
return (inputIndex, scriptPubKey, redeemScript, ioType) => {
768768
const redeemScriptOutput = payment({
769769
redeem: { output: redeemScript },
770770
}).output;
771771
if (!scriptPubKey.equals(redeemScriptOutput)) {
772772
throw new Error(
773-
`${paymentScriptName} for input #${inputIndex} doesn't match the scriptPubKey in the prevout`,
773+
`${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`,
774774
);
775775
}
776776
};
@@ -877,7 +877,7 @@ function getHashForSig(inputIndex, input, cache, sighashTypes) {
877877
);
878878
}
879879
let hash;
880-
let script;
880+
let prevout;
881881
if (input.nonWitnessUtxo) {
882882
const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
883883
cache,
@@ -893,83 +893,51 @@ function getHashForSig(inputIndex, input, cache, sighashTypes) {
893893
);
894894
}
895895
const prevoutIndex = unsignedTx.ins[inputIndex].index;
896-
const prevout = nonWitnessUtxoTx.outs[prevoutIndex];
897-
if (input.redeemScript) {
898-
// If a redeemScript is provided, the scriptPubKey must be for that redeemScript
899-
checkRedeemScript(inputIndex, prevout.script, input.redeemScript);
900-
script = input.redeemScript;
901-
} else {
902-
script = prevout.script;
903-
}
904-
if (isP2WSHScript(script)) {
905-
if (!input.witnessScript)
906-
throw new Error('Segwit input needs witnessScript if not P2WPKH');
907-
checkWitnessScript(inputIndex, script, input.witnessScript);
908-
hash = unsignedTx.hashForWitnessV0(
909-
inputIndex,
910-
input.witnessScript,
911-
prevout.value,
912-
sighashType,
913-
);
914-
script = input.witnessScript;
915-
} else if (isP2WPKH(script)) {
916-
// P2WPKH uses the P2PKH template for prevoutScript when signing
917-
const signingScript = payments.p2pkh({ hash: script.slice(2) }).output;
918-
hash = unsignedTx.hashForWitnessV0(
919-
inputIndex,
920-
signingScript,
921-
prevout.value,
922-
sighashType,
923-
);
924-
} else {
925-
hash = unsignedTx.hashForSignature(inputIndex, script, sighashType);
926-
}
896+
prevout = nonWitnessUtxoTx.outs[prevoutIndex];
927897
} else if (input.witnessUtxo) {
928-
let _script; // so we don't shadow the `let script` above
929-
if (input.redeemScript) {
930-
// If a redeemScript is provided, the scriptPubKey must be for that redeemScript
931-
checkRedeemScript(
932-
inputIndex,
933-
input.witnessUtxo.script,
934-
input.redeemScript,
935-
);
936-
_script = input.redeemScript;
937-
} else {
938-
_script = input.witnessUtxo.script;
939-
}
940-
if (isP2WPKH(_script)) {
941-
// P2WPKH uses the P2PKH template for prevoutScript when signing
942-
const signingScript = payments.p2pkh({ hash: _script.slice(2) }).output;
943-
hash = unsignedTx.hashForWitnessV0(
944-
inputIndex,
945-
signingScript,
946-
input.witnessUtxo.value,
947-
sighashType,
948-
);
949-
script = _script;
950-
} else if (isP2WSHScript(_script)) {
951-
if (!input.witnessScript)
952-
throw new Error('Segwit input needs witnessScript if not P2WPKH');
953-
checkWitnessScript(inputIndex, _script, input.witnessScript);
954-
hash = unsignedTx.hashForWitnessV0(
955-
inputIndex,
956-
input.witnessScript,
957-
input.witnessUtxo.value,
958-
sighashType,
959-
);
960-
// want to make sure the script we return is the actual meaningful script
961-
script = input.witnessScript;
962-
} else {
898+
prevout = input.witnessUtxo;
899+
} else {
900+
throw new Error('Need a Utxo input item for signing');
901+
}
902+
const { meaningfulScript, type } = getMeaningfulScript(
903+
prevout.script,
904+
inputIndex,
905+
'input',
906+
input.redeemScript,
907+
input.witnessScript,
908+
);
909+
if (['p2shp2wsh', 'p2wsh'].indexOf(type) >= 0) {
910+
hash = unsignedTx.hashForWitnessV0(
911+
inputIndex,
912+
meaningfulScript,
913+
prevout.value,
914+
sighashType,
915+
);
916+
} else if (isP2WPKH(meaningfulScript)) {
917+
// P2WPKH uses the P2PKH template for prevoutScript when signing
918+
const signingScript = payments.p2pkh({ hash: meaningfulScript.slice(2) })
919+
.output;
920+
hash = unsignedTx.hashForWitnessV0(
921+
inputIndex,
922+
signingScript,
923+
prevout.value,
924+
sighashType,
925+
);
926+
} else {
927+
// non-segwit
928+
if (input.nonWitnessUtxo === undefined)
963929
throw new Error(
964930
`Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
965-
`${_script.toString('hex')}`,
931+
`${meaningfulScript.toString('hex')}`,
966932
);
967-
}
968-
} else {
969-
throw new Error('Need a Utxo input item for signing');
933+
hash = unsignedTx.hashForSignature(
934+
inputIndex,
935+
meaningfulScript,
936+
sighashType,
937+
);
970938
}
971939
return {
972-
script,
940+
script: meaningfulScript,
973941
sighashType,
974942
hash,
975943
};
@@ -1235,24 +1203,33 @@ function pubkeyInInput(pubkey, input, inputIndex, cache) {
12351203
} else {
12361204
throw new Error("Can't find pubkey in input without Utxo data");
12371205
}
1238-
const meaningfulScript = getMeaningfulScript(
1206+
const { meaningfulScript } = getMeaningfulScript(
12391207
script,
1208+
inputIndex,
1209+
'input',
12401210
input.redeemScript,
12411211
input.witnessScript,
12421212
);
12431213
return pubkeyInScript(pubkey, meaningfulScript);
12441214
}
12451215
function pubkeyInOutput(pubkey, output, outputIndex, cache) {
12461216
const script = cache.__TX.outs[outputIndex].script;
1247-
const meaningfulScript = getMeaningfulScript(
1217+
const { meaningfulScript } = getMeaningfulScript(
12481218
script,
1219+
outputIndex,
1220+
'output',
12491221
output.redeemScript,
12501222
output.witnessScript,
12511223
);
12521224
return pubkeyInScript(pubkey, meaningfulScript);
12531225
}
1254-
function getMeaningfulScript(script, redeemScript, witnessScript) {
1255-
const { p2sh, p2wsh } = payments;
1226+
function getMeaningfulScript(
1227+
script,
1228+
index,
1229+
ioType,
1230+
redeemScript,
1231+
witnessScript,
1232+
) {
12561233
const isP2SH = isP2SHScript(script);
12571234
const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
12581235
const isP2WSH = isP2WSHScript(script);
@@ -1262,31 +1239,30 @@ function getMeaningfulScript(script, redeemScript, witnessScript) {
12621239
throw new Error(
12631240
'scriptPubkey or redeemScript is P2WSH but witnessScript missing',
12641241
);
1265-
let payment;
12661242
let meaningfulScript;
12671243
if (isP2SHP2WSH) {
12681244
meaningfulScript = witnessScript;
1269-
payment = p2sh({ redeem: p2wsh({ redeem: { output: meaningfulScript } }) });
1270-
if (!payment.redeem.output.equals(redeemScript))
1271-
throw new Error('P2SHP2WSH witnessScript and redeemScript do not match');
1272-
if (!payment.output.equals(script))
1273-
throw new Error(
1274-
'P2SHP2WSH witnessScript+redeemScript and scriptPubkey do not match',
1275-
);
1245+
checkRedeemScript(index, script, redeemScript, ioType);
1246+
checkWitnessScript(index, redeemScript, witnessScript, ioType);
12761247
} else if (isP2WSH) {
12771248
meaningfulScript = witnessScript;
1278-
payment = p2wsh({ redeem: { output: meaningfulScript } });
1279-
if (!payment.output.equals(script))
1280-
throw new Error('P2WSH witnessScript and scriptPubkey do not match');
1249+
checkWitnessScript(index, script, witnessScript, ioType);
12811250
} else if (isP2SH) {
12821251
meaningfulScript = redeemScript;
1283-
payment = p2sh({ redeem: { output: meaningfulScript } });
1284-
if (!payment.output.equals(script))
1285-
throw new Error('P2SH redeemScript and scriptPubkey do not match');
1252+
checkRedeemScript(index, script, redeemScript, ioType);
12861253
} else {
12871254
meaningfulScript = script;
12881255
}
1289-
return meaningfulScript;
1256+
return {
1257+
meaningfulScript,
1258+
type: isP2SHP2WSH
1259+
? 'p2shp2wsh'
1260+
: isP2SH
1261+
? 'p2sh'
1262+
: isP2WSH
1263+
? 'p2wsh'
1264+
: 'raw',
1265+
};
12901266
}
12911267
function pubkeyInScript(pubkey, script) {
12921268
const pubkeyHash = crypto_1.hash160(pubkey);

0 commit comments

Comments
 (0)