@@ -2572,6 +2572,37 @@ static RPCHelpMan listwallets()
2572
2572
};
2573
2573
}
2574
2574
2575
+ static std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelper (WalletContext& context, UniValue load_on_start_param, const std::string wallet_name)
2576
+ {
2577
+ DatabaseOptions options;
2578
+ DatabaseStatus status;
2579
+ options.require_existing = true ;
2580
+ bilingual_str error;
2581
+ std::vector<bilingual_str> warnings;
2582
+ std::optional<bool > load_on_start = load_on_start_param.isNull () ? std::nullopt : std::optional<bool >(load_on_start_param.get_bool ());
2583
+ std::shared_ptr<CWallet> const wallet = LoadWallet (*context.chain , wallet_name, load_on_start, options, status, error, warnings);
2584
+
2585
+ if (!wallet) {
2586
+ // Map bad format to not found, since bad format is returned when the
2587
+ // wallet directory exists, but doesn't contain a data file.
2588
+ RPCErrorCode code = RPC_WALLET_ERROR;
2589
+ switch (status) {
2590
+ case DatabaseStatus::FAILED_NOT_FOUND:
2591
+ case DatabaseStatus::FAILED_BAD_FORMAT:
2592
+ code = RPC_WALLET_NOT_FOUND;
2593
+ break ;
2594
+ case DatabaseStatus::FAILED_ALREADY_LOADED:
2595
+ code = RPC_WALLET_ALREADY_LOADED;
2596
+ break ;
2597
+ default : // RPC_WALLET_ERROR is returned for all other cases.
2598
+ break ;
2599
+ }
2600
+ throw JSONRPCError (code, error.original );
2601
+ }
2602
+
2603
+ return { wallet, warnings };
2604
+ }
2605
+
2575
2606
static RPCHelpMan loadwallet ()
2576
2607
{
2577
2608
return RPCHelpMan{" loadwallet" ,
@@ -2598,30 +2629,7 @@ static RPCHelpMan loadwallet()
2598
2629
WalletContext& context = EnsureWalletContext (request.context );
2599
2630
const std::string name (request.params [0 ].get_str ());
2600
2631
2601
- DatabaseOptions options;
2602
- DatabaseStatus status;
2603
- options.require_existing = true ;
2604
- bilingual_str error;
2605
- std::vector<bilingual_str> warnings;
2606
- std::optional<bool > load_on_start = request.params [1 ].isNull () ? std::nullopt : std::optional<bool >(request.params [1 ].get_bool ());
2607
- std::shared_ptr<CWallet> const wallet = LoadWallet (*context.chain , name, load_on_start, options, status, error, warnings);
2608
- if (!wallet) {
2609
- // Map bad format to not found, since bad format is returned when the
2610
- // wallet directory exists, but doesn't contain a data file.
2611
- RPCErrorCode code = RPC_WALLET_ERROR;
2612
- switch (status) {
2613
- case DatabaseStatus::FAILED_NOT_FOUND:
2614
- case DatabaseStatus::FAILED_BAD_FORMAT:
2615
- code = RPC_WALLET_NOT_FOUND;
2616
- break ;
2617
- case DatabaseStatus::FAILED_ALREADY_LOADED:
2618
- code = RPC_WALLET_ALREADY_LOADED;
2619
- break ;
2620
- default : // RPC_WALLET_ERROR is returned for all other cases.
2621
- break ;
2622
- }
2623
- throw JSONRPCError (code, error.original );
2624
- }
2632
+ auto [wallet, warnings] = LoadWalletHelper (context, request.params [1 ], name);
2625
2633
2626
2634
UniValue obj (UniValue::VOBJ);
2627
2635
obj.pushKV (" name" , wallet->GetName ());
@@ -2795,6 +2803,68 @@ static RPCHelpMan createwallet()
2795
2803
};
2796
2804
}
2797
2805
2806
+ static RPCHelpMan restorewallet ()
2807
+ {
2808
+ return RPCHelpMan{
2809
+ " restorewallet" ,
2810
+ " \n Restore and loads a wallet from backup.\n " ,
2811
+ {
2812
+ {" wallet_name" , RPCArg::Type::STR, RPCArg::Optional::NO, " The name that will be applied to the restored wallet" },
2813
+ {" backup_file" , RPCArg::Type::STR, RPCArg::Optional::NO, " The backup file that will be used to restore the wallet." },
2814
+ {" load_on_startup" , RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, " Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged." },
2815
+ },
2816
+ RPCResult{
2817
+ RPCResult::Type::OBJ, " " , " " ,
2818
+ {
2819
+ {RPCResult::Type::STR, " name" , " The wallet name if restored successfully." },
2820
+ {RPCResult::Type::STR, " warning" , " Warning message if wallet was not loaded cleanly." },
2821
+ }
2822
+ },
2823
+ RPCExamples{
2824
+ HelpExampleCli (" restorewallet" , " \" testwallet\" \" home\\ backups\\ backup-file.bak\" " )
2825
+ + HelpExampleRpc (" restorewallet" , " \" testwallet\" \" home\\ backups\\ backup-file.bak\" " )
2826
+ + HelpExampleCliNamed (" restorewallet" , {{" wallet_name" , " testwallet" }, {" backup_file" , " home\\ backups\\ backup-file.bak\" " }, {" load_on_startup" , true }})
2827
+ + HelpExampleRpcNamed (" restorewallet" , {{" wallet_name" , " testwallet" }, {" backup_file" , " home\\ backups\\ backup-file.bak\" " }, {" load_on_startup" , true }})
2828
+ },
2829
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2830
+ {
2831
+
2832
+ WalletContext& context = EnsureWalletContext (request.context );
2833
+
2834
+ std::string backup_file = request.params [1 ].get_str ();
2835
+
2836
+ if (!fs::exists (backup_file)) {
2837
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Backup file does not exist" );
2838
+ }
2839
+
2840
+ std::string wallet_name = request.params [0 ].get_str ();
2841
+
2842
+ const fs::path wallet_path = fsbridge::AbsPathJoin (GetWalletDir (), wallet_name);
2843
+
2844
+ if (fs::exists (wallet_path)) {
2845
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Wallet name already exists." );
2846
+ }
2847
+
2848
+ if (!TryCreateDirectories (wallet_path)) {
2849
+ throw JSONRPCError (RPC_WALLET_ERROR, strprintf (" Failed to create database path '%s'. Database already exists." , wallet_path.string ()));
2850
+ }
2851
+
2852
+ auto wallet_file = wallet_path / " wallet.dat" ;
2853
+
2854
+ fs::copy_file (backup_file, wallet_file, fs::copy_option::fail_if_exists);
2855
+
2856
+ auto [wallet, warnings] = LoadWalletHelper (context, request.params [2 ], wallet_name);
2857
+
2858
+ UniValue obj (UniValue::VOBJ);
2859
+ obj.pushKV (" name" , wallet->GetName ());
2860
+ obj.pushKV (" warning" , Join (warnings, Untranslated (" \n " )).original );
2861
+
2862
+ return obj;
2863
+
2864
+ },
2865
+ };
2866
+ }
2867
+
2798
2868
static RPCHelpMan unloadwallet ()
2799
2869
{
2800
2870
return RPCHelpMan{" unloadwallet" ,
@@ -4639,6 +4709,7 @@ static const CRPCCommand commands[] =
4639
4709
{ " wallet" , &bumpfee, },
4640
4710
{ " wallet" , &psbtbumpfee, },
4641
4711
{ " wallet" , &createwallet, },
4712
+ { " wallet" , &restorewallet, },
4642
4713
{ " wallet" , &dumpprivkey, },
4643
4714
{ " wallet" , &dumpwallet, },
4644
4715
{ " wallet" , &encryptwallet, },
0 commit comments