Bitcoin Core 29.99.0
P2P Digital Currency
migrate.cpp
Go to the documentation of this file.
1// Copyright (c) 2024-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <compat/byteswap.h>
6#include <crypto/common.h>
7#include <logging.h>
8#include <streams.h>
9#include <util/translation.h>
10#include <wallet/migrate.h>
11
12#include <array>
13#include <cstddef>
14#include <optional>
15#include <stdexcept>
16#include <variant>
17#include <vector>
18
19namespace wallet {
20// Magic bytes in both endianness's
21constexpr uint32_t BTREE_MAGIC = 0x00053162; // If the file endianness matches our system, we see this magic
22constexpr uint32_t BTREE_MAGIC_OE = 0x62310500; // If the file endianness is the other one, we will see this magic
23
24// Subdatabase name
25static const std::vector<std::byte> SUBDATABASE_NAME = {std::byte{'m'}, std::byte{'a'}, std::byte{'i'}, std::byte{'n'}};
26
27enum class PageType : uint8_t {
28 /*
29 * BDB has several page types, most of which we do not use
30 * They are listed here for completeness, but commented out
31 * to avoid opening something unintended.
32 INVALID = 0, // Invalid page type
33 DUPLICATE = 1, // Duplicate. Deprecated and no longer used
34 HASH_UNSORTED = 2, // Hash pages. Deprecated.
35 RECNO_INTERNAL = 4, // Recno internal
36 RECNO_LEAF = 6, // Recno leaf
37 HASH_META = 8, // Hash metadata
38 QUEUE_META = 10, // Queue Metadata
39 QUEUE_DATA = 11, // Queue Data
40 DUPLICATE_LEAF = 12, // Off-page duplicate leaf
41 HASH_SORTED = 13, // Sorted hash page
42 */
43 BTREE_INTERNAL = 3, // BTree internal
44 BTREE_LEAF = 5, // BTree leaf
45 OVERFLOW_DATA = 7, // Overflow
46 BTREE_META = 9, // BTree metadata
47};
48
49enum class RecordType : uint8_t {
50 KEYDATA = 1,
51 // DUPLICATE = 2, Unused as our databases do not support duplicate records
52 OVERFLOW_DATA = 3,
53 DELETE = 0x80, // Indicate this record is deleted. This is OR'd with the real type.
54};
55
56enum class BTreeFlags : uint32_t {
57 /*
58 * BTree databases have feature flags, but we do not use them except for
59 * subdatabases. The unused flags are included for completeness, but commented out
60 * to avoid accidental use.
61 DUP = 1, // Duplicates
62 RECNO = 2, // Recno tree
63 RECNUM = 4, // BTree: Maintain record counts
64 FIXEDLEN = 8, // Recno: fixed length records
65 RENUMBER = 0x10, // Recno: renumber on insert/delete
66 DUPSORT = 0x40, // Duplicates are sorted
67 COMPRESS = 0x80, // Compressed
68 */
69 SUBDB = 0x20, // Subdatabases
70};
71
74{
75public:
76 uint32_t lsn_file; // Log Sequence Number file
77 uint32_t lsn_offset; // Log Sequence Number offset
78 uint32_t page_num; // Current page number
79 uint32_t magic; // Magic number
80 uint32_t version; // Version
81 uint32_t pagesize; // Page size
82 uint8_t encrypt_algo; // Encryption algorithm
83 PageType type; // Page type
84 uint8_t metaflags; // Meta-only flags
85 uint8_t unused1; // Unused
86 uint32_t free_list; // Free list page number
87 uint32_t last_page; // Page number of last page in db
88 uint32_t partitions; // Number of partitions
89 uint32_t key_count; // Cached key count
90 uint32_t record_count; // Cached record count
91 BTreeFlags flags; // Flags
92 std::array<std::byte, 20> uid; // 20 byte unique file ID
93 uint32_t unused2; // Unused
94 uint32_t minkey; // Minimum key
95 uint32_t re_len; // Recno: fixed length record length
96 uint32_t re_pad; // Recno: fixed length record pad
97 uint32_t root; // Root page number
98 char unused3[368]; // 92 * 4 bytes of unused space
99 uint32_t crypto_magic; // Crypto magic number
100 char trash[12]; // 3 * 4 bytes of trash space
101 unsigned char iv[20]; // Crypto IV
102 unsigned char chksum[16]; // Checksum
103
106
108 MetaPage() = delete;
109
110 template <typename Stream>
111 void Unserialize(Stream& s)
112 {
113 s >> lsn_file;
114 s >> lsn_offset;
115 s >> page_num;
116 s >> magic;
117 s >> version;
118 s >> pagesize;
119 s >> encrypt_algo;
120
122
123 uint8_t uint8_type;
124 s >> uint8_type;
125 type = static_cast<PageType>(uint8_type);
126
127 s >> metaflags;
128 s >> unused1;
129 s >> free_list;
130 s >> last_page;
131 s >> partitions;
132 s >> key_count;
133 s >> record_count;
134
135 uint32_t uint32_flags;
136 s >> uint32_flags;
137 if (other_endian) {
138 uint32_flags = internal_bswap_32(uint32_flags);
139 }
140 flags = static_cast<BTreeFlags>(uint32_flags);
141
142 s >> uid;
143 s >> unused2;
144 s >> minkey;
145 s >> re_len;
146 s >> re_pad;
147 s >> root;
148 s >> unused3;
149 s >> crypto_magic;
150 s >> trash;
151 s >> iv;
152 s >> chksum;
153
154 if (other_endian) {
172 }
173
174 // Page number must match
176 throw std::runtime_error("Meta page number mismatch");
177 }
178
179 // Check magic
180 if (magic != BTREE_MAGIC) {
181 throw std::runtime_error("Not a BDB file");
182 }
183
184 // Only version 9 is supported
185 if (version != 9) {
186 throw std::runtime_error("Unsupported BDB data file version number");
187 }
188
189 // Page size must be 512 <= pagesize <= 64k, and be a power of 2
190 if (pagesize < 512 || pagesize > 65536 || (pagesize & (pagesize - 1)) != 0) {
191 throw std::runtime_error("Bad page size");
192 }
193
194 // Page type must be the btree type
195 if (type != PageType::BTREE_META) {
196 throw std::runtime_error("Unexpected page type, should be 9 (BTree Metadata)");
197 }
198
199 // Only supported meta-flag is subdatabase
200 if (flags != BTreeFlags::SUBDB) {
201 throw std::runtime_error("Unexpected database flags, should only be 0x20 (subdatabases)");
202 }
203 }
204};
205
208{
209public:
210 uint16_t len; // Key/data item length
211 RecordType type; // Page type (BDB has this include a DELETE FLAG that we track separately)
212 bool deleted; // Whether the DELETE flag was set on type
213
214 static constexpr size_t SIZE = 3; // The record header is 3 bytes
215
217
219 RecordHeader() = delete;
220
221 template <typename Stream>
222 void Unserialize(Stream& s)
223 {
224 s >> len;
225
226 uint8_t uint8_type;
227 s >> uint8_type;
228 type = static_cast<RecordType>(uint8_type & ~static_cast<uint8_t>(RecordType::DELETE));
229 deleted = uint8_type & static_cast<uint8_t>(RecordType::DELETE);
230
231 if (other_endian) {
233 }
234 }
235};
236
239{
240public:
241 DataRecord(const RecordHeader& header) : m_header(header) {}
242 DataRecord() = delete;
243
245
246 std::vector<std::byte> data; // Variable length key/data item
247
248 template <typename Stream>
249 void Unserialize(Stream& s)
250 {
251 data.resize(m_header.len);
252 s.read(std::as_writable_bytes(std::span(data.data(), data.size())));
253 }
254};
255
258{
259public:
260 InternalRecord(const RecordHeader& header) : m_header(header) {}
261 InternalRecord() = delete;
262
264
265 uint8_t unused; // Padding, unused
266 uint32_t page_num; // Page number of referenced page
267 uint32_t records; // Subtree record count
268 std::vector<std::byte> data; // Variable length key item
269
270 static constexpr size_t FIXED_SIZE = 9; // Size of fixed data is 9 bytes
271
272 template <typename Stream>
273 void Unserialize(Stream& s)
274 {
275 s >> unused;
276 s >> page_num;
277 s >> records;
278
279 data.resize(m_header.len);
280 s.read(std::as_writable_bytes(std::span(data.data(), data.size())));
281
285 }
286 }
287};
288
294{
295public:
296 OverflowRecord(const RecordHeader& header) : m_header(header) {}
297 OverflowRecord() = delete;
298
300
301 uint8_t unused2; // Padding, unused
302 uint32_t page_number; // Page number where data begins
303 uint32_t item_len; // Total length of item
304
305 static constexpr size_t SIZE = 9; // Overflow record is always 9 bytes
306
307 template <typename Stream>
308 void Unserialize(Stream& s)
309 {
310 s >> unused2;
311 s >> page_number;
312 s >> item_len;
313
317 }
318 }
319};
320
323{
324public:
325 uint32_t lsn_file; // Log Sequence Number file
326 uint32_t lsn_offset; // Log Sequence Number offset
327 uint32_t page_num; // Current page number
328 uint32_t prev_page; // Previous page number
329 uint32_t next_page; // Next page number
330 uint16_t entries; // Number of items on the page
331 uint16_t hf_offset; // High free byte page offset
332 uint8_t level; // Btree page level
333 PageType type; // Page type
334
335 static constexpr int64_t SIZE = 26; // The header is 26 bytes
336
339
341 PageHeader() = delete;
342
343 template <typename Stream>
344 void Unserialize(Stream& s)
345 {
346 s >> lsn_file;
347 s >> lsn_offset;
348 s >> page_num;
349 s >> prev_page;
350 s >> next_page;
351 s >> entries;
352 s >> hf_offset;
353 s >> level;
354
355 uint8_t uint8_type;
356 s >> uint8_type;
357 type = static_cast<PageType>(uint8_type);
358
359 if (other_endian) {
367 }
368
370 throw std::runtime_error("Page number mismatch");
371 }
372 if ((type != PageType::OVERFLOW_DATA && level < 1) || (type == PageType::OVERFLOW_DATA && level != 0)) {
373 throw std::runtime_error("Bad btree level");
374 }
375 }
376};
377
380{
381public:
382 RecordsPage(const PageHeader& header) : m_header(header) {}
383 RecordsPage() = delete;
384
386
387 std::vector<uint16_t> indexes;
388 std::vector<std::variant<DataRecord, OverflowRecord>> records;
389
390 template <typename Stream>
391 void Unserialize(Stream& s)
392 {
393 // Current position within the page
394 int64_t pos = PageHeader::SIZE;
395
396 // Get the items
397 for (uint32_t i = 0; i < m_header.entries; ++i) {
398 // Get the index
399 uint16_t index;
400 s >> index;
402 index = internal_bswap_16(index);
403 }
404 indexes.push_back(index);
405 pos += sizeof(uint16_t);
406
407 // Go to the offset from the index
408 int64_t to_jump = index - pos;
409 if (to_jump < 0) {
410 throw std::runtime_error("Data record position not in page");
411 }
412 s.ignore(to_jump);
413
414 // Read the record
416 s >> rec_hdr;
417 to_jump += RecordHeader::SIZE;
418
419 switch (rec_hdr.type) {
420 case RecordType::KEYDATA: {
421 DataRecord record(rec_hdr);
422 s >> record;
423 records.emplace_back(record);
424 to_jump += rec_hdr.len;
425 break;
426 }
428 OverflowRecord record(rec_hdr);
429 s >> record;
430 records.emplace_back(record);
431 to_jump += OverflowRecord::SIZE;
432 break;
433 }
434 default:
435 throw std::runtime_error("Unknown record type in records page");
436 }
437
438 // Go back to the indexes
439 s.seek(-to_jump, SEEK_CUR);
440 }
441 }
442};
443
446{
447public:
448 OverflowPage(const PageHeader& header) : m_header(header) {}
449 OverflowPage() = delete;
450
452
453 // BDB overloads some page fields to store overflow page data
454 // hf_offset contains the length of the overflow data stored on this page
455 // entries contains a reference count for references to this item
456
457 // The overflow data itself. Begins immediately following header
458 std::vector<std::byte> data;
459
460 template <typename Stream>
461 void Unserialize(Stream& s)
462 {
463 data.resize(m_header.hf_offset);
464 s.read(std::as_writable_bytes(std::span(data.data(), data.size())));
465 }
466};
467
470{
471public:
472 InternalPage(const PageHeader& header) : m_header(header) {}
473 InternalPage() = delete;
474
476
477 std::vector<uint16_t> indexes;
478 std::vector<InternalRecord> records;
479
480 template <typename Stream>
481 void Unserialize(Stream& s)
482 {
483 // Current position within the page
484 int64_t pos = PageHeader::SIZE;
485
486 // Get the items
487 for (uint32_t i = 0; i < m_header.entries; ++i) {
488 // Get the index
489 uint16_t index;
490 s >> index;
492 index = internal_bswap_16(index);
493 }
494 indexes.push_back(index);
495 pos += sizeof(uint16_t);
496
497 // Go to the offset from the index
498 int64_t to_jump = index - pos;
499 if (to_jump < 0) {
500 throw std::runtime_error("Internal record position not in page");
501 }
502 s.ignore(to_jump);
503
504 // Read the record
506 s >> rec_hdr;
507 to_jump += RecordHeader::SIZE;
508
509 if (rec_hdr.type != RecordType::KEYDATA) {
510 throw std::runtime_error("Unknown record type in internal page");
511 }
512 InternalRecord record(rec_hdr);
513 s >> record;
514 records.emplace_back(record);
515 to_jump += InternalRecord::FIXED_SIZE + rec_hdr.len;
516
517 // Go back to the indexes
518 s.seek(-to_jump, SEEK_CUR);
519 }
520 }
521};
522
523static void SeekToPage(AutoFile& s, uint32_t page_num, uint32_t page_size)
524{
525 int64_t pos = int64_t{page_num} * page_size;
526 s.seek(pos, SEEK_SET);
527}
528
530{
531 // Open the file
532 FILE* file = fsbridge::fopen(m_filepath, "rb");
533 AutoFile db_file(file);
534 if (db_file.IsNull()) {
535 throw std::runtime_error("BerkeleyRODatabase: Failed to open database file");
536 }
537
538 uint32_t page_size = 4096; // Default page size
539
540 // Read the outer metapage
541 // Expected page number is 0
542 MetaPage outer_meta(0);
543 db_file >> outer_meta;
544 page_size = outer_meta.pagesize;
545
546 // Verify the size of the file is a multiple of the page size
547 db_file.seek(0, SEEK_END);
548 int64_t size = db_file.tell();
549
550 // Since BDB stores everything in a page, the file size should be a multiple of the page size;
551 // However, BDB doesn't actually check that this is the case, and enforcing this check results
552 // in us rejecting a database that BDB would not, so this check needs to be excluded.
553 // This is left commented out as a reminder to not accidentally implement this in the future.
554 // if (size % page_size != 0) {
555 // throw std::runtime_error("File size is not a multiple of page size");
556 // }
557
558 // Check the last page number
559 uint32_t expected_last_page{uint32_t((size / page_size) - 1)};
560 if (outer_meta.last_page != expected_last_page) {
561 throw std::runtime_error("Last page number could not fit in file");
562 }
563
564 // Make sure encryption is disabled
565 if (outer_meta.encrypt_algo != 0) {
566 throw std::runtime_error("BDB builtin encryption is not supported");
567 }
568
569 // Check all Log Sequence Numbers (LSN) point to file 0 and offset 1 which indicates that the LSNs were
570 // reset and that the log files are not necessary to get all of the data in the database.
571 for (uint32_t i = 0; i < outer_meta.last_page; ++i) {
572 // The LSN is composed of 2 32-bit ints, the first is a file id, the second an offset
573 // It will always be the first 8 bytes of a page, so we deserialize it directly for every page
574 uint32_t file;
575 uint32_t offset;
576 SeekToPage(db_file, i, page_size);
577 db_file >> file >> offset;
578 if (outer_meta.other_endian) {
579 file = internal_bswap_32(file);
580 offset = internal_bswap_32(offset);
581 }
582 if (file != 0 || offset != 1) {
583 throw std::runtime_error("LSNs are not reset, this database is not completely flushed. Please reopen then close the database with a version that has BDB support");
584 }
585 }
586
587 // Read the root page
588 SeekToPage(db_file, outer_meta.root, page_size);
589 PageHeader header(outer_meta.root, outer_meta.other_endian);
590 db_file >> header;
591 if (header.type != PageType::BTREE_LEAF) {
592 throw std::runtime_error("Unexpected outer database root page type");
593 }
594 if (header.entries != 2) {
595 throw std::runtime_error("Unexpected number of entries in outer database root page");
596 }
597 RecordsPage page(header);
598 db_file >> page;
599
600 // First record should be the string "main"
601 if (!std::holds_alternative<DataRecord>(page.records.at(0)) || std::get<DataRecord>(page.records.at(0)).data != SUBDATABASE_NAME) {
602 throw std::runtime_error("Subdatabase has an unexpected name");
603 }
604 // Check length of page number for subdatabase location
605 if (!std::holds_alternative<DataRecord>(page.records.at(1)) || std::get<DataRecord>(page.records.at(1)).m_header.len != 4) {
606 throw std::runtime_error("Subdatabase page number has unexpected length");
607 }
608
609 // Read subdatabase page number
610 // It is written as a big endian 32 bit number
611 uint32_t main_db_page = ReadBE32(std::get<DataRecord>(page.records.at(1)).data.data());
612
613 // The main database is in a page that doesn't exist
614 if (main_db_page > outer_meta.last_page) {
615 throw std::runtime_error("Page number is greater than database last page");
616 }
617
618 // Read the inner metapage
619 SeekToPage(db_file, main_db_page, page_size);
620 MetaPage inner_meta(main_db_page);
621 db_file >> inner_meta;
622
623 if (inner_meta.pagesize != page_size) {
624 throw std::runtime_error("Unexpected page size");
625 }
626
627 if (inner_meta.last_page > outer_meta.last_page) {
628 throw std::runtime_error("Subdatabase last page is greater than database last page");
629 }
630
631 // Make sure encryption is disabled
632 if (inner_meta.encrypt_algo != 0) {
633 throw std::runtime_error("BDB builtin encryption is not supported");
634 }
635
636 // Do a DFS through the BTree, starting at root
637 std::vector<uint32_t> pages{inner_meta.root};
638 while (pages.size() > 0) {
639 uint32_t curr_page = pages.back();
640 // It turns out BDB completely ignores this last_page field and doesn't actually update it to the correct
641 // last page. While we should be checking this, we can't.
642 // This is left commented out as a reminder to not accidentally implement this in the future.
643 // if (curr_page > inner_meta.last_page) {
644 // throw std::runtime_error("Page number is greater than subdatabase last page");
645 // }
646 pages.pop_back();
647 SeekToPage(db_file, curr_page, page_size);
648 PageHeader header(curr_page, inner_meta.other_endian);
649 db_file >> header;
650 switch (header.type) {
652 InternalPage int_page(header);
653 db_file >> int_page;
654 for (const InternalRecord& rec : int_page.records) {
655 if (rec.m_header.deleted) continue;
656 pages.push_back(rec.page_num);
657 }
658 break;
659 }
661 RecordsPage rec_page(header);
662 db_file >> rec_page;
663 if (rec_page.records.size() % 2 != 0) {
664 // BDB stores key value pairs in consecutive records, thus an odd number of records is unexpected
665 throw std::runtime_error("Records page has odd number of records");
666 }
667 bool is_key = true;
668 std::vector<std::byte> key;
669 for (const std::variant<DataRecord, OverflowRecord>& rec : rec_page.records) {
670 std::vector<std::byte> data;
671 if (const DataRecord* drec = std::get_if<DataRecord>(&rec)) {
672 if (drec->m_header.deleted) continue;
673 data = drec->data;
674 } else if (const OverflowRecord* orec = std::get_if<OverflowRecord>(&rec)) {
675 if (orec->m_header.deleted) continue;
676 uint32_t next_page = orec->page_number;
677 while (next_page != 0) {
678 SeekToPage(db_file, next_page, page_size);
679 PageHeader opage_header(next_page, inner_meta.other_endian);
680 db_file >> opage_header;
681 if (opage_header.type != PageType::OVERFLOW_DATA) {
682 throw std::runtime_error("Bad overflow record page type");
683 }
684 OverflowPage opage(opage_header);
685 db_file >> opage;
686 data.insert(data.end(), opage.data.begin(), opage.data.end());
687 next_page = opage_header.next_page;
688 }
689 }
690
691 if (is_key) {
692 key = data;
693 } else {
694 m_records.emplace(SerializeData{key.begin(), key.end()}, SerializeData{data.begin(), data.end()});
695 key.clear();
696 }
697 is_key = !is_key;
698 }
699 break;
700 }
701 default:
702 throw std::runtime_error("Unexpected page type");
703 }
704 }
705}
706
707std::unique_ptr<DatabaseBatch> BerkeleyRODatabase::MakeBatch()
708{
709 return std::make_unique<BerkeleyROBatch>(*this);
710}
711
712bool BerkeleyRODatabase::Backup(const std::string& dest) const
713{
714 fs::path src(m_filepath);
715 fs::path dst(fs::PathFromString(dest));
716
717 if (fs::is_directory(dst)) {
718 dst = BDBDataFile(dst);
719 }
720 try {
721 if (fs::exists(dst) && fs::equivalent(src, dst)) {
722 LogPrintf("cannot backup to wallet source file %s\n", fs::PathToString(dst));
723 return false;
724 }
725
726 fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
727 LogPrintf("copied %s to %s\n", fs::PathToString(m_filepath), fs::PathToString(dst));
728 return true;
729 } catch (const fs::filesystem_error& e) {
730 LogWarning("error copying %s to %s - %s\n", fs::PathToString(m_filepath), fs::PathToString(dst), e.code().message());
731 return false;
732 }
733}
734
736{
737 SerializeData key_data{key.begin(), key.end()};
738 const auto it{m_database.m_records.find(key_data)};
739 if (it == m_database.m_records.end()) {
740 return false;
741 }
742 auto val = it->second;
743 value.clear();
744 value.write(std::span(val));
745 return true;
746}
747
749{
750 SerializeData key_data{key.begin(), key.end()};
751 return m_database.m_records.count(key_data) > 0;
752}
753
754BerkeleyROCursor::BerkeleyROCursor(const BerkeleyRODatabase& database, std::span<const std::byte> prefix)
755 : m_database(database)
756{
757 std::tie(m_cursor, m_cursor_end) = m_database.m_records.equal_range(BytePrefix{prefix});
758}
759
761{
762 if (m_cursor == m_cursor_end) {
764 }
765 ssKey.write(std::span(m_cursor->first));
766 ssValue.write(std::span(m_cursor->second));
767 m_cursor++;
769}
770
771std::unique_ptr<DatabaseCursor> BerkeleyROBatch::GetNewPrefixCursor(std::span<const std::byte> prefix)
772{
773 return std::make_unique<BerkeleyROCursor>(m_database, prefix);
774}
775
776std::unique_ptr<BerkeleyRODatabase> MakeBerkeleyRODatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
777{
778 fs::path data_file = BDBDataFile(path);
779 try {
780 std::unique_ptr<BerkeleyRODatabase> db = std::make_unique<BerkeleyRODatabase>(data_file);
782 return db;
783 } catch (const std::runtime_error& e) {
784 error.original = e.what();
786 return nullptr;
787 }
788}
789} // namespace wallet
BSWAP_CONSTEXPR uint32_t internal_bswap_32(uint32_t x)
Definition: byteswap.h:53
BSWAP_CONSTEXPR uint16_t internal_bswap_16(uint16_t x)
Definition: byteswap.h:44
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:392
void seek(int64_t offset, int origin)
Wrapper around fseek().
Definition: streams.cpp:33
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:428
int64_t tell()
Find position within the file.
Definition: streams.cpp:54
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
void write(std::span< const value_type > src)
Definition: streams.h:251
void clear()
Definition: streams.h:187
bool ReadKey(DataStream &&key, DataStream &value) override
Definition: migrate.cpp:735
std::unique_ptr< DatabaseCursor > GetNewPrefixCursor(std::span< const std::byte > prefix) override
Definition: migrate.cpp:771
const BerkeleyRODatabase & m_database
Definition: migrate.h:78
bool HasKey(DataStream &&key) override
Definition: migrate.cpp:748
BerkeleyROData::const_iterator m_cursor_end
Definition: migrate.h:65
BerkeleyROData::const_iterator m_cursor
Definition: migrate.h:64
const BerkeleyRODatabase & m_database
Definition: migrate.h:63
BerkeleyROCursor(const BerkeleyRODatabase &database, std::span< const std::byte > prefix={})
Definition: migrate.cpp:754
Status Next(DataStream &key, DataStream &value) override
Definition: migrate.cpp:760
A class representing a BerkeleyDB file from which we can only read records.
Definition: migrate.h:21
BerkeleyROData m_records
Definition: migrate.h:33
std::unique_ptr< DatabaseBatch > MakeBatch() override
Make a DatabaseBatch connected to this database.
Definition: migrate.cpp:707
void Open() override
Open the database if it is not already opened.
Definition: migrate.cpp:529
const fs::path m_filepath
Definition: migrate.h:23
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
Definition: migrate.cpp:712
Class for data in the record directly.
Definition: migrate.cpp:239
RecordHeader m_header
Definition: migrate.cpp:244
void Unserialize(Stream &s)
Definition: migrate.cpp:249
std::vector< std::byte > data
Definition: migrate.cpp:246
DataRecord(const RecordHeader &header)
Definition: migrate.cpp:241
A page of records in the database.
Definition: migrate.cpp:470
InternalPage(const PageHeader &header)
Definition: migrate.cpp:472
PageHeader m_header
Definition: migrate.cpp:475
void Unserialize(Stream &s)
Definition: migrate.cpp:481
std::vector< uint16_t > indexes
Definition: migrate.cpp:477
std::vector< InternalRecord > records
Definition: migrate.cpp:478
Class for records representing internal nodes of the BTree.
Definition: migrate.cpp:258
std::vector< std::byte > data
Definition: migrate.cpp:268
static constexpr size_t FIXED_SIZE
Definition: migrate.cpp:270
InternalRecord(const RecordHeader &header)
Definition: migrate.cpp:260
void Unserialize(Stream &s)
Definition: migrate.cpp:273
RecordHeader m_header
Definition: migrate.cpp:263
Berkeley DB BTree metadata page layout.
Definition: migrate.cpp:74
uint32_t version
Definition: migrate.cpp:80
uint32_t pagesize
Definition: migrate.cpp:81
uint8_t encrypt_algo
Definition: migrate.cpp:82
uint8_t metaflags
Definition: migrate.cpp:84
uint32_t re_pad
Definition: migrate.cpp:96
char unused3[368]
Definition: migrate.cpp:98
uint32_t re_len
Definition: migrate.cpp:95
uint32_t crypto_magic
Definition: migrate.cpp:99
void Unserialize(Stream &s)
Definition: migrate.cpp:111
uint8_t unused1
Definition: migrate.cpp:85
PageType type
Definition: migrate.cpp:83
uint32_t unused2
Definition: migrate.cpp:93
uint32_t free_list
Definition: migrate.cpp:86
uint32_t partitions
Definition: migrate.cpp:88
char trash[12]
Definition: migrate.cpp:100
uint32_t page_num
Definition: migrate.cpp:78
unsigned char iv[20]
Definition: migrate.cpp:101
unsigned char chksum[16]
Definition: migrate.cpp:102
uint32_t minkey
Definition: migrate.cpp:94
MetaPage(uint32_t expected_page_num)
Definition: migrate.cpp:107
uint32_t expected_page_num
Definition: migrate.cpp:105
uint32_t magic
Definition: migrate.cpp:79
uint32_t lsn_offset
Definition: migrate.cpp:77
BTreeFlags flags
Definition: migrate.cpp:91
uint32_t root
Definition: migrate.cpp:97
uint32_t record_count
Definition: migrate.cpp:90
uint32_t last_page
Definition: migrate.cpp:87
uint32_t lsn_file
Definition: migrate.cpp:76
uint32_t key_count
Definition: migrate.cpp:89
std::array< std::byte, 20 > uid
Definition: migrate.cpp:92
A page containing overflow data.
Definition: migrate.cpp:446
std::vector< std::byte > data
Definition: migrate.cpp:458
void Unserialize(Stream &s)
Definition: migrate.cpp:461
OverflowPage(const PageHeader &header)
Definition: migrate.cpp:448
PageHeader m_header
Definition: migrate.cpp:451
Class for records representing overflow records of the BTree.
Definition: migrate.cpp:294
OverflowRecord(const RecordHeader &header)
Definition: migrate.cpp:296
RecordHeader m_header
Definition: migrate.cpp:299
void Unserialize(Stream &s)
Definition: migrate.cpp:308
static constexpr size_t SIZE
Definition: migrate.cpp:305
A generic data page in the database.
Definition: migrate.cpp:323
uint32_t prev_page
Definition: migrate.cpp:328
static constexpr int64_t SIZE
Definition: migrate.cpp:335
uint32_t next_page
Definition: migrate.cpp:329
uint32_t lsn_offset
Definition: migrate.cpp:326
uint16_t entries
Definition: migrate.cpp:330
void Unserialize(Stream &s)
Definition: migrate.cpp:344
uint32_t page_num
Definition: migrate.cpp:327
uint16_t hf_offset
Definition: migrate.cpp:331
uint32_t lsn_file
Definition: migrate.cpp:325
PageHeader(uint32_t page_num, bool other_endian)
Definition: migrate.cpp:340
uint32_t expected_page_num
Definition: migrate.cpp:337
General class for records in a BDB BTree database.
Definition: migrate.cpp:208
RecordHeader(bool other_endian)
Definition: migrate.cpp:218
void Unserialize(Stream &s)
Definition: migrate.cpp:222
static constexpr size_t SIZE
Definition: migrate.cpp:214
A page of records in the database.
Definition: migrate.cpp:380
std::vector< std::variant< DataRecord, OverflowRecord > > records
Definition: migrate.cpp:388
void Unserialize(Stream &s)
Definition: migrate.cpp:391
RecordsPage(const PageHeader &header)
Definition: migrate.cpp:382
PageHeader m_header
Definition: migrate.cpp:385
std::vector< uint16_t > indexes
Definition: migrate.cpp:387
uint32_t ReadBE32(const B *ptr)
Definition: common.h:72
static bool exists(const path &p)
Definition: fs.h:89
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:128
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:174
#define LogWarning(...)
Definition: logging.h:262
#define LogPrintf(...)
Definition: logging.h:266
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
BTreeFlags
Definition: migrate.cpp:56
static const std::vector< std::byte > SUBDATABASE_NAME
Definition: migrate.cpp:25
constexpr uint32_t BTREE_MAGIC
Definition: migrate.cpp:21
PageType
Definition: migrate.cpp:27
RecordType
Definition: migrate.cpp:49
fs::path BDBDataFile(const fs::path &wallet_path)
Definition: db.cpp:76
constexpr uint32_t BTREE_MAGIC_OE
Definition: migrate.cpp:22
static void SeekToPage(AutoFile &s, uint32_t page_num, uint32_t page_size)
Definition: migrate.cpp:523
std::unique_ptr< BerkeleyRODatabase > MakeBerkeleyRODatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Return object giving access to Berkeley Read Only database at specified path.
Definition: migrate.cpp:776
DatabaseStatus
Definition: db.h:183
const char * prefix
Definition: rest.cpp:1009
Bilingual messages:
Definition: translation.h:24
std::string original
Definition: translation.h:25
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
Definition: zeroafterfree.h:49