背景
比如想基于Solana运行一个Layer2网络或者应用链,需要尽可能的加快出块时间{从综合测试和其它类似项目综合分析,50ms是最快最稳定的},
如果单一的降低出块时间,会导致 recent_blockhash过期时间变短,从而可能导致交易发送时容易报 “Blockhash not found”
下面我们将给出如何实现50ms的slot,并保持recent_blockhash过期时间(120s)不变的方案
代码修改
agave\sdk\program\src\clock.rs
/// 每秒 tick 数:PoH 产生 tick 的速度(原为 160)
pub const DEFAULT_TICKS_PER_SECOND: u64 = 1000; // 1000 ticks = 1秒
/// 每 slot 包含 tick 数(原为 64)
pub const DEFAULT_TICKS_PER_SLOT: u64 = 50; // 50 ticks = 1 slot
/// blockhash 最大有效时间(保持主网一致)
pub const MAX_HASH_AGE_IN_SECONDS: u64 = 120; // blockhash 有效时间 120秒
Solana 会自动计算:
pub const MAX_RECENT_BLOCKHASHES: usize =
MAX_HASH_AGE_IN_SECONDS * DEFAULT_TICKS_PER_SECOND as usize / DEFAULT_TICKS_PER_SLOT as usize;
// => 2400
MAX_RECENT_BLOCKHASHES 为什么要 调整为 2400
这是因为你想要 每个 slot 时间为 50ms,而官方默认是 400ms,两者时间差 8 倍。
解释为什么需要把 MAX_RECENT_BLOCKHASHES
调整到 2400
1. 官方默认参数回顾:
参数 | 数值 |
---|---|
MAX_HASH_AGE_IN_SECONDS | 120 s |
DEFAULT_TICKS_PER_SECOND | 160 |
DEFAULT_TICKS_PER_SLOT | 64 |
MAX_RECENT_BLOCKHASHES | 300 |
计算:
意味着最近 120 秒内链上大约有 300 个 slot(因为每 slot 约 0.4 秒)。
2. 你想改成 50ms/slot
50ms = 0.05秒,等于官方 0.4秒的 18\frac{1}{8}81。
在 120 秒内,会有:
3. 为了保持 blockhash
有效时间不变
你必须保存最近 2400 个 blockhash(对应 2400 个 slot),才能覆盖 120 秒内所有 slot。
4. 计算验证
MAX_RECENT_BLOCKHASHES = MAX_HASH_AGE_IN_SECONDS * DEFAULT_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT
现在参数改成:
- MAX_HASH_AGE_IN_SECONDS = 120
- DEFAULT_TICKS_PER_SECOND = 1000 (tick 速度提高了)
- DEFAULT_TICKS_PER_SLOT = 50
计算:
总结
每 slot 时间 | slot 数(120秒内) | 需保存最近 blockhash 数量 MAX_RECENT_BLOCKHASHES |
---|---|---|
400ms | 300 | 300 |
50ms | 2400 | 2400 |
所以,MAX_RECENT_BLOCKHASHES
调整为 2400 是为了匹配新的更快 slot 频率,保证 blockhash 在 120 秒内仍有效
solana-genesis 初始化
对于初始化时也需要对应的加入启动参数
--ticks-per-slot 50
测试脚本
#!/bin/bash
RPC_URL="https://api.mainnet-beta.solana.com"
# Step 1: 获取最新 blockhash
echo "Fetching latest blockhash..."
RESPONSE=$(curl -s -X POST $RPC_URL \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getLatestBlockhash"}')
BLOCKHASH=$(echo $RESPONSE | jq -r '.result.value.blockhash')
echo " Got blockhash: $BLOCKHASH"
echo " Starting to monitor validity..."
SECONDS_ELAPSED=0
INTERVAL=1 # 每次检测间隔,单位秒
while true; do
VALID_RESPONSE=$(curl -s -X POST $RPC_URL \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"isBlockhashValid\",\"params\":[\"$BLOCKHASH\"]}")
IS_VALID=$(echo $VALID_RESPONSE | jq -r '.result.value')
if [ "$IS_VALID" = "true" ]; then
echo "[$SECONDS_ELAPSED s] Blockhash still valid"
sleep $INTERVAL
SECONDS_ELAPSED=$((SECONDS_ELAPSED + INTERVAL))
else
echo "[$SECONDS_ELAPSED s] Blockhash EXPIRED"
break
fi
done
echo " Total validity duration: $SECONDS_ELAPSED seconds"