Easier to review ignoring whitespace:
git log -p -n1 -w
This commit does not change behavior. It passes new CScript arguments to signing functions, but the arguments aren't currently used.
Split from #17261
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--174a7506f384e20aa4161008e828411d-->
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
52 | + } 53 | + SignatureData sigdata; 54 | + input.FillSignatureData(sigdata); 55 | + const SigningProvider* provider = pwallet->GetSigningProvider(script, sigdata); 56 | + if (!provider) { 57 | + continue;
Adding complete = false would seem more consistent with previous behavior which sets complete to false if it can't sign one of the inputs.
Done
45 | + if (input.non_witness_utxo) { 46 | + script = input.non_witness_utxo->vout[txin.prevout.n].scriptPubKey; 47 | + } else if (!input.witness_utxo.IsNull()) { 48 | + script = input.witness_utxo.scriptPubKey; 49 | + } else { 50 | + // There's no UTXO so we can just skip this now
Add complete = false?
Done
38 | @@ -39,12 +39,33 @@ TransactionError FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& ps 39 | return TransactionError::SIGHASH_MISMATCH; 40 | } 41 | 42 | - complete &= SignPSBTInput(HidingSigningProvider(pwallet->GetSigningProvider(), !sign, !bip32derivs), psbtx, i, sighash_type); 43 | + // Get the scriptPubKey to know which SigningProvider to use 44 | + CScript script; 45 | + if (input.non_witness_utxo) { 46 | + script = input.non_witness_utxo->vout[txin.prevout.n].scriptPubKey;
Check for the witness UTXO first? (given the above The signing code will switch to the smaller witness_utxo if this is ok.). It seems unlikely they'd have different signing providers, but still.
Done
3303 | + providers.insert(&DUMMY_SIGNING_PROVIDER); 3304 | + } 3305 | + 3306 | + UniValue result; 3307 | + for (const SigningProvider* provider : providers) { 3308 | + result = SignTransaction(mtx, provider, coins, request.params[2]);
This seems brittle. I'm assuming the goal, if multiple signing providers match, is to have them all sign (part of) the transaction? What if the first signer succeeds, but the second returns an error object because it didn't have the key (in which it shouldn't have matched, but still...)?
There shouldn't ever be a SigningProvider that doesn't match.
In commit "Refactor: Require scriptPubKey to get wallet SigningProvider" (f7510c144b2262e1ee114eaa740b889c24ec7abb)
According to RPC documentation result has three fields: "hex" "complete" and "errors". I guess for "hex" and "complete" fields it makes sense to take the last values, but errors field should probably accumulate? In any case, this code is not very future proof in case new fields are added. Would suggest changing SignTransaction to take a UniValue& result input/output parameter, so it can be responsible for updating the result at each step, and this code isn't just blindly overwriting previous results.
I've added a commit which changes SignTransaction to void and has a result parameter to accumulate the errors array.
549 | @@ -550,7 +550,11 @@ static UniValue signmessage(const JSONRPCRequest& request) 550 | throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); 551 | } 552 | 553 | - const SigningProvider* provider = pwallet->GetSigningProvider(); 554 | + CScript script_pub_key = GetScriptForDestination(*pkhash);
In commit "Refactor: Require scriptPubKey to get wallet SigningProvider" (f7510c144b2262e1ee114eaa740b889c24ec7abb)
It would seem more direct to replace *pkhash with dest here and call GetScriptForDestination(dest)
I don't think it really matters as we still need pkhash since signmessage is supposed to only work on p2pkh addresses.
we still need
pkhashsincesignmessageis supposed to only work onp2pkhaddresses
That will change in https://github.com/bitcoin/bitcoin/pull/16440/files#diff-df7d84ff2f53fcb2a0dc15a3a51e55ceR559
3770 | + const SigningProvider* provider = pwallet->GetSigningProvider(scriptPubKey); 3771 | 3772 | isminetype mine = pwallet->IsMine(dest); 3773 | ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); 3774 | - bool solvable = IsSolvable(*provider, scriptPubKey); 3775 | + bool solvable = provider ? IsSolvable(*provider, scriptPubKey) : false;
In commit "Refactor: Require scriptPubKey to get wallet SigningProvider" (f7510c144b2262e1ee114eaa740b889c24ec7abb)
Would be slightly simpler to replace ternary with solvable = provider && IsSolvable(*provider)
Done
Code review ACK f7510c144b2262e1ee114eaa740b889c24ec7abb. Pretty straightforward to verify this doesn't change behavior.
SignTransaction will be called multiple times in the future. Pass
it a result UniValue so that it can accumulate the results of multiple
SignTransaction passes.
Easier to review ignoring whitespace:
git log -p -n1 -w
This commit does not change behavior. It passes new CScript arguments to
signing functions, but the arguments aren't currently used.Code review ACK d0dab897afaac0a18aa47d3ce673a4a43a69178a. Thanks for the SignTransaction update. No other changes since last review
Code review ACK d0dab897afaac0a18aa47d3ce673a4a43a69178a
@instagibbs and @meshcollider, you may be interested to review this. This is code you previously acked when it was part of #16341
20 | @@ -21,9 +21,9 @@ class SigningProvider; 21 | * @param keystore Temporary keystore containing signing keys 22 | * @param coins Map of unspent outputs 23 | * @param hashType The signature hash type 24 | - * @returns JSON object with details of signed transaction 25 | + * @param result JSON object where signed transaction results accumulate 26 | */ 27 | -UniValue SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType); 28 | +void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType, UniValue& result);
4b0c718f8f48c678cbe4575e9a9cf9e62a30f0da
An overload could be added, like
UniValue SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType)
{
UniValue result(UniValue::VOBJ);
SignTransaction(mtx, &keystore, coins, hashType, result);
return result;
}
But I see that in the next commit this refactor is handy in signrawtransactionwithwallet RPC.
Code review ACK d0dab897afaac0a18aa47d3ce673a4a43a69178a.
116 | @@ -117,8 +117,22 @@ class WalletImpl : public Wallet 117 | std::string error; 118 | return m_wallet->GetNewDestination(type, label, dest, error); 119 | } 120 | - bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet->GetLegacyScriptPubKeyMan()->GetPubKey(address, pub_key); } 121 | - bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetLegacyScriptPubKeyMan()->GetKey(address, key); } 122 | + bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override
note for future work(TM): address is a horrible name for this argument
2099 | @@ -2096,7 +2100,7 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector< 2100 | continue; 2101 | } 2102 | 2103 | - const SigningProvider* provider = GetSigningProvider(); 2104 | + const SigningProvider* provider = GetSigningProvider(wtx.tx->vout[i].scriptPubKey);
do we need to check for knowledge of provider here?
oh i cannot read.
3295 | + const SigningProvider* provider = pwallet->GetSigningProvider(coin_pair.second.out.scriptPubKey); 3296 | + if (provider) { 3297 | + providers.insert(std::move(provider)); 3298 | + } 3299 | + } 3300 | + if (providers.size() == 0) {
non-blocking-nit: .empty()
Not fixing to avoid invalidating ACKs.
ready for merge? @meshcollider
121 | - bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetLegacyScriptPubKeyMan()->GetKey(address, key); } 122 | + bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override 123 | + { 124 | + const SigningProvider* provider = m_wallet->GetSigningProvider(script); 125 | + if (provider) { 126 | + return provider->GetPubKey(address, pub_key);
Its kinda not that nice that there is no check the script and address have anything to do with each other. You could end up requesting the wrong SPKM for an address quite easily. Maybe move some of the ExtractDestination stuff inside here instead?
1341 | @@ -1342,7 +1342,11 @@ bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig 1342 | const CScript& scriptPubKey = txout.scriptPubKey; 1343 | SignatureData sigdata; 1344 | 1345 | - const SigningProvider* provider = GetSigningProvider(); 1346 | + const SigningProvider* provider = GetSigningProvider(scriptPubKey); 1347 | + if (!provider) { 1348 | + // We don't know about this scriptpbuKey;
nit: typo (same below)
2976 | @@ -2971,8 +2977,11 @@ static UniValue listunspent(const JSONRPCRequest& request) 2977 | entry.pushKV("spendable", out.fSpendable); 2978 | entry.pushKV("solvable", out.fSolvable); 2979 | if (out.fSolvable) { 2980 | - auto descriptor = InferDescriptor(scriptPubKey, *pwallet->GetLegacyScriptPubKeyMan()); 2981 | - entry.pushKV("desc", descriptor->ToString()); 2982 | + const SigningProvider* provider = pwallet->GetSigningProvider(scriptPubKey);
This can probably be combined with above to simplify
Code review ACK d0dab897afaac0a18aa47d3ce673a4a43a69178a