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.
251# also give up.252max_buf = (max_mem - (MINCHAINWORK_HEADERS // period)) // COMPACT_HEADER_SIZE253if max_buf < min_bufsize:254return None255if attack_rate(period, max_buf, attack_headers)[0] >= attack_headers:256return None257# If it is sufficient, that's an upper bound to start our search.258succ_buf = min_bufsize - 1259fail_buf = max_buf261# Then perform a bisection search to narrow it down.262while fail_buf > succ_buf + 1:263try_buf = (succ_buf + fail_buf) // 2264if attack_rate(period, try_buf, attack_headers)[0] >= attack_headers:265succ_buf = try_buf266else:267fail_buf = try_buf268return fail_buf271def optimize(when):272"""Find the best (period, bufsize) configuration."""274# When period*bufsize = memory_scale, the per-peer memory for a mainchain sync and a maximally275# long low-difficulty header sync are equal.276memory_scale = (find_max_headers(when) - MINCHAINWORK_HEADERS) / COMPACT_HEADER_SIZE277# Compute approximation for {bufsize/period}, using a formula for a simplified problem.278approx_ratio = lambert_w(log(4) * memory_scale / ATTACK_HEADERS**2) / log(4)279# Use those for a first attempt.280print("Searching configurations:")281period = int(sqrt(memory_scale / approx_ratio) + 0.5)282bufsize = find_bufsize(period, ATTACK_HEADERS, when)283mem = memory_usage(period, bufsize, when)284best = (period, bufsize, mem)285maps = [(period, bufsize), (MINCHAINWORK_HEADERS + 1, None)]286print(f"- Initial: period={period}, buffer={bufsize}, mem={mem[0] / 8192:.3f} KiB")288# Consider all period values between 1 and MINCHAINWORK_HEADERS, except the one just tried.289periods = [iv for iv in range(1, MINCHAINWORK_HEADERS + 1) if iv != period]290# Iterate, picking a random element from periods, computing its corresponding bufsize, and291# then using the result to shrink the period.292while True:293# Remove all periods whose memory usage for low-work long chain sync exceed the best294# memory usage we've found so far.295periods = [p for p in periods if find_max_headers(when) // p < best[2][0]]296# Stop if there is nothing left to try.297if len(periods) == 0:298break299# Pick a random remaining option for period size, and compute corresponding bufsize.300period = periods.pop(random.randrange(len(periods)))301# The buffer size (at a given attack level) cannot shrink as the period grows. Find the302# largest period smaller than the selected one we know the buffer size for, and use that303# as a lower bound to find_bufsize.304min_bufsize = max([(p, b) for p, b in maps if p < period] + [(0,0)])[1]305bufsize = find_bufsize(period, ATTACK_HEADERS, when, best[2][0], min_bufsize)306if bufsize is not None:307# We found a (period, bufsize) configuration with better memory usage than our best308# so far. Remember it for future lower bounds.309maps.append((period, bufsize))310mem = memory_usage(period, bufsize, when)311assert mem[0] <= best[2][0]312if ASSUME_CONVEX:313# Remove all periods that are on the other side of the former best as the new314# best.315periods = [p for p in periods if (p < best[0]) == (period < best[0])]316best = (period, bufsize, mem)317print(f"- New best: period={period}, buffer={bufsize}, mem={mem[0] / 8192:.3f} KiB")318else:319# The (period, bufsize) configuration we found is worse than what we already had.320if ASSUME_CONVEX:321# Remove all periods that are on the other side of the tried configuration as the322# best one.323periods = [p for p in periods if (p < period) == (best[0] < period)]325# Return the result.326period, bufsize, _ = best327return period, bufsize330def analyze(when):331"""Find the best configuration and print it out."""333period, bufsize = optimize(when)334# Compute accurate statistics for the best found configuration.335_, mem_mainchain, mem_timewarp = memory_usage(period, bufsize, when)336headers_per_attack, _ = attack_rate(period, bufsize)337attack_volume = NET_HEADER_SIZE * MINCHAINWORK_HEADERS338# And report them.339print()340print(f"Given current min chainwork headers of {MINCHAINWORK_HEADERS}, the optimal parameters for low")341print(f"memory usage on mainchain for release until {TIME:%Y-%m-%d} is:")342print()343print(f" // Generated by headerssync-params.py on {datetime.today():%Y-%m-%d}.")344print( " m_headers_sync_params = HeadersSyncParams{")345print(f" .commitment_period = {period},")346print(f" .redownload_buffer_size = {bufsize},"347f" // {bufsize}/{period} = ~{bufsize/period:.1f} commitments")348print( " };")349print()350print("Properties:")351print(f"- Per-peer memory for mainchain sync: {mem_mainchain / 8192:.3f} KiB")352print(f"- Per-peer memory for timewarp attack: {mem_timewarp / 8192:.3f} KiB")353print(f"- Attack rate: {1/headers_per_attack:.1f} attacks for 1 header of memory growth")354print(f" (where each attack costs {attack_volume / 8388608:.3f} MiB bandwidth)")357analyze(TIME)
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.