upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/main_gui.cpp
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-07-30 12:06:08 -0300
committerGitHub <noreply@github.com>2026-07-30 12:06:08 -0300
commitb539d776bd86df9224d97048f26f33d2750d1c92 (patch)
tree4a246ca7c8680e0b2d32613e388116a5d39247cf /src/main_gui.cpp
parentdaac46893448e49a21244d9646acf0ec47518537 (diff)
wallet: export and import keys as text (#49)
The last door out. Everything else assumes Berkeley DB will cooperate. When it will not -- a build that cannot read the file, a truncation, an environment past recovering -- the keys are usually still perfectly intact and were unreachable anyway. #40 is one person's account of exactly that, and #46 only rescues the cases where BDB still opens the file at all. bitflash -dumpwallet=keys.txt bitflash -importwallet=keys.txt One key per line with its address and label. No database, no environment, no version coupling: anything that can read a line can recover from it. The format is the DER private key in hex, which round-trips exactly through SetPrivKey. Not interchangeable with other wallets -- worth having eventually, but a WIF encoder I got subtly wrong would be worse than no encoder at all, and this file exists for the case where nothing else works. Care taken, because the failure modes here cost money: - Refuses to overwrite an existing file. A mistyped path must not eat the only copy of something irreplaceable. - Written owner-only on POSIX, before any key reaches it. Windows inherits the folder's ACL; the README says so rather than pretending otherwise. - Newlines in labels are flattened, so a label cannot forge an extra entry on read-back. - Import skips keys already present, so running it twice does nothing, and one unreadable line is reported and stepped over instead of costing the reader every other key in the file. Verified on Linux and Windows: a key exported from one wallet imports into a different one and its address then appears there; re-importing adds nothing; a corrupted line is skipped while the rest still load; the dump is 0600 and refuses to overwrite. This does not solve #47. Keys still are not derived from a seed, so a dump is as much a snapshot as any other backup. What it does is make the keys reachable no matter what state the database is in.
Diffstat (limited to 'src/main_gui.cpp')
-rw-r--r--src/main_gui.cpp33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
index 976cd42..2484592 100644
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -70,6 +70,9 @@ static void PrintUsage()
70 printf("Wallet:\n"); 70 printf("Wallet:\n");
71 printf(" /backupwallet=FILE (write a wallet.dat that opens on its own,\n"); 71 printf(" /backupwallet=FILE (write a wallet.dat that opens on its own,\n");
72 printf(" then exit; run it again after new addresses)\n"); 72 printf(" then exit; run it again after new addresses)\n");
73 printf(" /dumpwallet=FILE (export private keys as text -- readable by\n");
74 printf(" anyone, so guard it like cash)\n");
75 printf(" /importwallet=FILE (load keys from such a file back in)\n");
73 printf("\n"); 76 printf("\n");
74 printf("Each option also accepts '-' instead of '/'.\n"); 77 printf("Each option also accepts '-' instead of '/'.\n");
75} 78}
@@ -245,6 +248,36 @@ int main(int argc, char* argv[])
245 return fOk ? 0 : 1; 248 return fOk ? 0 : 1;
246 } 249 }
247 250
251 string strDump = argval2(argc, argv, "/dumpwallet", "-dumpwallet");
252 if (!strDump.empty())
253 {
254 bool fOk = DumpWallet(strDump);
255 if (fOk)
256 {
257 printf("Wrote %s\n", strDump.c_str());
258 printf("It holds your private keys as readable text. Anyone with the file "
259 "can spend these coins -- keep it off shared storage and delete it "
260 "once you have it somewhere safe.\n");
261 }
262 else
263 fprintf(stderr, "Export failed -- nothing was written.\n");
264 DBFlush(true);
265 return fOk ? 0 : 1;
266 }
267
268 string strImport = argval2(argc, argv, "/importwallet", "-importwallet");
269 if (!strImport.empty())
270 {
271 int nAdded = 0, nSkipped = 0;
272 bool fOk = ImportWallet(strImport, nAdded, nSkipped);
273 if (fOk)
274 printf("Imported %d key(s); %d were already here.\n", nAdded, nSkipped);
275 else
276 fprintf(stderr, "Import failed.\n");
277 DBFlush(true);
278 return fOk ? 0 : 1;
279 }
280
248 ReacceptWalletTransactions(); 281 ReacceptWalletTransactions();
249 282
250 if (!StartNode(strErrors)) { fprintf(stderr,"StartNode: %s\n",strErrors.c_str()); return 1; } 283 if (!StartNode(strErrors)) { fprintf(stderr,"StartNode: %s\n",strErrors.c_str()); return 1; }