Refactor PSBTInput signing to enforce invariant

Refactor the process of PSBTInput signing to enforce the invariant that
a PSBTInput always has _either_ a witness_utxo or a non_witness_utxo,
never both.

This simplifies the logic of SignPSBTInput slightly, since it no longer
has to deal with the "both" case. When calling it, we now give it, in
order of preference: (1) whichever of the utxo fields was already
present in the PSBT we received, or (2) if neither, the
non_witness_utxo field, which is just a copy of the input transaction,
which we get from the wallet.

SignPSBTInput no longer has to remove one of the two fields; instead, it
will check if we have a witness signature, and if so, it will replace
the non_witness_utxo with the witness_utxo (which is smaller, as it is
just a copy of the output being spent.)

Add PSBTInput::IsSane checks in two more places, which checks for
both utxo fields being present; we will now give an RPC error early on
if we are supplied such a malformed PSBT to fill in.

Also add a check to FillPSBT, to avoid touching any input that is
already signed. (This is now redundant, since we should no longer
potentially harm an already-signed input, but it's harmless.)

fixes #14473

Github-Pull: #14588
This commit is contained in:
Glenn Willen 2018-10-26 15:31:41 -07:00 committed by Anthony Fieroni
parent 248e1132b2
commit 2ff659ac91
2 changed files with 23 additions and 0 deletions

View file

@ -252,6 +252,19 @@ namespace {
PSBTInput& input = psbt.inputs.at(index); PSBTInput& input = psbt.inputs.at(index);
const CMutableTransaction& tx = *psbt.tx; const CMutableTransaction& tx = *psbt.tx;
// Verify input sanity, which checks that at most one of witness or non-witness utxos is provided.
if (!input.IsSane()) {
return false;
}
// If we have a witness signature, use the smaller witness UTXO.
if (sigdata.witness) {
input.witness_utxo = utxo;
input.non_witness_utxo = nullptr;
}
class SignatureExtractorChecker final : public BaseSignatureChecker class SignatureExtractorChecker final : public BaseSignatureChecker
{ {
private: private:

View file

@ -3988,6 +3988,16 @@ UniValue sethdseed(const JSONRPCRequest& request)
return NullUniValue; return NullUniValue;
} }
continue;
}
// Verify input looks sane. This will check that we have at most one uxto, witness or non-witness.
if (!input.IsSane()) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "PSBT input is not sane.");
}
// If we have no utxo, grab it from the wallet.
if (!input.non_witness_utxo && input.witness_utxo.IsNull()) {
if (sigdata.witness) { if (sigdata.witness) {
// Convert the non-witness utxo to witness // Convert the non-witness utxo to witness
if (input.witness_utxo.IsNull() && input.non_witness_utxo) { if (input.witness_utxo.IsNull() && input.non_witness_utxo) {