Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251kHeaderSize + 10000,2522 * (kHeaderSize + 10000),2532 * (kHeaderSize + 10000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize,2542 * (kHeaderSize + 10000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize +255kHeaderSize + 1,2563 * log::kBlockSize,257};259// LogTest::initial_offset_last_record_offsets_ must be defined before this.260int LogTest::num_initial_offset_records_ =261sizeof(LogTest::initial_offset_last_record_offsets_) / sizeof(uint64_t);263TEST(LogTest, Empty) { ASSERT_EQ("EOF", Read()); }265TEST(LogTest, ReadWrite) {266Write("foo");267Write("bar");268Write("");269Write("xxxx");270ASSERT_EQ("foo", Read());271ASSERT_EQ("bar", Read());272ASSERT_EQ("", Read());273ASSERT_EQ("xxxx", Read());274ASSERT_EQ("EOF", Read());275ASSERT_EQ("EOF", Read()); // Make sure reads at eof work276}278TEST(LogTest, ManyBlocks) {279for (int i = 0; i < 100000; i++) {280Write(NumberString(i));281}282for (int i = 0; i < 100000; i++) {283ASSERT_EQ(NumberString(i), Read());284}285ASSERT_EQ("EOF", Read());286}288TEST(LogTest, Fragmentation) {289Write("small");290Write(BigString("medium", 50000));291Write(BigString("large", 100000));292ASSERT_EQ("small", Read());293ASSERT_EQ(BigString("medium", 50000), Read());294ASSERT_EQ(BigString("large", 100000), Read());295ASSERT_EQ("EOF", Read());296}298TEST(LogTest, MarginalTrailer) {299// Make a trailer that is exactly the same length as an empty record.300const int n = kBlockSize - 2 * kHeaderSize;301Write(BigString("foo", n));302ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes());303Write("");304Write("bar");305ASSERT_EQ(BigString("foo", n), Read());306ASSERT_EQ("", Read());307ASSERT_EQ("bar", Read());308ASSERT_EQ("EOF", Read());309}311TEST(LogTest, MarginalTrailer2) {312// Make a trailer that is exactly the same length as an empty record.313const int n = kBlockSize - 2 * kHeaderSize;314Write(BigString("foo", n));315ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes());316Write("bar");317ASSERT_EQ(BigString("foo", n), Read());318ASSERT_EQ("bar", Read());319ASSERT_EQ("EOF", Read());320ASSERT_EQ(0, DroppedBytes());321ASSERT_EQ("", ReportMessage());322}324TEST(LogTest, ShortTrailer) {325const int n = kBlockSize - 2 * kHeaderSize + 4;326Write(BigString("foo", n));327ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes());328Write("");329Write("bar");330ASSERT_EQ(BigString("foo", n), Read());331ASSERT_EQ("", Read());332ASSERT_EQ("bar", Read());333ASSERT_EQ("EOF", Read());334}336TEST(LogTest, AlignedEof) {337const int n = kBlockSize - 2 * kHeaderSize + 4;338Write(BigString("foo", n));339ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes());340ASSERT_EQ(BigString("foo", n), Read());341ASSERT_EQ("EOF", Read());342}344TEST(LogTest, OpenForAppend) {345Write("hello");346ReopenForAppend();347Write("world");348ASSERT_EQ("hello", Read());349ASSERT_EQ("world", Read());350ASSERT_EQ("EOF", Read());351}353TEST(LogTest, RandomRead) {354const int N = 500;355Random write_rnd(301);356for (int i = 0; i < N; i++) {357Write(RandomSkewedString(i, &write_rnd));358}359Random read_rnd(301);360for (int i = 0; i < N; i++) {361ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read());362}363ASSERT_EQ("EOF", Read());364}366// Tests of all the error paths in log_reader.cc follow:368TEST(LogTest, ReadError) {369Write("foo");370ForceError();371ASSERT_EQ("EOF", Read());372ASSERT_EQ(kBlockSize, DroppedBytes());373ASSERT_EQ("OK", MatchError("read error"));374}376TEST(LogTest, BadRecordType) {377Write("foo");378// Type is stored in header[6]379IncrementByte(6, 100);380FixChecksum(0, 3);381ASSERT_EQ("EOF", Read());382ASSERT_EQ(3, DroppedBytes());383ASSERT_EQ("OK", MatchError("unknown record type"));384}386TEST(LogTest, TruncatedTrailingRecordIsIgnored) {387Write("foo");388ShrinkSize(4); // Drop all payload as well as a header byte389ASSERT_EQ("EOF", Read());390// Truncated last record is ignored, not treated as an error.391ASSERT_EQ(0, DroppedBytes());392ASSERT_EQ("", ReportMessage());393}395TEST(LogTest, BadLength) {396const int kPayloadSize = kBlockSize - kHeaderSize;397Write(BigString("bar", kPayloadSize));398Write("foo");399// Least significant size byte is stored in header[4].400IncrementByte(4, 1);401ASSERT_EQ("foo", Read());402ASSERT_EQ(kBlockSize, DroppedBytes());403ASSERT_EQ("OK", MatchError("bad record length"));404}406TEST(LogTest, BadLengthAtEndIsIgnored) {407Write("foo");408ShrinkSize(1);409ASSERT_EQ("EOF", Read());410ASSERT_EQ(0, DroppedBytes());411ASSERT_EQ("", ReportMessage());412}414TEST(LogTest, ChecksumMismatch) {415Write("foo");416IncrementByte(0, 10);417ASSERT_EQ("EOF", Read());418ASSERT_EQ(10, DroppedBytes());419ASSERT_EQ("OK", MatchError("checksum mismatch"));420}422TEST(LogTest, UnexpectedMiddleType) {423Write("foo");424SetByte(6, kMiddleType);425FixChecksum(0, 3);426ASSERT_EQ("EOF", Read());427ASSERT_EQ(3, DroppedBytes());428ASSERT_EQ("OK", MatchError("missing start"));429}431TEST(LogTest, UnexpectedLastType) {432Write("foo");433SetByte(6, kLastType);434FixChecksum(0, 3);435ASSERT_EQ("EOF", Read());436ASSERT_EQ(3, DroppedBytes());437ASSERT_EQ("OK", MatchError("missing start"));438}440TEST(LogTest, UnexpectedFullType) {441Write("foo");442Write("bar");443SetByte(6, kFirstType);444FixChecksum(0, 3);445ASSERT_EQ("bar", Read());446ASSERT_EQ("EOF", Read());447ASSERT_EQ(3, DroppedBytes());448ASSERT_EQ("OK", MatchError("partial record without end"));449}451TEST(LogTest, UnexpectedFirstType) {452Write("foo");453Write(BigString("bar", 100000));454SetByte(6, kFirstType);455FixChecksum(0, 3);456ASSERT_EQ(BigString("bar", 100000), Read());457ASSERT_EQ("EOF", Read());458ASSERT_EQ(3, DroppedBytes());459ASSERT_EQ("OK", MatchError("partial record without end"));460}462TEST(LogTest, MissingLastIsIgnored) {463Write(BigString("bar", kBlockSize));464// Remove the LAST block, including header.465ShrinkSize(14);466ASSERT_EQ("EOF", Read());467ASSERT_EQ("", ReportMessage());468ASSERT_EQ(0, DroppedBytes());469}471TEST(LogTest, PartialLastIsIgnored) {472Write(BigString("bar", kBlockSize));473// Cause a bad record length in the LAST block.474ShrinkSize(1);475ASSERT_EQ("EOF", Read());476ASSERT_EQ("", ReportMessage());477ASSERT_EQ(0, DroppedBytes());478}480TEST(LogTest, SkipIntoMultiRecord) {481// Consider a fragmented record:482// first(R1), middle(R1), last(R1), first(R2)483// If initial_offset points to a record after first(R1) but before first(R2)484// incomplete fragment errors are not actual errors, and must be suppressed485// until a new first or full record is encountered.486Write(BigString("foo", 3 * kBlockSize));487Write("correct");488StartReadingAt(kBlockSize);490ASSERT_EQ("correct", Read());491ASSERT_EQ("", ReportMessage());492ASSERT_EQ(0, DroppedBytes());493ASSERT_EQ("EOF", Read());494}496TEST(LogTest, ErrorJoinsRecords) {497// Consider two fragmented records:498// first(R1) last(R1) first(R2) last(R2)499// where the middle two fragments disappear. We do not want500// first(R1),last(R2) to get joined and returned as a valid record.
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.