zebra/zebra-utils/calculate-checkpoints.sh

66 lines
2.4 KiB
Bash
Raw Normal View History

#!/bin/bash
set -euo pipefail
# Prints Zebra checkpoints, based on a list of block heights, sizes, ans hashes.
#
# Reads lines containing a block height, block byte size, and block header hash
# from stdin. Writes each checkpoint to stdout, as a line with space-separated
# fields.
#
# The block header hash is read in Bitcoin order, but written out in Zebra's
# internal byte order.
#
# Usage: get-height-size-hash.sh | calculate-checkpoints.sh
# get-height-size-hash.sh -testnet | calculate-checkpoints.sh
#
# calculate-checkpoints.sh ignores any command-line arguments.
#
# TODO: rewrite as a stand-alone Rust command-line tool.
# zebra-consensus accepts an ordered list of checkpoints, starting with the
# genesis block. Checkpoint heights can be chosen arbitrarily.
# We limit the memory usage for each checkpoint, based on the cumulative size of
# the serialized blocks in the chain. Deserialized blocks are larger, because
# they contain pointers and non-compact integers. But they should be within a
# constant factor of the serialized size.
MAX_CHECKPOINT_BYTE_COUNT=$((256*1024*1024))
# We limit the maximum number of blocks in each checkpoint. Each block uses a
# constant amount of memory for the supporting data structures and futures.
#
# TODO: In the Rust implementation, set this gap to half the sync service's
# LOOKAHEAD_LIMIT.
MAX_CHECKPOINT_HEIGHT_GAP=2000
cumulative_bytes=0
height_gap=0
while read -r height size hash; do
cumulative_bytes=$((cumulative_bytes + size))
height_gap=$((height_gap + 1))
# Checkpoints can be slightly larger the maximum byte count. That's ok,
# because the memory usage is only approximate. (This is a bash-specific
# optimisation, to avoid keeping a copy of the previous height and hash.
# Since exact sizes don't matter, we can use the same check in the Rust
# implementation. Or choose a simpler alternative.)
if [ "$height" -eq 0 ] || \
[ "$cumulative_bytes" -ge "$MAX_CHECKPOINT_BYTE_COUNT" ] || \
[ "$height_gap" -ge "$MAX_CHECKPOINT_HEIGHT_GAP" ]; then
# Reverse the byte order of hash.
#
# We reverse the hash after selecting the checkpoints, because launching
# a zebrad subprocess is expensive. (This is a bash-specific
# optimisation, the Rust implementation should reverse hashes as it loads
# them.)
hash=$(zebrad revhex "$hash")
echo "$height $hash"
cumulative_bytes=0
height_gap=0
fi
done