Does this look like a good approach?
TODO:
- rawtransaction sweep functionality
- GUI sweep (Receive tab?)
- abstract shared sweep logic
RPC tests
NOTE: Currently needs #14602 for tests to pass
Concept ACK (Haven’t really looked at the code). I think a sweep function would be a great feature. One could import “old” private keys into a new HD wallet for example.
Possible extension: sweepseed
could be an extended version of that, moving all funds form a HD seed to a new one, generating large lookup-windows on different chainpathes. It could also be UTXO set only not requiring a -rescan.
importprivkey
with another optional argument sweep
defaulting to false
?
1070+ std::map<uint256, CCoins> mapcoins;
1071+ {
1072+ LOCK(cs_main);
1073+ mempool.FindScriptPubKey(setscriptSearch, mapcoins);
1074+ FlushStateToDisk();
1075+ pcoinsTip->FindScriptPubKey(setscriptSearch, mapcoins);
Concept ACK.
Hmm, what about extending RPC importprivkey with another optional argument sweep defaulting to false?
Please don’t do this. People confuse import
and sweep
all over the place. The least we can do is make them separate RPCs with separate documentation.
1105+
1106+ tempKeystore.AddKey(key);
1107+ CKeyID address = pubkey.GetID();
1108+ CScript script = GetScriptForDestination(address);
1109+ if (!script.empty()) {
1110+ needles.insert(script);
1109+ if (!script.empty()) {
1110+ needles.insert(script);
1111+ }
1112+ script = GetScriptForRawPubKey(pubkey);
1113+ if (!script.empty()) {
1114+ needles.insert(script);
1119+ } else {
1120+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unrecognised option '%s'", optname));
1121+ }
1122+ }
1123+
1124+ // Ensure keypool is filled if possible
1132+
1133+ // Reserve the key we will be using
1134+ CReserveKey reservekey(pwallet);
1135+ CPubKey pubkey;
1136+ if (!reservekey.GetReservedKey(pubkey)) {
1137+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
1137+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
1138+ }
1139+
1140+ // Scan UTXO set for inputs
1141+ std::vector<CTxOut> input_txos;
1142+ {
coins
1171+
1172+ while (true) {
1173+ if (IsDust(tx.vout[0], ::minRelayTxFee)) {
1174+ throw JSONRPCError(RPC_VERIFY_REJECTED, "Swept value would be dust");
1175+ }
1176+ for (size_t input_index = 0; input_index < tx.vin.size(); ++input_index) {
CWallet::FundTransaction
with coin control configured and with subtract fee from amount?
cs_main
lock on AcceptToMemoryPool
)
utACK a397deb247fc404064cf76ede8d64eb68f4fefe6 (will test soon). I personally dislike the “direct”-approach. I would like to “see” the transaction before submitting.
Possible extensions:
createrawsweeptransaction
(or similar)0@@ -0,0 +1,66 @@
1+#!/usr/bin/env python3
2+# Copyright (c) 2014-2017 The Bitcoin Core developers
3+# Distributed under the MIT software license, see the accompanying
4+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+"""Test the sweepprivkeys RPC."""
6+
7+import decimal
8+import math
The check fail is unrelated to this PR and limited to the ARM build, lacking the “flake8” python library.
0contrib/devtools/lint-python.sh: 10: contrib/devtools/lint-python.sh: flake8: not found
removing unused imports won’t fix lint-python.sh either.
If we still want this, it needs rebase/implementation in terms of #12196. But I’m going to close it for now, it’s been open since 2016 and there’s no clear progress.
It might make sense to open a new PR if you start work on this again, or you can ask me to reopen it.
scantxoutset
to be used in place of sweeping? I like to try to sort out my needs using that, but haven’t kept myself up to date enough to understand it without handholding. There is the integration test in python, but…
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
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.
942+ const UniValue& optval = request.params[0][optname];
943+ if (optname == "privkeys") {
944+ const UniValue& privkeys_a = optval.get_array();
945+ for (size_t privkey_i = 0; privkey_i < privkeys_a.size(); ++privkey_i) {
946+ const UniValue& privkey_wif = privkeys_a[privkey_i];
947+ std::string wif_secret = privkey_wif.get_str();
createrawsweeptransaction
)
master
.
createrawsweep
call (rather then directly signing and executing).
Maybe you can change this to be an argument for “scantxoutset” that would also spit out a rawtransaction (with configurable fee and eventually configurable target address) for the sweep transaction.
972+ }
973+
974+ if (request.fHelp || request.params.size() != 1) {
975+ throw std::runtime_error(
976+ RPCHelpMan{"sweepprivkeys",
977+ "\nSends bitcoins controlled by private key to specified destinations.\n",
Concept ACK. Using scantxoutset
internally seems like a good idea. It needs a fee control option, could be as simple as feeRate with 1 sat/byte default. Ideally also RBF control, but that can wait for a followup.
As mentioned by others, it’s good to be able to inspect the transaction. That could just be another option. In #16378 I introduce a add_to_wallet
to option, and the RPC call returns a hex & PSBT if false
.
Another potential followup could add descriptor support; those can have private keys now too. Others above suggest using those instead of WIF, but I think an array of WIFs is still common enough to be worth supporting directly.
This PR sweeps into the wallet itself. A followup could sweep into any arbitrary descriptor, which would make migrating wallets to some new scheme easier, e.g. moving from single-sig to multi-sig without joining UTXOs.
bitcoin-wallet
, so going to have to just make it a Knots-only hack for now. :/
I don’t see any sane way to rebase this post-bitcoin-wallet
I don’t think it should be too bad if someone wants to pick it up. It should just require a new interfaces::Chain
method to wrap FindScriptPubKey
calls, since wallet code can no longer access mempool
and pcoinsdbview
globals directly.