mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-05 10:17:30 -05:00
![Samuel Dobson](/assets/img/avatar_default.png)
3f373659d7
Refactor: Replace SigningProvider pointers with unique_ptrs (Andrew Chow)3afe53c403
Cleanup: Drop unused GUI learnRelatedScripts method (Andrew Chow)e2f02aa59e
Refactor: Copy CWallet signals and print function to LegacyScriptPubKeyMan (Andrew Chow)c729afd0a3
Box the wallet: Add multiple keyman maps and loops (Andrew Chow)4977c30d59
refactor: define a UINT256_ONE global constant (Andrew Chow)415afcccd3
HD Split: Avoid redundant upgrades (Andrew Chow)01b4511206
Make UpgradeKeyMetadata work only on LegacyScriptPubKeyMan (Andrew Chow)4a7e43e846
Store p2sh scripts in AddAndGetDestinationForScript (Andrew Chow)501acb5538
Always try to sign for all pubkeys in multisig (Andrew Chow)81610eddbc
List output types in an array in order to be iterated over (Andrew Chow)eb81fc3ee5
Refactor: Allow LegacyScriptPubKeyMan to be null (Andrew Chow)fadc08ad94
Locking: Lock cs_KeyStore instead of cs_wallet in legacy keyman (Andrew Chow)f5be479694
wallet: 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-utACK3f373659d7
Sjors: re-utACK3f373659d7
(it still compiles on macOS after https://github.com/bitcoin/bitcoin/pull/17261#discussion_r370377070) meshcollider: Tested re-ACK3f373659d7
Tree-SHA512: f8e2b8d9efa750b617691e8702d217ec4c33569ec2554a060141d9eb9b9a3a5323e4216938e2485c44625d7a6e0925d40dea1362b3af9857cf08860c2f344716
77 lines
3.1 KiB
C++
77 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;
|
|
}
|