| 701 | |
| 702 | |
| 703 | RPCHelpMan dumpwallet() |
| 704 | { |
| 705 | return RPCHelpMan{"dumpwallet", |
| 706 | "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n" |
| 707 | "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n" |
| 708 | "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n" |
| 709 | "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n", |
| 710 | { |
| 711 | {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The filename with path (absolute path recommended)"}, |
| 712 | }, |
| 713 | RPCResult{ |
| 714 | RPCResult::Type::OBJ, "", "", |
| 715 | { |
| 716 | {RPCResult::Type::STR, "filename", "The filename with full absolute path"}, |
| 717 | } |
| 718 | }, |
| 719 | RPCExamples{ |
| 720 | HelpExampleCli("dumpwallet", "\"test\"") |
| 721 | + HelpExampleRpc("dumpwallet", "\"test\"") |
| 722 | }, |
| 723 | [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 724 | { |
| 725 | const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); |
| 726 | if (!pwallet) return NullUniValue; |
| 727 | |
| 728 | const CWallet& wallet = *pwallet; |
| 729 | const LegacyScriptPubKeyMan& spk_man = EnsureConstLegacyScriptPubKeyMan(wallet); |
| 730 | |
| 731 | // Make sure the results are valid at least up to the most recent block |
| 732 | // the user could have gotten from another RPC command prior to now |
| 733 | wallet.BlockUntilSyncedToCurrentChain(); |
| 734 | |
| 735 | LOCK(wallet.cs_wallet); |
| 736 | |
| 737 | EnsureWalletIsUnlocked(wallet); |
| 738 | |
| 739 | fs::path filepath = fs::u8path(request.params[0].get_str()); |
| 740 | filepath = fs::absolute(filepath); |
| 741 | |
| 742 | /* Prevent arbitrary files from being overwritten. There have been reports |
| 743 | * that users have overwritten wallet files this way: |
| 744 | * https://github.com/bitcoin/bitcoin/issues/9934 |
| 745 | * It may also avoid other security issues. |
| 746 | */ |
| 747 | if (fs::exists(filepath)) { |
| 748 | throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.u8string() + " already exists. If you are sure this is what you want, move it out of the way first"); |
| 749 | } |
| 750 | |
| 751 | std::ofstream file; |
| 752 | file.open(filepath); |
| 753 | if (!file.is_open()) |
| 754 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); |
| 755 | |
| 756 | std::map<CKeyID, int64_t> mapKeyBirth; |
| 757 | wallet.GetKeyBirthTimes(mapKeyBirth); |
| 758 | |
| 759 | int64_t block_time = 0; |
| 760 | CHECK_NONFATAL(wallet.chain().findBlock(wallet.GetLastBlockHash(), FoundBlock().time(block_time))); |