Optionally sweep funds from private key. #8763

pull CryptAxe wants to merge 1 commits into bitcoin:master from bitcoin-nakamoto:2751PullRequest changing 2 files +174 −3
  1. CryptAxe commented at 5:43 AM on September 20, 2016: contributor

    Declared wallet rpc function "sweepkey" in src/wallet/rpcwallet.cpp

    Added "sweepkey" rpc function, can be used to sweep a wallet's private key's outputs to a new key.

    In rpc wallet function "importprivkey", added 2 optional parameters bool sweep & destination bitcoin address for sweep transaction. (Optionally sweep funds on private key import)

    Added SweepPrivKey function to src/wallet/rpcdump.cpp to help "sweepkey" and "importprivkey"

  2. Optionally sweep funds from private key.
    Declared wallet rpc function "sweepkey" in src/wallet/rpcwallet.cpp
    
    Added "sweepkey" rpc function, can be used to sweep a wallet's private key's
    outputs to a new key.
    
    In rpc wallet function "importprivkey", added 2 optional parameters
    bool sweep & destination bitcoin address for sweep transaction.
    (Optionally sweep funds on private key import)
    
    Added SweepPrivKey function to src/wallet/rpcdump.cpp to help "sweepkey"
    and "importprivkey"
    58afbb2868
  3. CryptAxe commented at 5:48 AM on September 20, 2016: contributor
  4. in src/wallet/rpcdump.cpp:None in 58afbb2868
      88 | +    if (!dirtyKey.VerifyPubKey(pubkey))
      89 | +        return false;
      90 | +
      91 | +    LOCK2(cs_main, pwalletMain->cs_wallet);
      92 | +
      93 | +    // Get outputs from wallet
    


    luke-jr commented at 6:29 AM on September 20, 2016:

    But the wallet won't have tracked UTXOs for this private key...


    CryptAxe commented at 4:03 AM on September 21, 2016:

    This is intended for a private key that is already in the wallet, with outputs.


    luke-jr commented at 8:02 AM on September 21, 2016:

    Why would you sweep it, if it's in the wallet (and thereby trusted to be exclusively yours)?

  5. in src/wallet/rpcdump.cpp:None in 58afbb2868
      94 | +    std::vector<COutput> vCoins;
      95 | +    pwalletMain->AvailableCoins(vCoins, false);
      96 | +
      97 | +    // Find all outputs of the key
      98 | +    std::vector<COutput> vToSweep;
      99 | +    BOOST_FOREACH(COutput output, vCoins)
    


    luke-jr commented at 6:30 AM on September 20, 2016:

    It's the full UTXO set you need to look through, not merely the wallet's coins.


    MarcoFalke commented at 8:24 AM on September 20, 2016:

    Nit: Don't use BOOST_*


    CryptAxe commented at 4:06 AM on September 21, 2016:

    This is for after importing a private key.

    I see BOOST_FOREACH particularly used in many places throughout the bitcoin source code, I will remove it but could you educate me as to me why I shouldn't use it?


    MarcoFalke commented at 7:34 AM on September 21, 2016:

    We are moving towards using the cpp11 for loop, no need to go back in new code and use a framework.

  6. in src/wallet/rpcdump.cpp:None in 58afbb2868
     126 | +    if (!mtx.vin.size() || !(total > 0))
     127 | +        return false;
     128 | +
     129 | +    // Add sweep destination - fee
     130 | +    mtx.vout.push_back(CTxOut(total, GetScriptForDestination(destAddress.Get())));
     131 | +    mtx.vout[0].nValue -= 3*CWallet::GetMinimumFee(GetVirtualTransactionSize(mtx), DEFAULT_TX_CONFIRM_TARGET, mempool);
    


    luke-jr commented at 6:34 AM on September 20, 2016:

    3x the fee why? Probably should make this configurable...


    MarcoFalke commented at 8:26 AM on September 20, 2016:

    Agree. Also, the new rpc should take a dictionary as input and not positional args to make this easier.


    CryptAxe commented at 4:09 AM on September 21, 2016:

    In testing I ended up with a sweep transaction where the fee estimation was not enough, and the tx was rejected from the memory pool. This is a bad solution though, I'm more than open to suggestions.


    MarcoFalke commented at 7:36 AM on September 21, 2016:

    E.g. fundrawtransaction takes options to set the fee rate.

  7. in src/wallet/rpcdump.cpp:None in 58afbb2868
     128 | +
     129 | +    // Add sweep destination - fee
     130 | +    mtx.vout.push_back(CTxOut(total, GetScriptForDestination(destAddress.Get())));
     131 | +    mtx.vout[0].nValue -= 3*CWallet::GetMinimumFee(GetVirtualTransactionSize(mtx), DEFAULT_TX_CONFIRM_TARGET, mempool);
     132 | +
     133 | +    mtx.nLockTime = chainActive.Height();
    


    luke-jr commented at 6:34 AM on September 20, 2016:

    This should probably be shared with the wallet code doing the same...


    CryptAxe commented at 4:12 AM on September 21, 2016:

    Are you talking about setting nLockTime? I didn't see that... Will look

  8. in src/wallet/rpcdump.cpp:None in 58afbb2868
      76 | @@ -74,19 +77,166 @@ std::string DecodeDumpString(const std::string &str) {
      77 |      return ret.str();
      78 |  }
      79 |  
      80 | +bool SweepPrivKey(CBitcoinSecret key, CBitcoinAddress destAddress) {
    


    luke-jr commented at 6:36 AM on September 20, 2016:

    This should probably get moved into a non-RPC-specific location, and RPC-specific errors moved out.


    CryptAxe commented at 4:02 AM on September 21, 2016:

    Agreed

  9. in src/wallet/rpcdump.cpp:None in 58afbb2868
     168 | +        LogPrintf("SweepPrivKey(): Error: Transaction not valid\n");
     169 | +        return false;
     170 | +    }
     171 | +
     172 | +    if (pwalletMain->GetBroadcastTransactions() && !g_connman)
     173 | +        throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
    


    luke-jr commented at 6:37 AM on September 20, 2016:

    Too late to error here - it's already been fed into AcceptToMemoryPool.


    CryptAxe commented at 4:14 AM on September 21, 2016:

    If I perform this check and throw the error before AcceptToMemoryPool, would that be okay?


    luke-jr commented at 8:02 AM on September 21, 2016:

    n/a if create and broadcast are split up.

  10. in src/wallet/rpcdump.cpp:None in 58afbb2868
     187 | +    if (!EnsureWalletIsAvailable(fHelp))
     188 | +        return NullUniValue;
     189 | +
     190 | +    if (fHelp || params.size() != 2)
     191 | +        throw runtime_error(
     192 | +            "sweepkey \"bitcoinprivkey\" \"bitcoinaddress\"\n"
    


    luke-jr commented at 6:37 AM on September 20, 2016:

    Suggest "sweepprivkey" to match "dumpprivkey" and "importprivkey"

  11. in src/wallet/rpcdump.cpp:None in 58afbb2868
     191 | +        throw runtime_error(
     192 | +            "sweepkey \"bitcoinprivkey\" \"bitcoinaddress\"\n"
     193 | +            "\nSweep the privkey's outputs to the specified address.\n"
     194 | +            "\nArguments:\n"
     195 | +            "1. \"bitcoinprivkey\"   (string, required) The private key (see dumpprivkey)\n"
     196 | +            "2. \"bitcoinaddress\"   (bitcoinaddress, required) The destination address\n"
    


    luke-jr commented at 6:38 AM on September 20, 2016:

    bitcoinaddress isn't a JSON type. Just string.


    luke-jr commented at 6:39 AM on September 20, 2016:

    Furthermore, so long as you're insisting on an address here, it makes no sense to include this as a wallet RPC...

  12. in src/wallet/rpcdump.cpp:None in 58afbb2868
     201 | +            + HelpExampleRpc("sweepkey", "\"mykey\" \"myaddress\"")
     202 | +        );
     203 | +
     204 | +    LOCK2(cs_main, pwalletMain->cs_wallet);
     205 | +
     206 | +    EnsureWalletIsUnlocked();
    


    luke-jr commented at 6:38 AM on September 20, 2016:

    Why? Shouldn't this work without unlocking the wallet?


    rebroad commented at 7:07 AM on September 20, 2016:

    It'll need to be unlocked at some point won't it? (in order to move the bitcoins from the swept address), although ideally there ought to be a way to do this without needing to unlock manually - i.e. store the private key for the swept address but require the private key of the wallet it is being swept to to access them.


    luke-jr commented at 7:29 AM on September 20, 2016:

    No. The swept key (not address; addresses don't control bitcoins) is not part of the wallet, and the wallet doesn't need to be unlocked to receive. Furthermore, so long as the user is proving the sweep-to address, the wallet isn't even being used.


    CryptAxe commented at 4:17 AM on September 21, 2016:

    I was making this with the intention that the private key is actually in the wallet, or being imported, in which case it will be in the wallet before the sweep.

  13. in src/wallet/rpcdump.cpp:None in 58afbb2868
     235 |              "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
     236 |              "\nArguments:\n"
     237 |              "1. \"bitcoinprivkey\"   (string, required) The private key (see dumpprivkey)\n"
     238 |              "2. \"label\"            (string, optional, default=\"\") An optional label\n"
     239 |              "3. rescan               (boolean, optional, default=true) Rescan the wallet for transactions\n"
     240 | +            "4. sweepkey             (boolean, optional, default=false) Sweep imported key for improved security\n"
    


    luke-jr commented at 6:40 AM on September 20, 2016:

    Importing an untrusted key is never secure, so it doesn't make sense to import+sweep...


    CryptAxe commented at 4:17 AM on September 21, 2016:

    Well that was the main issue pointed out in #2751 or I am just very confused.


    rebroad commented at 7:55 AM on September 21, 2016:

    @CryptAxe I think @luke-jr means that the risk is having funds to the imported key. Is this what you mean, @luke-jr ? I'm not sure how this would happen, but as part of making a key autoswept, I would hope this pull would make it less easy to select for receipt of funds as part of this.


    luke-jr commented at 8:06 AM on September 21, 2016:

    The first "use case" in #2751 I assume is poorly phrased. You never want to import such a key. What makes sense, and what @jgarzik probably meant, is that instead of importing the key, you sweep it, and keep a copy of the private key in an as-of-yet-non-existent part of the wallet to be continually swept in case someone sends funds to it in the future.

    The second use case is not likely to occur often in practice, but would benefit from the old keys being moved into a separated sweep-only keystore as well.

  14. luke-jr changes_requested
  15. jonasschnelli commented at 7:01 AM on September 20, 2016: contributor

    I think a sweep command is desirable.

    Just thinking: how would it be if we would have something like createrawsweeptransaction <pubkey> <outputaddress> as a first step. The people can use signrawtransaction together with the privatekey. We could still support a sweepkey RPC call that would use createrawsweeptransaction || signrawtransaction || sendrawtransaction.

    Splitting it up into a createrawsweeptransaction would allow to have more control over the sweep (confirmation page, etc.).

  16. jonasschnelli added the label RPC/REST/ZMQ on Sep 20, 2016
  17. MarcoFalke changes_requested
  18. laanwj added the label Wallet on Sep 20, 2016
  19. CryptAxe commented at 4:02 AM on September 21, 2016: contributor

    Thanks everyone, I will take all of your input and come back with something improved when I have the time. Does everyone agree with @jonasschnelli 's suggestion to separate the creation of the sweep transaction from the signing / broadcast? It seems like a good idea to me.

  20. gmaxwell commented at 7:05 PM on September 21, 2016: contributor

    As an aside, any new functionality which requires a rescan really must take a block range (allowing for a range that is open on the upper side.. e.g. a starting height) as an (optional) argument.

    [hmm. so this could be done without a rescan by only evaluating the utxo set...]

  21. CryptAxe closed this on Oct 1, 2016

  22. MarcoFalke locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 15:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me