qortal/tools/block-timings.sh
CalDescent 019ab2b21d Added tools/block-timings-sh which can be used to test out new block timings (specified in blockchain.json).
The script will fetch a set of blocks and then backtest the specified blockTimings settings (target, deviation, and power) against those real life blocks. This allows configurations to be fine tuned to tighten up block times, and to adjust the timestamp variance between levels.

Usage:
block-timings.sh <startheight> <count> [target] [deviation] [power]

startheight: a block height, preferably within the untrimmed range, to avoid data gaps
count: the number of blocks to request and analyse after the start height. Default: 100
target: the target block time in milliseconds. Originates from blockchain.json. Default: 60000
deviation: the allowed block time deviation in milliseconds. Originates from blockchain.json. Default: 30000
power: used when transforming key distance to a time offset. Originates from blockchain.json. Default: 0.2
2021-05-09 19:24:25 +01:00

148 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
start_height=$1
count=$2
if [ -z "${start_height}" ]; then
echo
echo "Error: missing start height."
echo
echo "Usage:"
echo "block-timings.sh <startheight> <count> [target] [deviation] [power]"
echo
echo "startheight: a block height, preferably within the untrimmed range, to avoid data gaps"
echo "count: the number of blocks to request and analyse after the start height. Default: 100"
echo "target: the target block time in milliseconds. Originates from blockchain.json. Default: 60000"
echo "deviation: the allowed block time deviation in milliseconds. Originates from blockchain.json. Default: 30000"
echo "power: used when transforming key distance to a time offset. Originates from blockchain.json. Default: 0.2"
echo
exit
fi
target=$3
deviation=$4
power=$5
count=${count:=100}
target=${target:=60000}
deviation=${deviation:=30000}
power=${power:=0.2}
finish_height=$((start_height + count - 1))
height=$start_height
echo "Settings:"
echo "Target time offset: ${target}"
echo "Deviation: ${deviation}"
echo "Power transform: ${power}"
echo
function calculate_time_offset {
local key_distance_ratio=$1
local transformed=$( echo "" | awk "END {print ${key_distance_ratio} ^ ${power}}")
local time_offset=$(echo "${deviation}*2*${transformed}" | bc)
time_offset=${time_offset%.*}
echo $time_offset
}
function fetch_and_process_blocks {
echo "Fetching blocks from height ${start_height} to ${finish_height}..."
echo
total_time_offset=0
errors=0
while [ "${height}" -le "${finish_height}" ]; do
block_minting_info=$(curl -s "http://localhost:12391/blocks/byheight/${height}/mintinginfo")
error=$(echo "${block_minting_info}" | jq -r .error)
if [ "${error}" != "null" ]; then
echo "Error fetching minting info for block ${height}"
echo
errors=$((errors+1))
height=$((height+1))
continue;
fi
# Parse minting info
minter_level=$(echo "${block_minting_info}" | jq -r .minterLevel)
key_distance_ratio=$(echo "${block_minting_info}" | jq -r .keyDistanceRatio)
time_delta=$(echo "${block_minting_info}" | jq -r .timeDelta)
time_offset=$(calculate_time_offset "${key_distance_ratio}")
block_time=$((target-deviation+time_offset))
echo "=== BLOCK ${height} ==="
echo "Minter level: ${minter_level}"
echo "Key distance ratio: ${key_distance_ratio}"
echo "Time offset: ${time_offset}"
echo "Block time (real): ${time_delta}"
echo "Block time (calculated): ${block_time}"
if [ "${time_delta}" -ne "${block_time}" ]; then
echo "WARNING: Block time mismatch. This is to be expected when using custom settings."
fi
echo
total_time_offset=$((total_time_offset+block_time))
height=$((height+1))
done
adjusted_count=$((count-errors))
if [ "${adjusted_count}" -eq 0 ]; then
echo "No blocks were retrieved."
echo
exit;
fi
mean_time_offset=$((total_time_offset/adjusted_count))
time_offset_diff=$((mean_time_offset-target))
echo "==================="
echo "===== SUMMARY ====="
echo "==================="
echo "Total blocks retrieved: ${adjusted_count}"
echo "Total blocks failed: ${errors}"
echo "Mean time offset: ${mean_time_offset}ms"
echo "Target time offset: ${target}ms"
echo "Difference from target: ${time_offset_diff}ms"
echo
}
function estimate_key_distance_ratio_for_level {
local level=$1
local example_key_distance="0.5"
echo "(${example_key_distance}/${level})"
}
function estimate_block_timestamps {
min_block_time=9999999
max_block_time=0
echo "===== BLOCK TIME ESTIMATES ====="
for level in {1..10}; do
example_key_distance_ratio=$(estimate_key_distance_ratio_for_level "${level}")
time_offset=$(calculate_time_offset "${example_key_distance_ratio}")
block_time=$((target-deviation+time_offset))
if [ "${block_time}" -gt "${max_block_time}" ]; then
max_block_time=${block_time}
fi
if [ "${block_time}" -lt "${min_block_time}" ]; then
min_block_time=${block_time}
fi
echo "Level: ${level}, time offset: ${time_offset}, block time: ${block_time}"
done
block_time_range=$((max_block_time-min_block_time))
echo "Range: ${block_time_range}"
echo
}
fetch_and_process_blocks
estimate_block_timestamps