mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 06:43:45 +01:00
3f373659d7Refactor: Replace SigningProvider pointers with unique_ptrs (Andrew Chow)3afe53c403Cleanup: Drop unused GUI learnRelatedScripts method (Andrew Chow)e2f02aa59eRefactor: Copy CWallet signals and print function to LegacyScriptPubKeyMan (Andrew Chow)c729afd0a3Box the wallet: Add multiple keyman maps and loops (Andrew Chow)4977c30d59refactor: define a UINT256_ONE global constant (Andrew Chow)415afcccd3HD Split: Avoid redundant upgrades (Andrew Chow)01b4511206Make UpgradeKeyMetadata work only on LegacyScriptPubKeyMan (Andrew Chow)4a7e43e846Store p2sh scripts in AddAndGetDestinationForScript (Andrew Chow)501acb5538Always try to sign for all pubkeys in multisig (Andrew Chow)81610eddbcList output types in an array in order to be iterated over (Andrew Chow)eb81fc3ee5Refactor: Allow LegacyScriptPubKeyMan to be null (Andrew Chow)fadc08ad94Locking: Lock cs_KeyStore instead of cs_wallet in legacy keyman (Andrew Chow)f5be479694wallet: Improve CWallet:MarkDestinationsDirty (João Barbosa) Pull request description: Continuation of wallet boxes project. Actually makes ScriptPubKeyMan an interface which LegacyScriptPubkeyMan. Moves around functions and things from CWallet into LegacyScriptPubKeyMan so that they are actually separate things without circular dependencies. *** Introducing the `ScriptPubKeyMan` (short for ScriptPubKeyManager) for managing scriptPubKeys and their associated scripts and keys. This functionality is moved over from `CWallet`. Instead, `CWallet` will have a pointer to a `ScriptPubKeyMan` for every possible address type, internal and external. It will fetch the correct `ScriptPubKeyMan` as necessary. When fetching new addresses, it chooses the `ScriptPubKeyMan` based on address type and whether it is change. For signing, it takes the script and asks each `ScriptPubKeyMan` for whether that `ScriptPubKeyMan` considers that script `IsMine`, whether it has that script, or whether it is able to produce a signature for it. If so, the `ScriptPubKeyMan` will provide a `SigningProvider` to the caller which will use that in order to sign. There is currently one `ScriptPubKeyMan` - the `LegacyScriptPubKeyMan`. Each `CWallet` will have only one `LegacyScriptPubKeyMan` with the pointers for all of the address types and change pointing to this `LegacyScriptPubKeyMan`. It is created when the wallet is loaded and all keys and metadata are loaded into it instead of `CWallet`. The `LegacyScriptPubKeyMan` is primarily made up of all of the key and script management that used to be in `CWallet`. For convenience, `CWallet` has a `GetLegacyScriptPubKeyMan` which will return the `LegacyScriptPubKeyMan` or a `nullptr` if it does not have one (not yet implemented, but callers will check for the `nullptr`). For purposes of signing, `LegacyScriptPubKeyMan`'s `GetSigningProvider` will return itself rather than a separate `SigningProvider`. This will be different for future `ScriptPubKeyMan`s. The `LegacyScriptPubKeyMan` will also handle the importing and exporting of keys and scripts instead of `CWallet`. As such, a number of RPCs have been limited to work only if a `LegacyScriptPubKeyMan` can be retrieved from the wallet. These RPCs are `sethdseed`, `addmultisigaddress`, `importaddress`, `importprivkey`, `importpubkey`, `importmulti`, `dumpprivkey`, and `dumpwallet`. Other RPCs which relied on the wallet for scripts and keys have been modified in order to take the `SigningProvider` retrieved from the `ScriptPubKeyMan` for a given script. Overall, these changes should not effect how everything actually works and the user should experience no difference between having this change and not having it. As such, no functional tests were changed, and the only unit tests changed were those that were directly accessing `CWallet` functions that have been removed. This PR is the last step in the [Wallet Structure Changes](https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Class-Structure-Changes). ACKs for top commit: instagibbs: re-utACK3f373659d7Sjors: re-utACK3f373659d7(it still compiles on macOS after https://github.com/bitcoin/bitcoin/pull/17261#discussion_r370377070) meshcollider: Tested re-ACK3f373659d7Tree-SHA512: f8e2b8d9efa750b617691e8702d217ec4c33569ec2554a060141d9eb9b9a3a5323e4216938e2485c44625d7a6e0925d40dea1362b3af9857cf08860c2f344716
78 lines
3.1 KiB
C++
78 lines
3.1 KiB
C++
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <wallet/psbtwallet.h>
|
|
|
|
TransactionError FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs)
|
|
{
|
|
LOCK(pwallet->cs_wallet);
|
|
// Get all of the previous transactions
|
|
complete = true;
|
|
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
|
|
const CTxIn& txin = psbtx.tx->vin[i];
|
|
PSBTInput& input = psbtx.inputs.at(i);
|
|
|
|
if (PSBTInputSigned(input)) {
|
|
continue;
|
|
}
|
|
|
|
// Verify input looks sane. This will check that we have at most one uxto, witness or non-witness.
|
|
if (!input.IsSane()) {
|
|
return TransactionError::INVALID_PSBT;
|
|
}
|
|
|
|
// If we have no utxo, grab it from the wallet.
|
|
if (!input.non_witness_utxo && input.witness_utxo.IsNull()) {
|
|
const uint256& txhash = txin.prevout.hash;
|
|
const auto it = pwallet->mapWallet.find(txhash);
|
|
if (it != pwallet->mapWallet.end()) {
|
|
const CWalletTx& wtx = it->second;
|
|
// We only need the non_witness_utxo, which is a superset of the witness_utxo.
|
|
// The signing code will switch to the smaller witness_utxo if this is ok.
|
|
input.non_witness_utxo = wtx.tx;
|
|
}
|
|
}
|
|
|
|
// Get the Sighash type
|
|
if (sign && input.sighash_type > 0 && input.sighash_type != sighash_type) {
|
|
return TransactionError::SIGHASH_MISMATCH;
|
|
}
|
|
|
|
// Get the scriptPubKey to know which SigningProvider to use
|
|
CScript script;
|
|
if (!input.witness_utxo.IsNull()) {
|
|
script = input.witness_utxo.scriptPubKey;
|
|
} else if (input.non_witness_utxo) {
|
|
if (txin.prevout.n >= input.non_witness_utxo->vout.size()) {
|
|
return TransactionError::MISSING_INPUTS;
|
|
}
|
|
script = input.non_witness_utxo->vout[txin.prevout.n].scriptPubKey;
|
|
} else {
|
|
// There's no UTXO so we can just skip this now
|
|
complete = false;
|
|
continue;
|
|
}
|
|
SignatureData sigdata;
|
|
input.FillSignatureData(sigdata);
|
|
std::unique_ptr<SigningProvider> provider = pwallet->GetSigningProvider(script, sigdata);
|
|
if (!provider) {
|
|
complete = false;
|
|
continue;
|
|
}
|
|
|
|
complete &= SignPSBTInput(HidingSigningProvider(provider.get(), !sign, !bip32derivs), psbtx, i, sighash_type);
|
|
}
|
|
|
|
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
|
|
for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
|
|
const CTxOut& out = psbtx.tx->vout.at(i);
|
|
std::unique_ptr<SigningProvider> provider = pwallet->GetSigningProvider(out.scriptPubKey);
|
|
if (provider) {
|
|
UpdatePSBTOutput(HidingSigningProvider(provider.get(), true, !bip32derivs), psbtx, i);
|
|
}
|
|
}
|
|
|
|
return TransactionError::OK;
|
|
}
|