Bitcoin Core  31.0.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 
19 namespace wallet {
20 // Magic bytes in both endianness's
21 constexpr uint32_t BTREE_MAGIC = 0x00053162; // If the file endianness matches our system, we see this magic
22 constexpr uint32_t BTREE_MAGIC_OE = 0x62310500; // If the file endianness is the other one, we will see this magic
23 
24 // Subdatabase name
25 static const std::vector<std::byte> SUBDATABASE_NAME = {std::byte{'m'}, std::byte{'a'}, std::byte{'i'}, std::byte{'n'}};
26 
27 enum 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 
49 enum 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_FLAG = 0x80, // Indicate this record is deleted. This is OR'd with the real type.
54 };
55 
56 enum 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 
73 class MetaPage
74 {
75 public:
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
175  if (page_num != expected_page_num) {
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 {
209 public:
210  uint16_t len; // Key/data item length
211  RecordType type; // Page type (BDB has this; includes 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_FLAG));
229  deleted = uint8_type & static_cast<uint8_t>(RecordType::DELETE_FLAG);
230 
231  if (other_endian) {
233  }
234  }
235 };
236 
239 {
240 public:
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 {
259 public:
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 
282  if (m_header.other_endian) {
285  }
286  }
287 };
288 
294 {
295 public:
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 
314  if (m_header.other_endian) {
317  }
318  }
319 };
320 
323 {
324 public:
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 
369  if (expected_page_num != page_num) {
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 {
381 public:
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;
401  if (m_header.other_endian) {
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 {
447 public:
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 {
471 public:
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;
491  if (m_header.other_endian) {
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 
523 static 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  const int64_t size{db_file.size()};
548 
549  // Since BDB stores everything in a page, the file size should be a multiple of the page size;
550  // However, BDB doesn't actually check that this is the case, and enforcing this check results
551  // in us rejecting a database that BDB would not, so this check needs to be excluded.
552  // This is left commented out as a reminder to not accidentally implement this in the future.
553  // if (size % page_size != 0) {
554  // throw std::runtime_error("File size is not a multiple of page size");
555  // }
556 
557  // Check the last page number
558  uint32_t expected_last_page{uint32_t((size / page_size) - 1)};
559  if (outer_meta.last_page != expected_last_page) {
560  throw std::runtime_error("Last page number could not fit in file");
561  }
562 
563  // Make sure encryption is disabled
564  if (outer_meta.encrypt_algo != 0) {
565  throw std::runtime_error("BDB builtin encryption is not supported");
566  }
567 
568  // Check all Log Sequence Numbers (LSN) point to file 0 and offset 1 which indicates that the LSNs were
569  // reset and that the log files are not necessary to get all of the data in the database.
570  for (uint32_t i = 0; i < outer_meta.last_page; ++i) {
571  // The LSN is composed of 2 32-bit ints, the first is a file id, the second an offset
572  // It will always be the first 8 bytes of a page, so we deserialize it directly for every page
573  uint32_t file;
574  uint32_t offset;
575  SeekToPage(db_file, i, page_size);
576  db_file >> file >> offset;
577  if (outer_meta.other_endian) {
578  file = internal_bswap_32(file);
579  offset = internal_bswap_32(offset);
580  }
581  if (file != 0 || offset != 1) {
582  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");
583  }
584  }
585 
586  // Read the root page
587  SeekToPage(db_file, outer_meta.root, page_size);
588  PageHeader header(outer_meta.root, outer_meta.other_endian);
589  db_file >> header;
590  if (header.type != PageType::BTREE_LEAF) {
591  throw std::runtime_error("Unexpected outer database root page type");
592  }
593  if (header.entries != 2) {
594  throw std::runtime_error("Unexpected number of entries in outer database root page");
595  }
596  RecordsPage page(header);
597  db_file >> page;
598 
599  // First record should be the string "main"
600  if (!std::holds_alternative<DataRecord>(page.records.at(0)) || std::get<DataRecord>(page.records.at(0)).data != SUBDATABASE_NAME) {
601  throw std::runtime_error("Subdatabase has an unexpected name");
602  }
603  // Check length of page number for subdatabase location
604  if (!std::holds_alternative<DataRecord>(page.records.at(1)) || std::get<DataRecord>(page.records.at(1)).m_header.len != 4) {
605  throw std::runtime_error("Subdatabase page number has unexpected length");
606  }
607 
608  // Read subdatabase page number
609  // It is written as a big endian 32 bit number
610  uint32_t main_db_page = ReadBE32(std::get<DataRecord>(page.records.at(1)).data.data());
611 
612  // The main database is in a page that doesn't exist
613  if (main_db_page > outer_meta.last_page) {
614  throw std::runtime_error("Page number is greater than database last page");
615  }
616 
617  // Read the inner metapage
618  SeekToPage(db_file, main_db_page, page_size);
619  MetaPage inner_meta(main_db_page);
620  db_file >> inner_meta;
621 
622  if (inner_meta.pagesize != page_size) {
623  throw std::runtime_error("Unexpected page size");
624  }
625 
626  if (inner_meta.last_page > outer_meta.last_page) {
627  throw std::runtime_error("Subdatabase last page is greater than database last page");
628  }
629 
630  // Make sure encryption is disabled
631  if (inner_meta.encrypt_algo != 0) {
632  throw std::runtime_error("BDB builtin encryption is not supported");
633  }
634 
635  // Do a DFS through the BTree, starting at root
636  std::vector<uint32_t> pages{inner_meta.root};
637  while (pages.size() > 0) {
638  uint32_t curr_page = pages.back();
639  // It turns out BDB completely ignores this last_page field and doesn't actually update it to the correct
640  // last page. While we should be checking this, we can't.
641  // This is left commented out as a reminder to not accidentally implement this in the future.
642  // if (curr_page > inner_meta.last_page) {
643  // throw std::runtime_error("Page number is greater than subdatabase last page");
644  // }
645  pages.pop_back();
646  SeekToPage(db_file, curr_page, page_size);
647  PageHeader header(curr_page, inner_meta.other_endian);
648  db_file >> header;
649  switch (header.type) {
651  InternalPage int_page(header);
652  db_file >> int_page;
653  for (const InternalRecord& rec : int_page.records) {
654  if (rec.m_header.deleted) continue;
655  pages.push_back(rec.page_num);
656  }
657  break;
658  }
659  case PageType::BTREE_LEAF: {
660  RecordsPage rec_page(header);
661  db_file >> rec_page;
662  if (rec_page.records.size() % 2 != 0) {
663  // BDB stores key value pairs in consecutive records, thus an odd number of records is unexpected
664  throw std::runtime_error("Records page has odd number of records");
665  }
666  bool is_key = true;
667  std::vector<std::byte> key;
668  for (const std::variant<DataRecord, OverflowRecord>& rec : rec_page.records) {
669  std::vector<std::byte> data;
670  if (const DataRecord* drec = std::get_if<DataRecord>(&rec)) {
671  if (drec->m_header.deleted) continue;
672  data = drec->data;
673  } else if (const OverflowRecord* orec = std::get_if<OverflowRecord>(&rec)) {
674  if (orec->m_header.deleted) continue;
675  uint32_t next_page = orec->page_number;
676  while (next_page != 0) {
677  SeekToPage(db_file, next_page, page_size);
678  PageHeader opage_header(next_page, inner_meta.other_endian);
679  db_file >> opage_header;
680  if (opage_header.type != PageType::OVERFLOW_DATA) {
681  throw std::runtime_error("Bad overflow record page type");
682  }
683  OverflowPage opage(opage_header);
684  db_file >> opage;
685  data.insert(data.end(), opage.data.begin(), opage.data.end());
686  next_page = opage_header.next_page;
687  }
688  }
689 
690  if (is_key) {
691  key = data;
692  } else {
693  m_records.emplace(SerializeData{key.begin(), key.end()}, SerializeData{data.begin(), data.end()});
694  key.clear();
695  }
696  is_key = !is_key;
697  }
698  break;
699  }
700  default:
701  throw std::runtime_error("Unexpected page type");
702  }
703  }
704 }
705 
706 std::unique_ptr<DatabaseBatch> BerkeleyRODatabase::MakeBatch()
707 {
708  return std::make_unique<BerkeleyROBatch>(*this);
709 }
710 
711 bool BerkeleyRODatabase::Backup(const std::string& dest) const
712 {
713  fs::path src(m_filepath);
714  fs::path dst(fs::PathFromString(dest));
715 
716  if (fs::is_directory(dst)) {
717  dst = BDBDataFile(dst);
718  }
719  try {
720  if (fs::exists(dst) && fs::equivalent(src, dst)) {
721  LogWarning("cannot backup to wallet source file %s", fs::PathToString(dst));
722  return false;
723  }
724 
725  fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
726  LogInfo("copied %s to %s\n", fs::PathToString(m_filepath), fs::PathToString(dst));
727  return true;
728  } catch (const fs::filesystem_error& e) {
729  LogWarning("error copying %s to %s - %s\n", fs::PathToString(m_filepath), fs::PathToString(dst), e.code().message());
730  return false;
731  }
732 }
733 
735 {
736  SerializeData key_data{key.begin(), key.end()};
737  const auto it{m_database.m_records.find(key_data)};
738  if (it == m_database.m_records.end()) {
739  return false;
740  }
741  auto val = it->second;
742  value.clear();
743  value.write(std::span(val));
744  return true;
745 }
746 
748 {
749  SerializeData key_data{key.begin(), key.end()};
750  return m_database.m_records.contains(key_data);
751 }
752 
753 BerkeleyROCursor::BerkeleyROCursor(const BerkeleyRODatabase& database, std::span<const std::byte> prefix)
754  : m_database(database)
755 {
756  std::tie(m_cursor, m_cursor_end) = m_database.m_records.equal_range(BytePrefix{prefix});
757 }
758 
760 {
761  if (m_cursor == m_cursor_end) {
763  }
764  ssKey.write(std::span(m_cursor->first));
765  ssValue.write(std::span(m_cursor->second));
766  m_cursor++;
768 }
769 
770 std::unique_ptr<DatabaseCursor> BerkeleyROBatch::GetNewPrefixCursor(std::span<const std::byte> prefix)
771 {
772  return std::make_unique<BerkeleyROCursor>(m_database, prefix);
773 }
774 
775 std::unique_ptr<BerkeleyRODatabase> MakeBerkeleyRODatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
776 {
777  fs::path data_file = BDBDataFile(path);
778  try {
779  std::unique_ptr<BerkeleyRODatabase> db = std::make_unique<BerkeleyRODatabase>(data_file);
780  status = DatabaseStatus::SUCCESS;
781  return db;
782  } catch (const std::runtime_error& e) {
783  error.original = e.what();
785  return nullptr;
786  }
787 }
788 } // namespace wallet
void write(std::span< const value_type > src)
Definition: streams.h:236
std::vector< std::variant< DataRecord, OverflowRecord > > records
Definition: migrate.cpp:388
BSWAP_CONSTEXPR uint32_t internal_bswap_32(uint32_t x)
Definition: byteswap.h:53
std::unique_ptr< DatabaseBatch > MakeBatch() override
Make a DatabaseBatch connected to this database.
Definition: migrate.cpp:706
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
Definition: migrate.cpp:711
BerkeleyROData::const_iterator m_cursor_end
Definition: migrate.h:66
uint8_t unused1
Definition: migrate.cpp:85
BerkeleyROData::const_iterator m_cursor
Definition: migrate.h:65
BTreeFlags flags
Definition: migrate.cpp:91
RecordHeader m_header
Definition: migrate.cpp:263
void Unserialize(Stream &s)
Definition: migrate.cpp:222
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:775
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:25
static const std::vector< std::byte > SUBDATABASE_NAME
Definition: migrate.cpp:25
static constexpr size_t SIZE
Definition: migrate.cpp:305
uint32_t ReadBE32(const B *ptr)
Definition: common.h:72
std::vector< std::byte > data
Definition: migrate.cpp:458
void Unserialize(Stream &s)
Definition: migrate.cpp:481
Bilingual messages:
Definition: translation.h:24
RecordHeader(bool other_endian)
Definition: migrate.cpp:218
#define LogWarning(...)
Definition: log.h:96
std::vector< uint16_t > indexes
Definition: migrate.cpp:477
PageHeader(uint32_t page_num, bool other_endian)
Definition: migrate.cpp:340
std::vector< InternalRecord > records
Definition: migrate.cpp:478
std::vector< std::byte > data
Definition: migrate.cpp:246
const char * prefix
Definition: rest.cpp:1141
PageType
Definition: migrate.cpp:27
uint32_t root
Definition: migrate.cpp:97
void Open() override
Open the database if it is not already opened.
Definition: migrate.cpp:529
InternalPage(const PageHeader &header)
Definition: migrate.cpp:472
A page of records in the database.
Definition: migrate.cpp:469
std::array< std::byte, 20 > uid
Definition: migrate.cpp:92
BTreeFlags
Definition: migrate.cpp:56
OverflowPage(const PageHeader &header)
Definition: migrate.cpp:448
uint32_t expected_page_num
Definition: migrate.cpp:105
uint32_t re_len
Definition: migrate.cpp:95
void Unserialize(Stream &s)
Definition: migrate.cpp:391
General class for records in a BDB BTree database.
Definition: migrate.cpp:207
MetaPage(uint32_t expected_page_num)
Definition: migrate.cpp:107
A class representing a BerkeleyDB file from which we can only read records.
Definition: migrate.h:20
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:372
std::vector< std::byte > data
Definition: migrate.cpp:268
uint32_t lsn_file
Definition: migrate.cpp:325
unsigned char chksum[16]
Definition: migrate.cpp:102
static constexpr int64_t SIZE
Definition: migrate.cpp:335
void Unserialize(Stream &s)
Definition: migrate.cpp:111
uint8_t encrypt_algo
Definition: migrate.cpp:82
PageHeader m_header
Definition: migrate.cpp:451
uint32_t magic
Definition: migrate.cpp:79
static bool exists(const path &p)
Definition: fs.h:95
void Unserialize(Stream &s)
Definition: migrate.cpp:461
uint32_t crypto_magic
Definition: migrate.cpp:99
constexpr uint32_t BTREE_MAGIC
Definition: migrate.cpp:21
DataRecord(const RecordHeader &header)
Definition: migrate.cpp:241
uint32_t lsn_file
Definition: migrate.cpp:76
uint8_t metaflags
Definition: migrate.cpp:84
A generic data page in the database.
Definition: migrate.cpp:322
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:132
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
Definition: zeroafterfree.h:44
#define LogInfo(...)
Definition: log.h:95
uint32_t page_num
Definition: migrate.cpp:78
PageType type
Definition: migrate.cpp:83
PageHeader m_header
Definition: migrate.cpp:475
unsigned char iv[20]
Definition: migrate.cpp:101
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:134
int64_t size()
Return the size of the file.
Definition: streams.cpp:60
uint32_t version
Definition: migrate.cpp:80
Class for records representing internal nodes of the BTree.
Definition: migrate.cpp:257
RecordHeader m_header
Definition: migrate.cpp:299
Status Next(DataStream &key, DataStream &value) override
Definition: migrate.cpp:759
uint32_t last_page
Definition: migrate.cpp:87
A page containing overflow data.
Definition: migrate.cpp:445
uint32_t prev_page
Definition: migrate.cpp:328
std::vector< uint16_t > indexes
Definition: migrate.cpp:387
uint32_t expected_page_num
Definition: migrate.cpp:337
Class for records representing overflow records of the BTree.
Definition: migrate.cpp:293
bool HasKey(DataStream &&key) override
Definition: migrate.cpp:747
uint32_t minkey
Definition: migrate.cpp:94
char trash[12]
Definition: migrate.cpp:100
BerkeleyROData m_records
Definition: migrate.h:33
uint32_t partitions
Definition: migrate.cpp:88
DatabaseStatus
Definition: db.h:186
uint32_t page_num
Definition: migrate.cpp:327
std::unique_ptr< DatabaseCursor > GetNewPrefixCursor(std::span< const std::byte > prefix) override
Definition: migrate.cpp:770
uint32_t re_pad
Definition: migrate.cpp:96
void clear()
Definition: streams.h:173
void Unserialize(Stream &s)
Definition: migrate.cpp:344
bool ReadKey(DataStream &&key, DataStream &value) override
Definition: migrate.cpp:734
std::string original
Definition: translation.h:25
constexpr uint32_t BTREE_MAGIC_OE
Definition: migrate.cpp:22
uint32_t key_count
Definition: migrate.cpp:89
Berkeley DB BTree metadata page layout.
Definition: migrate.cpp:73
void Unserialize(Stream &s)
Definition: migrate.cpp:249
static void SeekToPage(AutoFile &s, uint32_t page_num, uint32_t page_size)
Definition: migrate.cpp:523
fs::path BDBDataFile(const fs::path &wallet_path)
Definition: db.cpp:75
uint32_t next_page
Definition: migrate.cpp:329
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:157
RecordType
Definition: migrate.cpp:49
RecordHeader m_header
Definition: migrate.cpp:244
RecordsPage(const PageHeader &header)
Definition: migrate.cpp:382
uint32_t lsn_offset
Definition: migrate.cpp:326
A page of records in the database.
Definition: migrate.cpp:379
static constexpr size_t SIZE
Definition: migrate.cpp:214
uint32_t lsn_offset
Definition: migrate.cpp:77
char unused3[368]
Definition: migrate.cpp:98
PageHeader m_header
Definition: migrate.cpp:385
OverflowRecord(const RecordHeader &header)
Definition: migrate.cpp:296
uint32_t pagesize
Definition: migrate.cpp:81
const BerkeleyRODatabase & m_database
Definition: migrate.h:64
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:180
void Unserialize(Stream &s)
Definition: migrate.cpp:308
uint32_t unused2
Definition: migrate.cpp:93
uint32_t record_count
Definition: migrate.cpp:90
Class for data in the record directly.
Definition: migrate.cpp:238
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
uint32_t free_list
Definition: migrate.cpp:86
const fs::path m_filepath
Definition: migrate.h:23
const BerkeleyRODatabase & m_database
Definition: migrate.h:79
InternalRecord(const RecordHeader &header)
Definition: migrate.cpp:260
static constexpr size_t FIXED_SIZE
Definition: migrate.cpp:270
BerkeleyROCursor(const BerkeleyRODatabase &database, std::span< const std::byte > prefix={})
Definition: migrate.cpp:753
uint16_t hf_offset
Definition: migrate.cpp:331
void Unserialize(Stream &s)
Definition: migrate.cpp:273
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:426
uint16_t entries
Definition: migrate.cpp:330
BSWAP_CONSTEXPR uint16_t internal_bswap_16(uint16_t x)
Definition: byteswap.h:44