forked from Qortal/qortal
019ab2b21d
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
148 lines
4.2 KiB
Bash
Executable File
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
|