From d5b82d9cdc823212250ec8cc9796ad24d76b6f38 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 17 Aug 2026 11:56:33 +0800 Subject: [PATCH 01/15] genesis(testnet): schedule the Zanzibar hardfork at 46850041 Zanzibar is the next fork after Yap. It activates IIP-59 on-chain voter reward distribution, the BLS proof-of-possession requirement at candidate register/update, the in-contract transfer log topic fix, and the GetCommittedState prestate fix. 46850041 starts an epoch ((h-1) % 360 == 0, testnet epoch is numDelegates 24 * numSubEpochs 15) and sits roughly three days ahead of the chain tip at the time of writing (46750267, ~2.6s/block). epochsPerRewardEra (24) and voterBudgetPerBlock (256) are left at their iotex-core defaults; the genesis loader layers this YAML over them. Requires iotex-core v2.5.0. --- genesis_testnet.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/genesis_testnet.yaml b/genesis_testnet.yaml index a5fbb1b..d2c314e 100644 --- a/genesis_testnet.yaml +++ b/genesis_testnet.yaml @@ -40,6 +40,7 @@ blockchain: xinguBetaHeight: 36826561 yapHeight: 42819841 yapBetaHeight: 43361281 + zanzibarHeight: 46850041 numCandidateDelegates: 36 numDelegates: 24 numSubEpochs: 15 From 704591f2a48210e409e44bc353473fd427f5ce4c Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 17 Aug 2026 13:07:25 +0800 Subject: [PATCH 02/15] release: prepare v2.5.0 (Zanzibar hardfork on TestNet) - genesis_testnet.yaml: autoDepositContractAddress and delegateProfileContractAddress, the two contracts IIP-59 reads. The AutoDepositRegister was deployed on TestNet for this release from the same runtime bytecode as MainNet's, so the storage layout the direct-slot reader depends on matches; DelegateProfile already existed. - changelog/v2.5.0-release-note.md. - v2.4.4 -> v2.5.0 across READMEs, archive-node.md and the all_in_one scripts. config_mainnet.yaml / config_testnet.yaml are untouched: v2.5.0 adds no new node-config fields, only the Zanzibar height-ordering check, which lives in genesis. MainNet has no zanzibarHeight, so v2.5.0 is a no-op upgrade there. --- CLAUDE.md | 6 +-- README.md | 26 +++++----- README_CN.md | 22 ++++---- README_CN_testnet.md | 14 ++--- README_testnet.md | 14 ++--- archive-node.md | 4 +- changelog/v2.5.0-release-note.md | 88 ++++++++++++++++++++++++++++++++ genesis_testnet.yaml | 2 + scripts/all_in_one_mainnet.sh | 14 ++--- scripts/all_in_one_testnet.sh | 8 +-- 10 files changed, 144 insertions(+), 54 deletions(-) create mode 100644 changelog/v2.5.0-release-note.md diff --git a/CLAUDE.md b/CLAUDE.md index 4bacd2b..d0459d1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This is the **IoTeX Delegate Manual** repository - configuration and operational ## Version Alignment -This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.4.4**. When iotex-core releases a new version: +This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0**. When iotex-core releases a new version: 1. Update version references in README.md, config files, and scripts 2. Add a release note in `changelog/` 3. Create a PR but do NOT merge until the final release is tagged in iotex-core @@ -38,7 +38,7 @@ See `release_flow.md` for the complete release process. ## Common Tasks ### Update for a new iotex-core release -1. Update `version` references in README.md (search for `v2.4.4`) +1. Update `version` references in README.md (search for `v2.5.0`) 2. Update docker image tags in `scripts/all_in_one_mainnet.sh` and `scripts/all_in_one_testnet.sh` 3. Add release note in `changelog/vX.Y.Z-release-note.md` 4. Update `config_mainnet.yaml` and `config_testnet.yaml` if needed @@ -56,7 +56,7 @@ bash <(curl -s https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/ma ### Non-interactive upgrade (AI agent / CI) ```bash bash setup_fullnode.sh --auto --home=/path/to/iotex-var -bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.4.4 +bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0 bash setup_fullnode.sh --auto --home=/path/to/iotex-var --force # reinstall same version ``` Flags: `--auto` (skip prompts), `--home=` (IOTEX_HOME), `--version=` (target version), `--force` (bypass same-version check), `--monitor` (enable monitoring), `plugin=gateway` (enable gateway). diff --git a/README.md b/README.md index 2256f50..82379b9 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Here are the software versions we use: -- MainNet: v2.4.4 +- MainNet: v2.5.0 ## Join TestNet To start and run a testnet node, please click [**Join Testnet**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_testnet.md) @@ -33,7 +33,7 @@ This is the recommended way to start an IoTeX node 1. Pull the docker image: ``` -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 ``` 2. Set the environment with the following commands: @@ -48,9 +48,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch ``` 3. Edit `$IOTEX_HOME/etc/config.yaml`, look for `externalHost` and `producerPrivKey`, uncomment the lines and fill in your external IP and private key. If you leave `producerPrivKey` empty, your node will be assgined with a random key. @@ -105,7 +105,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -126,7 +126,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -150,7 +150,7 @@ Same as [Join MainNet](#mainnet) step 2 ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.4.4 +git checkout v2.5.0 // optional export GOPROXY=https://goproxy.io @@ -312,7 +312,7 @@ The upgrade script supports a non-interactive mode for use with AI agents, CI/CD |---|---| | `--auto` | Non-interactive mode, skip all prompts | | `--home=/path` | Set `$IOTEX_HOME` directory | -| `--version=v2.4.4` | Target version (default: latest release) | +| `--version=v2.5.0` | Target version (default: latest release) | | `--force` | Reinstall even if already running the same version | | `--snapshot` | Download blockchain snapshot (recommended for fresh install) | | `--monitor` | Enable monitoring | @@ -326,7 +326,7 @@ bash setup_fullnode.sh --auto --home=/path/to/iotex-var --snapshot bash setup_fullnode.sh --auto --home=/path/to/iotex-var # Upgrade to a specific version -bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.4.4 +bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0 ``` **Notes:** @@ -339,12 +339,12 @@ Node with gateway plugin enabled will perform extra indexing to serve API reques ### Transaction-log patch (gateway / API / archive nodes) -Nodes that **serve transaction-log queries** (`GetTransactionLogByActionHash`, `GetTransactionLogByBlockHeight`) should apply the transaction-log patch shipped with v2.4.4, which corrects a set of historical in-contract-transfer records. Delegate / fullnodes that do not serve these queries do not need it. +Nodes that **serve transaction-log queries** (`GetTransactionLogByActionHash`, `GetTransactionLogByBlockHeight`) should apply the transaction-log patch shipped with v2.5.0, which corrects a set of historical in-contract-transfer records. Delegate / fullnodes that do not serve these queries do not need it. 1. Download the patch file into the node's data directory and verify its checksum: ``` -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch echo "dee9406afc991d5439ab4c27bc85fa658e1fb241ddabe1cc5fef18f27d728986 $IOTEX_HOME/data/txlog.db.patch" | sha256sum -c ``` @@ -357,7 +357,7 @@ chain: 3. Restart the node. -> **Important:** only set `patchTransactionLogPath` if the patch file exists at that path — a node configured with a missing patch file will **fail to start**. The patch is read-only and does not change balances, receipts, or block hashes. See the [v2.4.4 release note](changelog/v2.4.4-release-note.md) for details. +> **Important:** only set `patchTransactionLogPath` if the patch file exists at that path — a node configured with a missing patch file will **fail to start**. The patch is read-only and does not change balances, receipts, or block hashes. See the [v2.5.0 release note](changelog/v2.5.0-release-note.md) for details. ## Q&A Please refer [here](https://github.com/iotexproject/iotex-bootstrap/wiki/Q&A) for Q&A. diff --git a/README_CN.md b/README_CN.md index 06afa72..8dead9c 100644 --- a/README_CN.md +++ b/README_CN.md @@ -18,7 +18,7 @@ 以下是当前我们使用的软件版本: -- 主网:v2.4.4 +- 主网:v2.5.0 ## 加入测试网 如果你要启动节点加入测试网,请点击[**加入测试网**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_CN_testnet.md) @@ -32,7 +32,7 @@ 1. 提取(pull) docker镜像 ``` -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 ``` 2. 使用以下命令设置运行环境 @@ -47,9 +47,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch ``` 3. 编辑 `$IOTEX_HOME/etc/config.yaml`, 查找 `externalHost` 和 `producerPrivKey`, 取消注释行并填写您的外部 IP 和私钥。如果`producerPrivKey`放空,你的节点将被分配一个随机密钥。 @@ -103,7 +103,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -121,7 +121,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -141,7 +141,7 @@ docker run -d --restart on-failure --name iotex \ ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.4.4 +git checkout v2.5.0 // optional export GOPROXY=https://goproxy.io @@ -281,12 +281,12 @@ bash <(curl -s https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/ma ### 交易日志补丁(网关 / API / 归档节点) -**对外提供交易日志查询**(`GetTransactionLogByActionHash`、`GetTransactionLogByBlockHeight`)的节点应安装 v2.4.4 引入的交易日志补丁,它会修正一组历史合约内转账记录。不对外提供这些查询的 delegate / 全节点无需安装。 +**对外提供交易日志查询**(`GetTransactionLogByActionHash`、`GetTransactionLogByBlockHeight`)的节点应安装 v2.5.0 引入的交易日志补丁,它会修正一组历史合约内转账记录。不对外提供这些查询的 delegate / 全节点无需安装。 1. 将补丁文件下载到节点的 data 目录,并校验其 checksum: ``` -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch echo "dee9406afc991d5439ab4c27bc85fa658e1fb241ddabe1cc5fef18f27d728986 $IOTEX_HOME/data/txlog.db.patch" | sha256sum -c ``` @@ -299,7 +299,7 @@ chain: 3. 重启节点。 -> **重要:** 仅当补丁文件确实存在于该路径时才设置 `patchTransactionLogPath` —— 若配置了该路径但文件缺失,节点将**无法启动**。该补丁为只读,不会改变余额、收据或区块哈希。详见 [v2.4.4 release note](changelog/v2.4.4-release-note.md)。 +> **重要:** 仅当补丁文件确实存在于该路径时才设置 `patchTransactionLogPath` —— 若配置了该路径但文件缺失,节点将**无法启动**。该补丁为只读,不会改变余额、收据或区块哈希。详见 [v2.5.0 release note](changelog/v2.5.0-release-note.md)。 ## 常见问题 diff --git a/README_CN_testnet.md b/README_CN_testnet.md index 27ed08a..1ea5cc3 100644 --- a/README_CN_testnet.md +++ b/README_CN_testnet.md @@ -17,7 +17,7 @@ 以下是当前我们使用的软件版本: -- 测试网:v2.4.4 +- 测试网:v2.5.0 **Note** 如果你要启动节点加入主网,请点击[**加入主网**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_CN.md) @@ -31,7 +31,7 @@ 1. 提取(pull) docker镜像 ``` -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 ``` 2. 使用以下命令设置运行环境 @@ -46,8 +46,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. 编辑 `$IOTEX_HOME/etc/config.yaml`, 查找 `externalHost` 和 `producerPrivKey`, 取消注释行并填写您的外部 IP 和私钥。如果`producerPrivKey`放空,你的节点将被分配一个随机密钥。 @@ -100,7 +100,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -118,7 +118,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -138,7 +138,7 @@ docker run -d --restart on-failure --name iotex \ ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.4.4 +git checkout v2.5.0 // optional export GOPROXY=https://goproxy.io diff --git a/README_testnet.md b/README_testnet.md index eb980b1..d7fca20 100644 --- a/README_testnet.md +++ b/README_testnet.md @@ -18,7 +18,7 @@ Here are the software versions we use: -- TestNet: v2.4.4 +- TestNet: v2.5.0 **Note** To start and run a mainnet node, please click [**Join Mainnet**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README.md) @@ -31,7 +31,7 @@ This is the recommended way to start an IoTeX node 1. Pull the docker image: ``` -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 ``` 2. Set the environment with the following commands: @@ -46,8 +46,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. Edit `$IOTEX_HOME/etc/config.yaml`, look for `externalHost` and `producerPrivKey`, uncomment the lines and fill in your external IP and private key. If you leave `producerPrivKey` empty, your node will be assgined with a random key. @@ -101,7 +101,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -121,7 +121,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -142,7 +142,7 @@ Same as [Join TestNet](#testnet) step 2 ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.4.4 +git checkout v2.5.0 // optional export GOPROXY=https://goproxy.io diff --git a/archive-node.md b/archive-node.md index f2fadec..363157c 100644 --- a/archive-node.md +++ b/archive-node.md @@ -151,7 +151,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/iotex-archive/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -194,7 +194,7 @@ git clone https://github.com/iotexproject/iotex-core.git cd iotex-core #checkout the code branch for archive node -git checkout v2.4.4 +git checkout v2.5.0 #build binary make build diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md new file mode 100644 index 0000000..945e96e --- /dev/null +++ b/changelog/v2.5.0-release-note.md @@ -0,0 +1,88 @@ +# v2.5.0 Release Note + +## Summary + +v2.5.0 is a **required** release for TestNet delegates. It introduces the **Zanzibar** hardfork, which activates IIP-59 on-chain voter reward distribution together with three correctness/security fixes. + +Zanzibar is scheduled on **TestNet at block 46850041** (roughly three days after this release). It is **not scheduled on MainNet** — `genesis_mainnet.yaml` carries no `zanzibarHeight`, so MainNet nodes running v2.5.0 behave exactly as they did on v2.4.4. MainNet operators may upgrade at their convenience; TestNet delegates **must** upgrade before block 46850041 or they will fork off the network. + +Both `genesis_testnet.yaml` and `config_testnet.yaml` must be refreshed as part of this upgrade — the genesis file carries the new activation height and two new contract addresses. + +> **TestNet delegates:** the genesis file changed. Re-download `genesis_testnet.yaml` when you upgrade; keeping the old one will fork your node at 46850041. + +## Hardfork: Zanzibar + +| Network | Height | Approx. date | +|---------|--------|--------------| +| TestNet | 46850041 | ~3 days after release | +| MainNet | not scheduled | — | + +Zanzibar activates four changes at once: + +1. **IIP-59 on-chain voter reward distribution** — voter rewards are computed and credited by the protocol at era boundaries instead of by the off-chain Hermes service. +2. **BLS proof-of-possession at candidate register/update** — closes a rogue-key aggregate-forgery window ahead of IIP-52's signature aggregation. +3. **In-contract transfer log topic fix.** +4. **`GetCommittedState` prestate fix** — storage slots absent from the pre-transaction trie no longer report a post-mutation value, correcting EIP-2200 SSTORE gas accounting. + +### New genesis fields + +`genesis_testnet.yaml` gains three entries: + +```yaml +blockchain: + zanzibarHeight: 46850041 + autoDepositContractAddress: io1grzhsc5w7a07d6ple4kuaxylxdwcsj7w8r2zuu +poll: + delegateProfileContractAddress: io16x0lkj99cx9h032p6vkpkxkzgsxzsam5t5sk5s +``` + +`autoDepositContractAddress` is the AutoDepositRegister contract IIP-59 reads per-voter compound preferences from. It was deployed on TestNet for this release at `0x40C578628ef75fe6e83FCD6DCE989f335D884bCE`, installing the same runtime bytecode as the MainNet deployment so the storage layout matches. + +`delegateProfileContractAddress` is the existing TestNet DelegateProfile contract (`0xd19ffB48a5C18B77c541D32c1B1ac2440c287774`), from which IIP-59 reads each delegate's voter-take portions when it freezes the era snapshot. + +Two IIP-59 parameters are left at their built-in defaults and do not appear in the YAML: `epochsPerRewardEra` (24) and `voterBudgetPerBlock` (256). + +> A delegate that has not configured `blockRewardPortion` / `epochRewardPortion` in the DelegateProfile contract is snapshotted at 100% commission, meaning its voters receive nothing through the on-chain path. Delegates intending to exercise IIP-59 on TestNet should set those fields before the fork height. + +## Changes + +### Feature + +- **IIP-59 on-chain voter reward distribution** (#4953) — moves voter reward computation and payout into the protocol. Rewards accrue per delegate and are drained at era boundaries (24 epochs), chunked across blocks with a per-block voter budget so a single block never carries the whole payout. Adds the `SetVoterRewardOptIn` staking action, per-candidate poll snapshots frozen at the era freeze height, an owner-index over contract-staking buckets, and a `DelegateVoterRewardsDistributed` event for off-chain indexers. +- **Export the distributed-log decoding API** (#4968) — exposes `Unpack`, `ABI`, and `Topic0` from the `distributedlog` package so indexers can decode `DelegateVoterRewardsDistributed` logs without vendoring the ABI. +- **`-stop-at-height` to cap startup replay** — bounds indexer catch-up at startup, which makes it practical to bring a node up at a specific height for debugging. +- **Dump the state write queue on a delta-state digest mismatch** — turns an opaque digest mismatch into an actionable diff. + +### Security + +- **BLS proof-of-possession at candidate register/update** (#4854) — the staking handler previously validated `blsPubKey` only for format and subgroup membership. Without a possession proof, IIP-52's planned `FastAggregateVerify` path is open to a rogue-key attack: a candidate could register `pk_rogue = g^x − Σ(other pubkeys)` and, once aggregation goes live, forge a 2/3+ quorum certificate with a single signature. Requiring the proof **before** aggregation activates closes the window in which un-attested pubkeys could be collected. Adds `ioctl account blssignpop` and threads the proof through `stake2register` / `stake2update`. +- **Serialize tracer `Stop` against `GetResult`** — the `debug_trace*` timeout watchdog called `tracer.Stop` from its own goroutine while the tracing goroutine called `GetResult`, with no synchronisation on the interruption reason. Fixed on MainNet-affecting code paths as well; no fork gate. + +### Fix + +- **`GetCommittedState` must not return a post-mutation value for prestate-absent keys** (#4869) — the contract-level committed-state cache was populated with post-mutation values for storage slots that did not exist in the pre-transaction trie, so EIP-2200 SSTORE dynamic gas misclassified dirty in-place writes as `SSTORE_RESET` and overcharged 2900 instead of 100 gas per hit. Gated on Zanzibar. +- **Restore fund-before-sentinel write order in `GrantEpochReward`.** +- **Rename the voter reward distribution event** (#4969). + +### Dependencies + +- `iotex-proto` moves to v0.6.12, which carries the `blsPop` field on `CandidateBasicInfo`. + +## Upgrade + +TestNet: + +```bash +export IOTEX_HOME=$HOME/iotex-var +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +docker pull iotex/iotex-core:v2.5.0 +``` + +Then restart your node against the `iotex/iotex-core:v2.5.0` image. Or non-interactively: + +```bash +bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0 +``` + +Confirm the node picked up the new genesis before the fork height — a node still on the old genesis will produce or accept a divergent block at 46850041. diff --git a/genesis_testnet.yaml b/genesis_testnet.yaml index d2c314e..fb44194 100644 --- a/genesis_testnet.yaml +++ b/genesis_testnet.yaml @@ -41,6 +41,7 @@ blockchain: yapHeight: 42819841 yapBetaHeight: 43361281 zanzibarHeight: 46850041 + autoDepositContractAddress: io1grzhsc5w7a07d6ple4kuaxylxdwcsj7w8r2zuu numCandidateDelegates: 36 numDelegates: 24 numSubEpochs: 15 @@ -67,6 +68,7 @@ poll: systemStakingContractV2Height: 26978830 systemStakingContractV3Address: io1phddfwuj6ht64lkvjyywqjc2e8t5ycez6c69d7 systemStakingContractV3Height: 31939788 + delegateProfileContractAddress: io16x0lkj99cx9h032p6vkpkxkzgsxzsam5t5sk5s staking: withdrawWaitingPeriod: "336h" rewarding: diff --git a/scripts/all_in_one_mainnet.sh b/scripts/all_in_one_mainnet.sh index 3975416..3742fa9 100644 --- a/scripts/all_in_one_mainnet.sh +++ b/scripts/all_in_one_mainnet.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 mkdir -p ~/iotex-var cd ~/iotex-var @@ -12,9 +12,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch # Download core snapshot (for delegate node) — use multi-threaded aria2c for speed, fall back to curl command -v aria2c >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y aria2) || true @@ -32,7 +32,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -40,9 +40,9 @@ docker run -d --restart on-failure --name iotex \ # --- Optional: gateway / API node only (not needed for a delegate / fullnode) --- # If you run this node as a gateway (add `-plugin=gateway` to the docker run above) so it # serves API / transaction-log queries, also apply the transaction-log patch shipped with -# v2.4.4 (see changelog/v2.4.4-release-note.md): +# v2.5.0 (see changelog/v2.5.0-release-note.md): # -# curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +# curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch # # then add the following to the chain: section of $IOTEX_HOME/etc/config.yaml and restart: # diff --git a/scripts/all_in_one_testnet.sh b/scripts/all_in_one_testnet.sh index 21eafb2..a7f3263 100644 --- a/scripts/all_in_one_testnet.sh +++ b/scripts/all_in_one_testnet.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 mkdir -p ~/iotex-var cd ~/iotex-var @@ -12,8 +12,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml # Download core snapshot (for delegate node) — use multi-threaded aria2c for speed, fall back to curl command -v aria2c >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y aria2) || true @@ -31,7 +31,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml From d53b4310ee8c0834eca690fe23444afc69325b78 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 17 Aug 2026 13:21:06 +0800 Subject: [PATCH 03/15] release: keep MainNet docs on v2.4.4 Zanzibar is scheduled on TestNet only, so v2.5.0 is a TestNet release and MainNet operators should not upgrade yet. Reverts the version bump in the MainNet-facing files -- README.md, README_CN.md, archive-node.md and all_in_one_mainnet.sh -- which also un-does an incorrect rewrite of README.md's transaction-log patch section, where the patch and its release note genuinely belong to v2.4.4. TestNet docs, the all_in_one_testnet.sh docker tags and the changelog stay on v2.5.0. CLAUDE.md and the release note now state the split explicitly. --- CLAUDE.md | 2 +- README.md | 26 +++++++++++++------------- README_CN.md | 22 +++++++++++----------- archive-node.md | 4 ++-- changelog/v2.5.0-release-note.md | 4 +++- scripts/all_in_one_mainnet.sh | 14 +++++++------- 6 files changed, 37 insertions(+), 35 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d0459d1..ea15645 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This is the **IoTeX Delegate Manual** repository - configuration and operational ## Version Alignment -This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0**. When iotex-core releases a new version: +This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0 on TestNet** and **v2.4.4 on MainNet** — v2.5.0 carries the Zanzibar hardfork, which is scheduled on TestNet only, so the MainNet docs deliberately still point at v2.4.4. When iotex-core releases a new version: 1. Update version references in README.md, config files, and scripts 2. Add a release note in `changelog/` 3. Create a PR but do NOT merge until the final release is tagged in iotex-core diff --git a/README.md b/README.md index 82379b9..2256f50 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Here are the software versions we use: -- MainNet: v2.5.0 +- MainNet: v2.4.4 ## Join TestNet To start and run a testnet node, please click [**Join Testnet**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_testnet.md) @@ -33,7 +33,7 @@ This is the recommended way to start an IoTeX node 1. Pull the docker image: ``` -docker pull iotex/iotex-core:v2.5.0 +docker pull iotex/iotex-core:v2.4.4 ``` 2. Set the environment with the following commands: @@ -48,9 +48,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch ``` 3. Edit `$IOTEX_HOME/etc/config.yaml`, look for `externalHost` and `producerPrivKey`, uncomment the lines and fill in your external IP and private key. If you leave `producerPrivKey` empty, your node will be assgined with a random key. @@ -105,7 +105,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.4.4 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -126,7 +126,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.4.4 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -150,7 +150,7 @@ Same as [Join MainNet](#mainnet) step 2 ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0 +git checkout v2.4.4 // optional export GOPROXY=https://goproxy.io @@ -312,7 +312,7 @@ The upgrade script supports a non-interactive mode for use with AI agents, CI/CD |---|---| | `--auto` | Non-interactive mode, skip all prompts | | `--home=/path` | Set `$IOTEX_HOME` directory | -| `--version=v2.5.0` | Target version (default: latest release) | +| `--version=v2.4.4` | Target version (default: latest release) | | `--force` | Reinstall even if already running the same version | | `--snapshot` | Download blockchain snapshot (recommended for fresh install) | | `--monitor` | Enable monitoring | @@ -326,7 +326,7 @@ bash setup_fullnode.sh --auto --home=/path/to/iotex-var --snapshot bash setup_fullnode.sh --auto --home=/path/to/iotex-var # Upgrade to a specific version -bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0 +bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.4.4 ``` **Notes:** @@ -339,12 +339,12 @@ Node with gateway plugin enabled will perform extra indexing to serve API reques ### Transaction-log patch (gateway / API / archive nodes) -Nodes that **serve transaction-log queries** (`GetTransactionLogByActionHash`, `GetTransactionLogByBlockHeight`) should apply the transaction-log patch shipped with v2.5.0, which corrects a set of historical in-contract-transfer records. Delegate / fullnodes that do not serve these queries do not need it. +Nodes that **serve transaction-log queries** (`GetTransactionLogByActionHash`, `GetTransactionLogByBlockHeight`) should apply the transaction-log patch shipped with v2.4.4, which corrects a set of historical in-contract-transfer records. Delegate / fullnodes that do not serve these queries do not need it. 1. Download the patch file into the node's data directory and verify its checksum: ``` -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch echo "dee9406afc991d5439ab4c27bc85fa658e1fb241ddabe1cc5fef18f27d728986 $IOTEX_HOME/data/txlog.db.patch" | sha256sum -c ``` @@ -357,7 +357,7 @@ chain: 3. Restart the node. -> **Important:** only set `patchTransactionLogPath` if the patch file exists at that path — a node configured with a missing patch file will **fail to start**. The patch is read-only and does not change balances, receipts, or block hashes. See the [v2.5.0 release note](changelog/v2.5.0-release-note.md) for details. +> **Important:** only set `patchTransactionLogPath` if the patch file exists at that path — a node configured with a missing patch file will **fail to start**. The patch is read-only and does not change balances, receipts, or block hashes. See the [v2.4.4 release note](changelog/v2.4.4-release-note.md) for details. ## Q&A Please refer [here](https://github.com/iotexproject/iotex-bootstrap/wiki/Q&A) for Q&A. diff --git a/README_CN.md b/README_CN.md index 8dead9c..06afa72 100644 --- a/README_CN.md +++ b/README_CN.md @@ -18,7 +18,7 @@ 以下是当前我们使用的软件版本: -- 主网:v2.5.0 +- 主网:v2.4.4 ## 加入测试网 如果你要启动节点加入测试网,请点击[**加入测试网**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_CN_testnet.md) @@ -32,7 +32,7 @@ 1. 提取(pull) docker镜像 ``` -docker pull iotex/iotex-core:v2.5.0 +docker pull iotex/iotex-core:v2.4.4 ``` 2. 使用以下命令设置运行环境 @@ -47,9 +47,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch ``` 3. 编辑 `$IOTEX_HOME/etc/config.yaml`, 查找 `externalHost` 和 `producerPrivKey`, 取消注释行并填写您的外部 IP 和私钥。如果`producerPrivKey`放空,你的节点将被分配一个随机密钥。 @@ -103,7 +103,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.4.4 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -121,7 +121,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.4.4 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -141,7 +141,7 @@ docker run -d --restart on-failure --name iotex \ ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0 +git checkout v2.4.4 // optional export GOPROXY=https://goproxy.io @@ -281,12 +281,12 @@ bash <(curl -s https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/ma ### 交易日志补丁(网关 / API / 归档节点) -**对外提供交易日志查询**(`GetTransactionLogByActionHash`、`GetTransactionLogByBlockHeight`)的节点应安装 v2.5.0 引入的交易日志补丁,它会修正一组历史合约内转账记录。不对外提供这些查询的 delegate / 全节点无需安装。 +**对外提供交易日志查询**(`GetTransactionLogByActionHash`、`GetTransactionLogByBlockHeight`)的节点应安装 v2.4.4 引入的交易日志补丁,它会修正一组历史合约内转账记录。不对外提供这些查询的 delegate / 全节点无需安装。 1. 将补丁文件下载到节点的 data 目录,并校验其 checksum: ``` -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch echo "dee9406afc991d5439ab4c27bc85fa658e1fb241ddabe1cc5fef18f27d728986 $IOTEX_HOME/data/txlog.db.patch" | sha256sum -c ``` @@ -299,7 +299,7 @@ chain: 3. 重启节点。 -> **重要:** 仅当补丁文件确实存在于该路径时才设置 `patchTransactionLogPath` —— 若配置了该路径但文件缺失,节点将**无法启动**。该补丁为只读,不会改变余额、收据或区块哈希。详见 [v2.5.0 release note](changelog/v2.5.0-release-note.md)。 +> **重要:** 仅当补丁文件确实存在于该路径时才设置 `patchTransactionLogPath` —— 若配置了该路径但文件缺失,节点将**无法启动**。该补丁为只读,不会改变余额、收据或区块哈希。详见 [v2.4.4 release note](changelog/v2.4.4-release-note.md)。 ## 常见问题 diff --git a/archive-node.md b/archive-node.md index 363157c..f2fadec 100644 --- a/archive-node.md +++ b/archive-node.md @@ -151,7 +151,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/iotex-archive/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.4.4 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -194,7 +194,7 @@ git clone https://github.com/iotexproject/iotex-core.git cd iotex-core #checkout the code branch for archive node -git checkout v2.5.0 +git checkout v2.4.4 #build binary make build diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index 945e96e..3e1b5e3 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -4,7 +4,9 @@ v2.5.0 is a **required** release for TestNet delegates. It introduces the **Zanzibar** hardfork, which activates IIP-59 on-chain voter reward distribution together with three correctness/security fixes. -Zanzibar is scheduled on **TestNet at block 46850041** (roughly three days after this release). It is **not scheduled on MainNet** — `genesis_mainnet.yaml` carries no `zanzibarHeight`, so MainNet nodes running v2.5.0 behave exactly as they did on v2.4.4. MainNet operators may upgrade at their convenience; TestNet delegates **must** upgrade before block 46850041 or they will fork off the network. +Zanzibar is scheduled on **TestNet at block 46850041** (roughly three days after this release). It is **not scheduled on MainNet**. + +v2.5.0 is therefore a **TestNet-only release**: the MainNet docs in this repository deliberately stay on v2.4.4, and MainNet operators should not upgrade yet. TestNet delegates **must** upgrade before block 46850041 or they will fork off the network. Both `genesis_testnet.yaml` and `config_testnet.yaml` must be refreshed as part of this upgrade — the genesis file carries the new activation height and two new contract addresses. diff --git a/scripts/all_in_one_mainnet.sh b/scripts/all_in_one_mainnet.sh index 3742fa9..3975416 100644 --- a/scripts/all_in_one_mainnet.sh +++ b/scripts/all_in_one_mainnet.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -docker pull iotex/iotex-core:v2.5.0 +docker pull iotex/iotex-core:v2.4.4 mkdir -p ~/iotex-var cd ~/iotex-var @@ -12,9 +12,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch # Download core snapshot (for delegate node) — use multi-threaded aria2c for speed, fall back to curl command -v aria2c >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y aria2) || true @@ -32,7 +32,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.4.4 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -40,9 +40,9 @@ docker run -d --restart on-failure --name iotex \ # --- Optional: gateway / API node only (not needed for a delegate / fullnode) --- # If you run this node as a gateway (add `-plugin=gateway` to the docker run above) so it # serves API / transaction-log queries, also apply the transaction-log patch shipped with -# v2.5.0 (see changelog/v2.5.0-release-note.md): +# v2.4.4 (see changelog/v2.4.4-release-note.md): # -# curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +# curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch # # then add the following to the chain: section of $IOTEX_HOME/etc/config.yaml and restart: # From 1ada785c18d2eba0f6216b6621b79d3b11c3f75a Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 17 Aug 2026 13:25:31 +0800 Subject: [PATCH 04/15] docs(changelog): spell out what TestNet delegates must do before Zanzibar IIP-59 only pays out for candidates with VoterRewardOnchainOptIn set. The fork-block migration sets it automatically for candidates whose reward address is one of hermesRewardVaultAddresses, but genesis_testnet.yaml does not override that list, so it inherits the two MainNet Hermes vaults -- and every TestNet delegate sampled uses its own address as its reward address. The migration therefore matches nobody on TestNet and delegates have to send SetVoterRewardOptIn themselves. Paired with the existing note about DelegateProfile commission portions, since either one being unset leaves the distribution path with nothing to pay out. --- changelog/v2.5.0-release-note.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index 3e1b5e3..4c711c3 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -44,7 +44,13 @@ poll: Two IIP-59 parameters are left at their built-in defaults and do not appear in the YAML: `epochsPerRewardEra` (24) and `voterBudgetPerBlock` (256). -> A delegate that has not configured `blockRewardPortion` / `epochRewardPortion` in the DelegateProfile contract is snapshotted at 100% commission, meaning its voters receive nothing through the on-chain path. Delegates intending to exercise IIP-59 on TestNet should set those fields before the fork height. +### TestNet delegates: two things to do before the fork + +**1. Opt in.** IIP-59 only distributes for candidates whose `VoterRewardOnchainOptIn` flag is set. At the fork block the protocol auto-opts-in any candidate whose reward address is one of `hermesRewardVaultAddresses` — a convenience for MainNet delegates who route rewards through a Hermes vault. On TestNet, delegates set their reward address to their own address, so **this migration matches nobody** and no candidate is opted in automatically. TestNet delegates who want on-chain distribution must send the new `SetVoterRewardOptIn` staking action themselves. + +**2. Set the commission portions.** A delegate that has not configured `blockRewardPortion` / `epochRewardPortion` in the DelegateProfile contract is snapshotted at 100% commission, so its voters receive nothing through the on-chain path. + +Without both, Zanzibar activates but the voter distribution path has nothing to pay out. That is a safe state — no rewards are lost, they simply keep flowing through the existing off-chain path — but it also means IIP-59 is not actually being exercised. ## Changes From 9c67e4db0b5eb14dc9df287c851667f11b67e573 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 18 Aug 2026 09:46:22 +0800 Subject: [PATCH 05/15] docs(changelog): record the blacklist removal activating at Zanzibar Fifth change on the fork. Notes that the height moved out of node config into genesis, so blackListRemovalHeight in config.yaml is no longer read. --- changelog/v2.5.0-release-note.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index 4c711c3..1afef14 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -19,12 +19,13 @@ Both `genesis_testnet.yaml` and `config_testnet.yaml` must be refreshed as part | TestNet | 46850041 | ~3 days after release | | MainNet | not scheduled | — | -Zanzibar activates four changes at once: +Zanzibar activates five changes at once: 1. **IIP-59 on-chain voter reward distribution** — voter rewards are computed and credited by the protocol at era boundaries instead of by the off-chain Hermes service. 2. **BLS proof-of-possession at candidate register/update** — closes a rogue-key aggregate-forgery window ahead of IIP-52's signature aggregation. 3. **In-contract transfer log topic fix.** 4. **`GetCommittedState` prestate fix** — storage slots absent from the pre-transaction trie no longer report a post-mutation value, correcting EIP-2200 SSTORE gas accounting. +5. **Blacklist removal** — 13 of the 29 blacklisted accounts stop being treated as blacklisted. No effect on TestNet, whose `config_testnet.yaml` sets an empty `blackList`. ### New genesis fields @@ -71,6 +72,7 @@ Without both, Zanzibar activates but the voter distribution path has nothing to - **`GetCommittedState` must not return a post-mutation value for prestate-absent keys** (#4869) — the contract-level committed-state cache was populated with post-mutation values for storage slots that did not exist in the pre-transaction trie, so EIP-2200 SSTORE dynamic gas misclassified dirty in-place writes as `SSTORE_RESET` and overcharged 2900 instead of 100 gas per hit. Gated on Zanzibar. - **Restore fund-before-sentinel write order in `GrantEpochReward`.** - **Rename the voter reward distribution event** (#4969). +- **Activate the actpool blacklist removal at Zanzibar** (#4861) — the removal list added in #4861 shipped with its height defaulting to "never", so it has not been in effect. It is now driven by the genesis fork height rather than a node-config field: the blacklist predicate is wired into the execution protocol and consulted by the EIP-7702 authorization check, so an operator-settable height was a way for two nodes to validate the same block differently. `blackListRemovalHeight` is no longer read from `config.yaml`. ### Dependencies From 68a401dd4f7137a01b6301c23d9f41b88d8fd94c Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 18 Aug 2026 18:49:53 +0800 Subject: [PATCH 06/15] docs(changelog): record the optional candidate BLS key Sixth change on the fork. Spells out which ABI entry a BLS-less registration uses, since the amount travels in a different field there. --- changelog/v2.5.0-release-note.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index 1afef14..9374728 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -19,13 +19,14 @@ Both `genesis_testnet.yaml` and `config_testnet.yaml` must be refreshed as part | TestNet | 46850041 | ~3 days after release | | MainNet | not scheduled | — | -Zanzibar activates five changes at once: +Zanzibar activates six changes at once: 1. **IIP-59 on-chain voter reward distribution** — voter rewards are computed and credited by the protocol at era boundaries instead of by the off-chain Hermes service. 2. **BLS proof-of-possession at candidate register/update** — closes a rogue-key aggregate-forgery window ahead of IIP-52's signature aggregation. 3. **In-contract transfer log topic fix.** 4. **`GetCommittedState` prestate fix** — storage slots absent from the pre-transaction trie no longer report a post-mutation value, correcting EIP-2200 SSTORE gas accounting. 5. **Blacklist removal** — 13 of the 29 blacklisted accounts stop being treated as blacklisted. No effect on TestNet, whose `config_testnet.yaml` sets an empty `blackList`. +6. **Candidate BLS key becomes optional** — `candidateRegister` and `candidateUpdate` no longer require `blsPubKey`. ### New genesis fields @@ -72,6 +73,7 @@ Without both, Zanzibar activates but the voter distribution path has nothing to - **`GetCommittedState` must not return a post-mutation value for prestate-absent keys** (#4869) — the contract-level committed-state cache was populated with post-mutation values for storage slots that did not exist in the pre-transaction trie, so EIP-2200 SSTORE dynamic gas misclassified dirty in-place writes as `SSTORE_RESET` and overcharged 2900 instead of 100 gas per hit. Gated on Zanzibar. - **Restore fund-before-sentinel write order in `GrantEpochReward`.** - **Rename the voter reward distribution event** (#4969). +- **Candidate BLS public key is optional from Zanzibar** — Xingu made `blsPubKey` mandatory on candidate register and update. Nothing consumes it until IIP-52 signature aggregation activates, so it is optional again. A registration that supplies a key keeps using the value-carrying `candidateRegisterWithBLSAndPoP` ABI; one that omits it goes back through the legacy `candidateRegister` entry, whose amount travels in the ABI parameter rather than `msg.value`. An update that omits the key leaves any previously registered key untouched. Supplying a key without its proof-of-possession is still rejected — by the handler, as `ErrUnauthorizedOperator` on the receipt. - **Activate the actpool blacklist removal at Zanzibar** (#4861) — the removal list added in #4861 shipped with its height defaulting to "never", so it has not been in effect. It is now driven by the genesis fork height rather than a node-config field: the blacklist predicate is wired into the execution protocol and consulted by the EIP-7702 authorization check, so an operator-settable height was a way for two nodes to validate the same block differently. `blackListRemovalHeight` is no longer read from `config.yaml`. ### Dependencies From 9a30f25fa2e61ff9c712e987e578b5e45043df74 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 20 Aug 2026 06:54:06 +0800 Subject: [PATCH 07/15] docs(changelog): correct the opt-in survey and record the carried-over fixes The opt-in section claimed the fork-block migration "matches nobody" on TestNet. That was written from a four-delegate sample and is wrong: three of the 35 delegates route rewards through a Hermes vault and will be opted in automatically. Replaced with the full survey -- 3 vault-routed, 2 with commission configured, 1 with both -- which makes the same point without overstating it, plus the ioctl commands to check any delegate. Also records what landed in v2.5.0 after this note was first written: the three fixes carried over from master (#4910 SELFDESTRUCT transaction log, #4921 sender eviction on a mint panic, #4937 block-level gasUsed), the abandoned-drain terminal state, and the new ioctl surface. Notes that the DelegateProfile write must come from the candidate's identifier address, since sending it from the operator address writes a record nothing reads. --- changelog/v2.5.0-release-note.md | 35 ++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index 9374728..fb2cd63 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -48,12 +48,32 @@ Two IIP-59 parameters are left at their built-in defaults and do not appear in t ### TestNet delegates: two things to do before the fork -**1. Opt in.** IIP-59 only distributes for candidates whose `VoterRewardOnchainOptIn` flag is set. At the fork block the protocol auto-opts-in any candidate whose reward address is one of `hermesRewardVaultAddresses` — a convenience for MainNet delegates who route rewards through a Hermes vault. On TestNet, delegates set their reward address to their own address, so **this migration matches nobody** and no candidate is opted in automatically. TestNet delegates who want on-chain distribution must send the new `SetVoterRewardOptIn` staking action themselves. +**1. Opt in.** IIP-59 only distributes for candidates whose `VoterRewardOnchainOptIn` flag is set. At the fork block the protocol auto-opts-in any candidate whose reward address is one of `hermesRewardVaultAddresses`, a convenience for delegates who route rewards through a Hermes vault. Everyone else must send the new `SetVoterRewardOptIn` staking action themselves: -**2. Set the commission portions.** A delegate that has not configured `blockRewardPortion` / `epochRewardPortion` in the DelegateProfile contract is snapshotted at 100% commission, so its voters receive nothing through the on-chain path. +```bash +ioctl stake2 voterrewardoptin -s +``` + +**2. Set the commission portions.** A delegate that has not configured `blockRewardPortion` / `epochRewardPortion` in the DelegateProfile contract is snapshotted at 100% commission, so its voters receive nothing through the on-chain path. The profile is keyed by the candidate's identifier address, so the transaction has to be sent from it — sending from the operator address writes a record nothing reads. Without both, Zanzibar activates but the voter distribution path has nothing to pay out. That is a safe state — no rewards are lost, they simply keep flowing through the existing off-chain path — but it also means IIP-59 is not actually being exercised. +Surveying the 35 TestNet delegates at the time of writing: + +| | count | +|---|---| +| reward address is a Hermes vault (auto-opted-in at the fork) | 3 | +| `blockRewardPortion` / `epochRewardPortion` configured | 2 | +| both, i.e. paying voters with no further action | **1** | + +So the fork will activate with essentially nothing to distribute unless delegates act. To check any single delegate: + +```bash +ioctl node reward payout # opted in? +ioctl node reward snapshot # commission frozen for the era +ioctl node reward pending # pool waiting to be paid +``` + ## Changes ### Feature @@ -74,8 +94,19 @@ Without both, Zanzibar activates but the voter distribution path has nothing to - **Restore fund-before-sentinel write order in `GrantEpochReward`.** - **Rename the voter reward distribution event** (#4969). - **Candidate BLS public key is optional from Zanzibar** — Xingu made `blsPubKey` mandatory on candidate register and update. Nothing consumes it until IIP-52 signature aggregation activates, so it is optional again. A registration that supplies a key keeps using the value-carrying `candidateRegisterWithBLSAndPoP` ABI; one that omits it goes back through the legacy `candidateRegister` entry, whose amount travels in the ABI parameter rather than `msg.value`. An update that omits the key leaves any previously registered key untouched. Supplying a key without its proof-of-possession is still rejected — by the handler, as `ErrUnauthorizedOperator` on the receipt. +- **Correct the SELFDESTRUCT transaction-log amount** (#4910) — `generateSelfDestructTransferLog` stored the mutable `lastAddBalanceAmount` pointer directly into the `IN_CONTRACT_TRANSFER` log. That pointer is rewritten in place by the gas-deposit refund performed right after the EVM returns, so the recorded self-destruct log was retroactively overwritten with the refund amount. Balances, receipts and state roots are unaffected — transaction logs are not part of any root — but anything reconstructing balances from transaction logs (indexers, wallets, exchanges) was misled. Also ships `txlogpatch --correct-amount` to repair already-recorded logs. +- **Evict the sender when an action panics during minting** (#4921) — a panic in a single pending action unwound past the sender-eviction logic and was only caught by the mint goroutine's top-level recover, so the whole draft was discarded without removing the offending action from the pool and the same action was picked again on every subsequent attempt. Now recovered around the single-action call and routed through normal error handling, turning a run of failed drafts into one lost draft. +- **Populate block-level `gasUsed` from fetched receipts** (#4937) — `eth_getBlockByNumber` and friends returned `0x0` for historical and archive reads, because the block loaded from the DAO carries no receipts and the aggregate fell back to that empty list. +- **Retire a drain whose copy-on-write window was superseded** — a drain frozen against a window that a later freeze replaced can never finish, but the cursor was left merely incomplete, so a chunk grant was emitted on every subsequent block and failed identically until the next era boundary. The cursor now reaches a terminal `abandoned` state and emits one `DRAIN_ABANDONED` reward log, so an indexer can tell "gave up" from "still retrying" instead of seeing an unbounded run of failure receipts. - **Activate the actpool blacklist removal at Zanzibar** (#4861) — the removal list added in #4861 shipped with its height defaulting to "never", so it has not been in effect. It is now driven by the genesis fork height rather than a node-config field: the blacklist predicate is wired into the execution protocol and consulted by the EIP-7702 authorization check, so an operator-settable height was a way for two nodes to validate the same block differently. `blackListRemovalHeight` is no longer read from `config.yaml`. +### ioctl + +- `ioctl stake2 voterrewardoptin` — opt a candidate into on-chain voter reward distribution. +- `ioctl action voterrewarddestination [ADDR] [--reset]` — route a voter's rewards to another address. +- `ioctl node reward pending|delegates|distribution|snapshot|payout|destination` — read the IIP-59 state. `snapshot` and `payout` call out the two configurations that silently pay nothing. +- `ioctl stake2 register --no-bls` — register a candidate without a BLS key, now that the key is optional. + ### Dependencies - `iotex-proto` moves to v0.6.12, which carries the `blsPop` field on `CandidateBasicInfo`. From 0e67e4e045c7b919274aab7ce04b8566cacc29c3 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 20 Aug 2026 07:02:35 +0800 Subject: [PATCH 08/15] release: move Zanzibar to 46880641 and point TestNet at v2.5.0-rc0 Height moves from 46850041 to 46880641, an era's first epoch rather than a point 12 epochs into one. Both are safe -- the constraint that matters is leaving enough room before the settling epoch, and 46850041 had 12 epochs of it -- but starting an era means the first settlement Zanzibar takes part in is one it has been active for from the beginning, with the full 23 epochs of margin. height 46880641 epoch aligned (h-1) % 360 == 0, epoch 130225 era start 130225 % 24 == 1 settles at epoch 130248, 23 epochs later ETA 2026-08-21 ~10:00 CST Note the era's *first* epoch is epochNum % 24 == 1, not == 0: the latter is where IsEraBoundary fires, which is the epoch the era settles *at the end of*. Scheduling activation there is the one case that loses that era's rewards, because the freeze it needs happens ~1.5 epochs earlier, before the fork is live. TestNet docs, the all_in_one_testnet script and the release note's upgrade steps now name v2.5.0-rc0, which is what is tagged and what delegates will run; v2.5.0 proper is tagged after the fork is observed. MainNet docs stay on v2.4.4. --- CLAUDE.md | 6 +++--- README_CN_testnet.md | 14 +++++++------- README_testnet.md | 14 +++++++------- changelog/v2.5.0-release-note.md | 25 +++++++++++++------------ genesis_testnet.yaml | 2 +- scripts/all_in_one_testnet.sh | 8 ++++---- 6 files changed, 35 insertions(+), 34 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index ea15645..c56de99 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This is the **IoTeX Delegate Manual** repository - configuration and operational ## Version Alignment -This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0 on TestNet** and **v2.4.4 on MainNet** — v2.5.0 carries the Zanzibar hardfork, which is scheduled on TestNet only, so the MainNet docs deliberately still point at v2.4.4. When iotex-core releases a new version: +This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0-rc0 on TestNet** and **v2.4.4 on MainNet** — v2.5.0-rc0 carries the Zanzibar hardfork, which is scheduled on TestNet only, so the MainNet docs deliberately still point at v2.4.4. When iotex-core releases a new version: 1. Update version references in README.md, config files, and scripts 2. Add a release note in `changelog/` 3. Create a PR but do NOT merge until the final release is tagged in iotex-core @@ -38,7 +38,7 @@ See `release_flow.md` for the complete release process. ## Common Tasks ### Update for a new iotex-core release -1. Update `version` references in README.md (search for `v2.5.0`) +1. Update `version` references in README.md (search for `v2.5.0-rc0`) 2. Update docker image tags in `scripts/all_in_one_mainnet.sh` and `scripts/all_in_one_testnet.sh` 3. Add release note in `changelog/vX.Y.Z-release-note.md` 4. Update `config_mainnet.yaml` and `config_testnet.yaml` if needed @@ -56,7 +56,7 @@ bash <(curl -s https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/ma ### Non-interactive upgrade (AI agent / CI) ```bash bash setup_fullnode.sh --auto --home=/path/to/iotex-var -bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0 +bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0-rc0 bash setup_fullnode.sh --auto --home=/path/to/iotex-var --force # reinstall same version ``` Flags: `--auto` (skip prompts), `--home=` (IOTEX_HOME), `--version=` (target version), `--force` (bypass same-version check), `--monitor` (enable monitoring), `plugin=gateway` (enable gateway). diff --git a/README_CN_testnet.md b/README_CN_testnet.md index 1ea5cc3..3e0bbd1 100644 --- a/README_CN_testnet.md +++ b/README_CN_testnet.md @@ -17,7 +17,7 @@ 以下是当前我们使用的软件版本: -- 测试网:v2.5.0 +- 测试网:v2.5.0-rc0 **Note** 如果你要启动节点加入主网,请点击[**加入主网**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_CN.md) @@ -31,7 +31,7 @@ 1. 提取(pull) docker镜像 ``` -docker pull iotex/iotex-core:v2.5.0 +docker pull iotex/iotex-core:v2.5.0-rc0 ``` 2. 使用以下命令设置运行环境 @@ -46,8 +46,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. 编辑 `$IOTEX_HOME/etc/config.yaml`, 查找 `externalHost` 和 `producerPrivKey`, 取消注释行并填写您的外部 IP 和私钥。如果`producerPrivKey`放空,你的节点将被分配一个随机密钥。 @@ -100,7 +100,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.5.0-rc0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -118,7 +118,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.5.0-rc0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -138,7 +138,7 @@ docker run -d --restart on-failure --name iotex \ ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0 +git checkout v2.5.0-rc0 // optional export GOPROXY=https://goproxy.io diff --git a/README_testnet.md b/README_testnet.md index d7fca20..feddb31 100644 --- a/README_testnet.md +++ b/README_testnet.md @@ -18,7 +18,7 @@ Here are the software versions we use: -- TestNet: v2.5.0 +- TestNet: v2.5.0-rc0 **Note** To start and run a mainnet node, please click [**Join Mainnet**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README.md) @@ -31,7 +31,7 @@ This is the recommended way to start an IoTeX node 1. Pull the docker image: ``` -docker pull iotex/iotex-core:v2.5.0 +docker pull iotex/iotex-core:v2.5.0-rc0 ``` 2. Set the environment with the following commands: @@ -46,8 +46,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. Edit `$IOTEX_HOME/etc/config.yaml`, look for `externalHost` and `producerPrivKey`, uncomment the lines and fill in your external IP and private key. If you leave `producerPrivKey` empty, your node will be assgined with a random key. @@ -101,7 +101,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.5.0-rc0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -121,7 +121,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.5.0-rc0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -142,7 +142,7 @@ Same as [Join TestNet](#testnet) step 2 ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0 +git checkout v2.5.0-rc0 // optional export GOPROXY=https://goproxy.io diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index fb2cd63..ffd89e7 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -4,19 +4,19 @@ v2.5.0 is a **required** release for TestNet delegates. It introduces the **Zanzibar** hardfork, which activates IIP-59 on-chain voter reward distribution together with three correctness/security fixes. -Zanzibar is scheduled on **TestNet at block 46850041** (roughly three days after this release). It is **not scheduled on MainNet**. +Zanzibar is scheduled on **TestNet at block 46880641** (2026-08-21, roughly a day after this release). It is **not scheduled on MainNet**. -v2.5.0 is therefore a **TestNet-only release**: the MainNet docs in this repository deliberately stay on v2.4.4, and MainNet operators should not upgrade yet. TestNet delegates **must** upgrade before block 46850041 or they will fork off the network. +v2.5.0 is therefore a **TestNet-only release**: the MainNet docs in this repository deliberately stay on v2.4.4, and MainNet operators should not upgrade yet. TestNet delegates **must** upgrade before block 46880641 or they will fork off the network. Both `genesis_testnet.yaml` and `config_testnet.yaml` must be refreshed as part of this upgrade — the genesis file carries the new activation height and two new contract addresses. -> **TestNet delegates:** the genesis file changed. Re-download `genesis_testnet.yaml` when you upgrade; keeping the old one will fork your node at 46850041. +> **TestNet delegates:** the genesis file changed. Re-download `genesis_testnet.yaml` when you upgrade; keeping the old one will fork your node at 46880641. ## Hardfork: Zanzibar | Network | Height | Approx. date | |---------|--------|--------------| -| TestNet | 46850041 | ~3 days after release | +| TestNet | 46880641 | 2026-08-21 ~10:00 CST | | MainNet | not scheduled | — | Zanzibar activates six changes at once: @@ -34,7 +34,7 @@ Zanzibar activates six changes at once: ```yaml blockchain: - zanzibarHeight: 46850041 + zanzibarHeight: 46880641 autoDepositContractAddress: io1grzhsc5w7a07d6ple4kuaxylxdwcsj7w8r2zuu poll: delegateProfileContractAddress: io16x0lkj99cx9h032p6vkpkxkzgsxzsam5t5sk5s @@ -113,19 +113,20 @@ ioctl node reward pending # pool waiting to be paid ## Upgrade -TestNet: +The TestNet rollout runs the **`v2.5.0-rc0`** pre-release; `v2.5.0` proper is +tagged once the fork has been observed on TestNet. ```bash export IOTEX_HOME=$HOME/iotex-var -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml -docker pull iotex/iotex-core:v2.5.0 +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +docker pull iotex/iotex-core:v2.5.0-rc0 ``` -Then restart your node against the `iotex/iotex-core:v2.5.0` image. Or non-interactively: +Then restart your node against the `iotex/iotex-core:v2.5.0-rc0` image. Or non-interactively: ```bash -bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0 +bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0-rc0 ``` -Confirm the node picked up the new genesis before the fork height — a node still on the old genesis will produce or accept a divergent block at 46850041. +Confirm the node picked up the new genesis before the fork height — a node still on the old genesis will produce or accept a divergent block at 46880641. The height moved from an earlier draft, so re-download rather than assuming yours is current. diff --git a/genesis_testnet.yaml b/genesis_testnet.yaml index fb44194..b041006 100644 --- a/genesis_testnet.yaml +++ b/genesis_testnet.yaml @@ -40,7 +40,7 @@ blockchain: xinguBetaHeight: 36826561 yapHeight: 42819841 yapBetaHeight: 43361281 - zanzibarHeight: 46850041 + zanzibarHeight: 46880641 autoDepositContractAddress: io1grzhsc5w7a07d6ple4kuaxylxdwcsj7w8r2zuu numCandidateDelegates: 36 numDelegates: 24 diff --git a/scripts/all_in_one_testnet.sh b/scripts/all_in_one_testnet.sh index a7f3263..9363b82 100644 --- a/scripts/all_in_one_testnet.sh +++ b/scripts/all_in_one_testnet.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -docker pull iotex/iotex-core:v2.5.0 +docker pull iotex/iotex-core:v2.5.0-rc0 mkdir -p ~/iotex-var cd ~/iotex-var @@ -12,8 +12,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml # Download core snapshot (for delegate node) — use multi-threaded aria2c for speed, fall back to curl command -v aria2c >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y aria2) || true @@ -31,7 +31,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0 \ + iotex/iotex-core:v2.5.0-rc0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml From 02b047649e769d79a223a2b84dcf7315686070c4 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 20 Aug 2026 08:31:27 +0800 Subject: [PATCH 09/15] fix(testnet): point Zanzibar at freshly deployed profile and auto-deposit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both addresses previously named deployments whose owner keys are not available to this release. autoDepositContractAddress named a deployment whose `owner()` is the zero address — its bytecode carries pause()/unpause()/transferOwnership, so those are permanently uncallable. It also differed from the address iotex-hub writes compound registrations to, which would have left the protocol reading one contract while users registered against another: compound preferences silently ignored, rewards credited to unclaimed balance instead. The replacements were deployed by replaying the mainnet creation transactions, so both runtimes are byte-identical to mainnet's and the constructors ran normally, leaving the owner set. Verified on chain: owner is the release key, paused is false, DelegateProfile has the three reward-portion fields registered against the existing PermyriadVerifier, and an arbitrary address can publish portions. The three delegates holding published portions on the old DelegateProfile were migrated across and their values reconciled value by value. delegateProfile io19l8qpk08rw0jr4vwguyufva9w4t6aq75q2kt90 0x2fcE00d9E71B9f21D58e4709c4B3A57557ae83D4 autoDeposit io1pvlpc02xft2va4f38ae2nvgqglcxtfytez75c4 0x0b3e1C3d464AD4CED5313f72A9b10047f065A48B Co-Authored-By: Claude Opus 5 (1M context) --- genesis_testnet.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/genesis_testnet.yaml b/genesis_testnet.yaml index b041006..e3148ba 100644 --- a/genesis_testnet.yaml +++ b/genesis_testnet.yaml @@ -41,7 +41,7 @@ blockchain: yapHeight: 42819841 yapBetaHeight: 43361281 zanzibarHeight: 46880641 - autoDepositContractAddress: io1grzhsc5w7a07d6ple4kuaxylxdwcsj7w8r2zuu + autoDepositContractAddress: io1pvlpc02xft2va4f38ae2nvgqglcxtfytez75c4 numCandidateDelegates: 36 numDelegates: 24 numSubEpochs: 15 @@ -68,7 +68,7 @@ poll: systemStakingContractV2Height: 26978830 systemStakingContractV3Address: io1phddfwuj6ht64lkvjyywqjc2e8t5ycez6c69d7 systemStakingContractV3Height: 31939788 - delegateProfileContractAddress: io16x0lkj99cx9h032p6vkpkxkzgsxzsam5t5sk5s + delegateProfileContractAddress: io19l8qpk08rw0jr4vwguyufva9w4t6aq75q2kt90 staking: withdrawWaitingPeriod: "336h" rewarding: From d098dca574cd4fba7b7981fb459659e7d2a334e7 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 20 Aug 2026 08:46:32 +0800 Subject: [PATCH 10/15] docs: sync the release note with the redeployed contracts, announce the fork Three things were out of sync with genesis_testnet.yaml. The contract addresses. 02b0476 replaced both deployments; the note still named the old ones, including in a yaml block operators might copy. It now carries both the bech32 and 0x forms and explains what changed: replaying the MainNet creation transactions keeps each runtime byte-identical -- which is what AutoDepositRegister needs, since IIP-59 reads its storage slots directly -- while letting the constructors run, so the owner is set. It also records that the AutoDeposit address is the one iotex-hub writes to, which is the property the previous deployment lacked. A stale claim. The note told operators to refresh config_testnet.yaml as well. Only the genesis changed. The READMEs. README_testnet.md and README_CN_testnet.md -- the docs a delegate actually follows -- said nothing about the fork. Bumping the image tag there was not enough: an operator upgrading an existing node has no reason to re-download the genesis, and nothing told them there is a deadline. Both now carry a notice above the body with the height, the date, the requirement to re-download the genesis specifically (it changed twice, so a stale copy is plausible), and the two ioctl steps for IIP-59. Drops the "two things to do before the fork" section: the ioctl section below already covers opt-in and the reward-portion setup, and the survey numbers in it were a snapshot that would go stale before the fork. --- README_CN_testnet.md | 13 +++++++++ README_testnet.md | 16 ++++++++++ changelog/v2.5.0-release-note.md | 50 ++++++++++++-------------------- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/README_CN_testnet.md b/README_CN_testnet.md index 3e0bbd1..87b87ed 100644 --- a/README_CN_testnet.md +++ b/README_CN_testnet.md @@ -2,6 +2,19 @@ *最新版本请参考 https://github.com/iotexproject/iotex-bootstrap/blob/master/README.md* + +> ### ⚠️ Zanzibar 硬分叉 — 测试网 46880641 块(2026-08-21 约 10:00 CST) +> +> 必须在该高度之前升级到 `v2.5.0-rc0` **并**重新下载 `genesis_testnet.yaml`。 +> 停留在旧二进制或旧 genesis 的节点会从网络分叉出去。 +> +> 激活高度较早前的草案有过调整,请重新下载 genesis,不要假设手上那份是最新的。 +> `config_testnet.yaml` 本次没有变化,可以沿用。 +> +> 希望启用 IIP-59 链上投票人奖励发放的 delegate,需要用 +> `ioctl stake2 voterrewardoptin` 开启,并在 DelegateProfile 合约中设置分成比例。 +> 详见 [v2.5.0 release note](changelog/v2.5.0-release-note.md)。 + ## 索引 - [发布状态](#status) diff --git a/README_testnet.md b/README_testnet.md index feddb31..09de277 100644 --- a/README_testnet.md +++ b/README_testnet.md @@ -14,6 +14,22 @@ - [Upgrade Your Node(One Line Upgrader)](#upgrade) - [Q&A](#qa) + +> ### ⚠️ Zanzibar hardfork — TestNet block 46880641 (2026-08-21 ~10:00 CST) +> +> Upgrading to `v2.5.0-rc0` **and** re-downloading `genesis_testnet.yaml` is +> required before that block. A node left on the old binary or the old genesis +> will fork off the network. +> +> The activation height changed from an earlier draft, so re-download the +> genesis rather than assuming the copy you have is current. `config_testnet.yaml` +> is unchanged and can be kept. +> +> Delegates who want IIP-59 on-chain voter reward distribution need to opt in +> with `ioctl stake2 voterrewardoptin` and set their reward portions in the +> DelegateProfile contract. See the +> [v2.5.0 release note](changelog/v2.5.0-release-note.md). + ## Release Status Here are the software versions we use: diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index ffd89e7..541a183 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -8,7 +8,7 @@ Zanzibar is scheduled on **TestNet at block 46880641** (2026-08-21, roughly a da v2.5.0 is therefore a **TestNet-only release**: the MainNet docs in this repository deliberately stay on v2.4.4, and MainNet operators should not upgrade yet. TestNet delegates **must** upgrade before block 46880641 or they will fork off the network. -Both `genesis_testnet.yaml` and `config_testnet.yaml` must be refreshed as part of this upgrade — the genesis file carries the new activation height and two new contract addresses. +`genesis_testnet.yaml` must be refreshed as part of this upgrade — it carries the new activation height and two new contract addresses. `config_testnet.yaml` is unchanged in this release; an existing one can be kept. > **TestNet delegates:** the genesis file changed. Re-download `genesis_testnet.yaml` when you upgrade; keeping the old one will fork your node at 46880641. @@ -35,44 +35,30 @@ Zanzibar activates six changes at once: ```yaml blockchain: zanzibarHeight: 46880641 - autoDepositContractAddress: io1grzhsc5w7a07d6ple4kuaxylxdwcsj7w8r2zuu + autoDepositContractAddress: io1pvlpc02xft2va4f38ae2nvgqglcxtfytez75c4 poll: - delegateProfileContractAddress: io16x0lkj99cx9h032p6vkpkxkzgsxzsam5t5sk5s + delegateProfileContractAddress: io19l8qpk08rw0jr4vwguyufva9w4t6aq75q2kt90 ``` -`autoDepositContractAddress` is the AutoDepositRegister contract IIP-59 reads per-voter compound preferences from. It was deployed on TestNet for this release at `0x40C578628ef75fe6e83FCD6DCE989f335D884bCE`, installing the same runtime bytecode as the MainNet deployment so the storage layout matches. +Both contracts were deployed on TestNet for this release by replaying the +MainNet creation transactions, so each runtime is byte-identical to MainNet's +— which matters for AutoDepositRegister, whose storage slots IIP-59 reads +directly — while the constructors still ran, leaving the owner set and +pause/unpause usable. -`delegateProfileContractAddress` is the existing TestNet DelegateProfile contract (`0xd19ffB48a5C18B77c541D32c1B1ac2440c287774`), from which IIP-59 reads each delegate's voter-take portions when it freezes the era snapshot. - -Two IIP-59 parameters are left at their built-in defaults and do not appear in the YAML: `epochsPerRewardEra` (24) and `voterBudgetPerBlock` (256). - -### TestNet delegates: two things to do before the fork - -**1. Opt in.** IIP-59 only distributes for candidates whose `VoterRewardOnchainOptIn` flag is set. At the fork block the protocol auto-opts-in any candidate whose reward address is one of `hermesRewardVaultAddresses`, a convenience for delegates who route rewards through a Hermes vault. Everyone else must send the new `SetVoterRewardOptIn` staking action themselves: - -```bash -ioctl stake2 voterrewardoptin -s -``` - -**2. Set the commission portions.** A delegate that has not configured `blockRewardPortion` / `epochRewardPortion` in the DelegateProfile contract is snapshotted at 100% commission, so its voters receive nothing through the on-chain path. The profile is keyed by the candidate's identifier address, so the transaction has to be sent from it — sending from the operator address writes a record nothing reads. - -Without both, Zanzibar activates but the voter distribution path has nothing to pay out. That is a safe state — no rewards are lost, they simply keep flowing through the existing off-chain path — but it also means IIP-59 is not actually being exercised. - -Surveying the 35 TestNet delegates at the time of writing: - -| | count | +| | address | |---|---| -| reward address is a Hermes vault (auto-opted-in at the fork) | 3 | -| `blockRewardPortion` / `epochRewardPortion` configured | 2 | -| both, i.e. paying voters with no further action | **1** | +| AutoDepositRegister | `io1pvlpc02xft2va4f38ae2nvgqglcxtfytez75c4` / `0x0b3e1C3d464AD4CED5313f72A9b10047f065A48B` | +| DelegateProfile | `io19l8qpk08rw0jr4vwguyufva9w4t6aq75q2kt90` / `0x2fcE00d9E71B9f21D58e4709c4B3A57557ae83D4` | -So the fork will activate with essentially nothing to distribute unless delegates act. To check any single delegate: +`autoDepositContractAddress` is where IIP-59 reads per-voter compound +preferences from; it is the same contract iotex-hub writes registrations to, +so a preference set through the hub is the one the protocol acts on. +`delegateProfileContractAddress` is where it reads each delegate's voter-take +portions when it freezes the era snapshot; its three reward-portion fields are +registered against the existing PermyriadVerifier. -```bash -ioctl node reward payout # opted in? -ioctl node reward snapshot # commission frozen for the era -ioctl node reward pending # pool waiting to be paid -``` +Two IIP-59 parameters are left at their built-in defaults and do not appear in the YAML: `epochsPerRewardEra` (24) and `voterBudgetPerBlock` (256). ## Changes From a09640001c9b34f6d7f35412e388f73746823d08 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 28 Aug 2026 23:52:24 +0800 Subject: [PATCH 11/15] release: schedule Zanzibar Beta and the testnet balance grant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both land at height 47141281 — epoch 32737's first block, which every other fork height on this chain is also aligned to, and roughly 06:00 CST on 2026-08-29, about six hours after this is written. zanzibarBetaHeight carries the three corrections that landed after v2.5.0-rc0: the epoch-settlement fault handling, the DelegateProfile requirement for the Hermes opt-in migration, and the era freeze log. They correct behaviour Zanzibar already turned on, so they cannot share Zanzibar's height — this chain committed 250k blocks under the pre-correction rules and re-deciding them would change those blocks' receipt roots. Verified locally: a node given zanzibarBetaHeight == zanzibarHeight diverges at the activation block itself. testnetGrants credits 1e9 IOTX to a fresh address so the delegate set can be re-registered. The credit goes through the state manager, so it reaches the Erigon secondary store as well as the trie, and it adds to whatever the account already holds rather than overwriting it. Both heights must stay ahead of the tip until every node is upgraded. Note that a v2.5.0-rc0 node cannot read this file at all — it rejects the unknown zanzibarBetaHeight key and refuses to start — so the binary has to be rolled before this genesis is distributed. Co-Authored-By: Claude Opus 5 (1M context) --- genesis_testnet.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/genesis_testnet.yaml b/genesis_testnet.yaml index e3148ba..31ed809 100644 --- a/genesis_testnet.yaml +++ b/genesis_testnet.yaml @@ -1,4 +1,9 @@ account: + testnetGrants: + - height: 47141281 + recipients: + - address: io1ycl9fzdve2l5yqwxywrtpvz2wtwlzfc349r7fc + amount: "1000000000000000000000000000" initBalances: io10t7juxazfteqzjsd6qjk7tkgmngj2tm7n4fvrd: "1000000000000000000000000000" io120au9ra0nffdle04jx2g5gccn6gq8qd4fy03l4: "7000000000000000000000000000" @@ -41,6 +46,7 @@ blockchain: yapHeight: 42819841 yapBetaHeight: 43361281 zanzibarHeight: 46880641 + zanzibarBetaHeight: 47141281 autoDepositContractAddress: io1pvlpc02xft2va4f38ae2nvgqglcxtfytez75c4 numCandidateDelegates: 36 numDelegates: 24 From 4efb70c087a02a5bd346f8bb2f9b00ff01dbf69b Mon Sep 17 00:00:00 2001 From: envestcc Date: Sat, 29 Aug 2026 00:06:25 +0800 Subject: [PATCH 12/15] docs: bump testnet to v2.5.0-rc1 and document Zanzibar Beta Zanzibar activated on TestNet at 46880641 on 2026-08-21. Zanzibar Beta follows at 47141281 with three corrections to what it turned on, plus the scheduled balance grant, so every version reference moves to v2.5.0-rc1. Both READMEs and the release note now lead with the upgrade ordering requirement: rc0 cannot parse the new genesis at all -- it rejects the zanzibarBetaHeight and account.testnetGrants keys and refuses to start -- so operators must pull the new binary before swapping the genesis in. Verified by loading this genesis under both rc0 (rejects, with the two field errors quoted in the release note) and rc1 (accepts, all four values as scheduled). The release note also records that the Hermes opt-in migration guard is permanently inert on TestNet: it runs only in the block at Zanzibar's height, which TestNet has passed, so a later Beta height cannot restore it. Chains that have not yet activated Zanzibar should set zanzibarBetaHeight equal to zanzibarHeight and get all three corrections. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 6 +-- README_CN_testnet.md | 29 +++++++---- README_testnet.md | 32 +++++++----- changelog/v2.5.0-release-note.md | 89 ++++++++++++++++++++++++++++---- scripts/all_in_one_testnet.sh | 8 +-- 5 files changed, 125 insertions(+), 39 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c56de99..d70a86b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This is the **IoTeX Delegate Manual** repository - configuration and operational ## Version Alignment -This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0-rc0 on TestNet** and **v2.4.4 on MainNet** — v2.5.0-rc0 carries the Zanzibar hardfork, which is scheduled on TestNet only, so the MainNet docs deliberately still point at v2.4.4. When iotex-core releases a new version: +This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0-rc1 on TestNet** and **v2.4.4 on MainNet** — v2.5.0-rc1 carries the Zanzibar hardfork, which is scheduled on TestNet only, so the MainNet docs deliberately still point at v2.4.4. When iotex-core releases a new version: 1. Update version references in README.md, config files, and scripts 2. Add a release note in `changelog/` 3. Create a PR but do NOT merge until the final release is tagged in iotex-core @@ -38,7 +38,7 @@ See `release_flow.md` for the complete release process. ## Common Tasks ### Update for a new iotex-core release -1. Update `version` references in README.md (search for `v2.5.0-rc0`) +1. Update `version` references in README.md (search for `v2.5.0-rc1`) 2. Update docker image tags in `scripts/all_in_one_mainnet.sh` and `scripts/all_in_one_testnet.sh` 3. Add release note in `changelog/vX.Y.Z-release-note.md` 4. Update `config_mainnet.yaml` and `config_testnet.yaml` if needed @@ -56,7 +56,7 @@ bash <(curl -s https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/ma ### Non-interactive upgrade (AI agent / CI) ```bash bash setup_fullnode.sh --auto --home=/path/to/iotex-var -bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0-rc0 +bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0-rc1 bash setup_fullnode.sh --auto --home=/path/to/iotex-var --force # reinstall same version ``` Flags: `--auto` (skip prompts), `--home=` (IOTEX_HOME), `--version=` (target version), `--force` (bypass same-version check), `--monitor` (enable monitoring), `plugin=gateway` (enable gateway). diff --git a/README_CN_testnet.md b/README_CN_testnet.md index 87b87ed..d263c7e 100644 --- a/README_CN_testnet.md +++ b/README_CN_testnet.md @@ -3,13 +3,20 @@ *最新版本请参考 https://github.com/iotexproject/iotex-bootstrap/blob/master/README.md* -> ### ⚠️ Zanzibar 硬分叉 — 测试网 46880641 块(2026-08-21 约 10:00 CST) +> ### ⚠️ Zanzibar Beta 硬分叉 — 测试网 47141281 块(2026-08-29 约 06:00 CST) > -> 必须在该高度之前升级到 `v2.5.0-rc0` **并**重新下载 `genesis_testnet.yaml`。 +> 必须在该高度之前升级到 `v2.5.0-rc1` **并**重新下载 `genesis_testnet.yaml`。 > 停留在旧二进制或旧 genesis 的节点会从网络分叉出去。 > -> 激活高度较早前的草案有过调整,请重新下载 genesis,不要假设手上那份是最新的。 -> `config_testnet.yaml` 本次没有变化,可以沿用。 +> **先升级二进制,再换 genesis。** `v2.5.0-rc0` 的节点根本读不了新的 +> `genesis_testnet.yaml`——它无法识别新增的两个字段(`zanzibarBetaHeight` 和 +> `account.testnetGrants`),会直接启动失败。 +> 请先拉取 `v2.5.0-rc1` 并重启,然后再替换 genesis。`config_testnet.yaml` +> 本次没有变化,可以沿用。 +> +> Zanzibar 已于 2026-08-21 在 46880641 块激活,目前已经生效。Zanzibar Beta +> 包含对 Zanzibar 所启用功能的三处修正,因此需要单独的激活高度——如果放在 +> Zanzibar 的高度上生效,会改写这条链已经出块确认过的历史。 > > 希望启用 IIP-59 链上投票人奖励发放的 delegate,需要用 > `ioctl stake2 voterrewardoptin` 开启,并在 DelegateProfile 合约中设置分成比例。 @@ -30,7 +37,7 @@ 以下是当前我们使用的软件版本: -- 测试网:v2.5.0-rc0 +- 测试网:v2.5.0-rc1 **Note** 如果你要启动节点加入主网,请点击[**加入主网**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_CN.md) @@ -44,7 +51,7 @@ 1. 提取(pull) docker镜像 ``` -docker pull iotex/iotex-core:v2.5.0-rc0 +docker pull iotex/iotex-core:v2.5.0-rc1 ``` 2. 使用以下命令设置运行环境 @@ -59,8 +66,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. 编辑 `$IOTEX_HOME/etc/config.yaml`, 查找 `externalHost` 和 `producerPrivKey`, 取消注释行并填写您的外部 IP 和私钥。如果`producerPrivKey`放空,你的节点将被分配一个随机密钥。 @@ -113,7 +120,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc0 \ + iotex/iotex-core:v2.5.0-rc1 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -131,7 +138,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc0 \ + iotex/iotex-core:v2.5.0-rc1 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -151,7 +158,7 @@ docker run -d --restart on-failure --name iotex \ ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0-rc0 +git checkout v2.5.0-rc1 // optional export GOPROXY=https://goproxy.io diff --git a/README_testnet.md b/README_testnet.md index 09de277..29695d1 100644 --- a/README_testnet.md +++ b/README_testnet.md @@ -15,15 +15,23 @@ - [Q&A](#qa) -> ### ⚠️ Zanzibar hardfork — TestNet block 46880641 (2026-08-21 ~10:00 CST) +> ### ⚠️ Zanzibar Beta hardfork — TestNet block 47141281 (2026-08-29 ~06:00 CST) > -> Upgrading to `v2.5.0-rc0` **and** re-downloading `genesis_testnet.yaml` is +> Upgrading to `v2.5.0-rc1` **and** re-downloading `genesis_testnet.yaml` is > required before that block. A node left on the old binary or the old genesis > will fork off the network. > -> The activation height changed from an earlier draft, so re-download the -> genesis rather than assuming the copy you have is current. `config_testnet.yaml` -> is unchanged and can be kept. +> **Upgrade the binary first, then the genesis.** A `v2.5.0-rc0` node cannot +> read the new `genesis_testnet.yaml` at all — it rejects the two keys it does +> not know (`zanzibarBetaHeight` and `account.testnetGrants`) and refuses to +> start. Pull `v2.5.0-rc1`, restart, and +> only then replace the genesis. `config_testnet.yaml` is unchanged and can be +> kept. +> +> Zanzibar itself activated at block 46880641 on 2026-08-21 and is already +> live. Zanzibar Beta carries three corrections to what Zanzibar turned on, so +> it needs a height of its own — applying them at Zanzibar's height would +> re-decide blocks this chain has already committed. > > Delegates who want IIP-59 on-chain voter reward distribution need to opt in > with `ioctl stake2 voterrewardoptin` and set their reward portions in the @@ -34,7 +42,7 @@ Here are the software versions we use: -- TestNet: v2.5.0-rc0 +- TestNet: v2.5.0-rc1 **Note** To start and run a mainnet node, please click [**Join Mainnet**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README.md) @@ -47,7 +55,7 @@ This is the recommended way to start an IoTeX node 1. Pull the docker image: ``` -docker pull iotex/iotex-core:v2.5.0-rc0 +docker pull iotex/iotex-core:v2.5.0-rc1 ``` 2. Set the environment with the following commands: @@ -62,8 +70,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. Edit `$IOTEX_HOME/etc/config.yaml`, look for `externalHost` and `producerPrivKey`, uncomment the lines and fill in your external IP and private key. If you leave `producerPrivKey` empty, your node will be assgined with a random key. @@ -117,7 +125,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc0 \ + iotex/iotex-core:v2.5.0-rc1 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -137,7 +145,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc0 \ + iotex/iotex-core:v2.5.0-rc1 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -158,7 +166,7 @@ Same as [Join TestNet](#testnet) step 2 ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0-rc0 +git checkout v2.5.0-rc1 // optional export GOPROXY=https://goproxy.io diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index 541a183..561c1e7 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -8,9 +8,13 @@ Zanzibar is scheduled on **TestNet at block 46880641** (2026-08-21, roughly a da v2.5.0 is therefore a **TestNet-only release**: the MainNet docs in this repository deliberately stay on v2.4.4, and MainNet operators should not upgrade yet. TestNet delegates **must** upgrade before block 46880641 or they will fork off the network. +Zanzibar has since activated on TestNet as scheduled. `v2.5.0-rc1` follows it with a second fork, **Zanzibar Beta at block 47141281**, carrying three corrections to what Zanzibar turned on plus a TestNet balance grant. + `genesis_testnet.yaml` must be refreshed as part of this upgrade — it carries the new activation height and two new contract addresses. `config_testnet.yaml` is unchanged in this release; an existing one can be kept. -> **TestNet delegates:** the genesis file changed. Re-download `genesis_testnet.yaml` when you upgrade; keeping the old one will fork your node at 46880641. +> **TestNet delegates:** the genesis file changed again in `rc1`. Re-download `genesis_testnet.yaml` when you upgrade; keeping the old one will fork your node at 47141281. +> +> **Order matters:** upgrade the binary *first*, then replace the genesis. A `v2.5.0-rc0` node cannot parse the new file — it rejects the two keys it does not know (`zanzibarBetaHeight` and `account.testnetGrants`) and refuses to start. ## Hardfork: Zanzibar @@ -60,6 +64,58 @@ registered against the existing PermyriadVerifier. Two IIP-59 parameters are left at their built-in defaults and do not appear in the YAML: `epochsPerRewardEra` (24) and `voterBudgetPerBlock` (256). +## Hardfork: Zanzibar Beta + +| Network | Height | Approx. date | +|---------|--------|--------------| +| TestNet | 47141281 | 2026-08-29 ~06:00 CST | +| MainNet | not scheduled | — | + +Zanzibar Beta exists because Zanzibar is already live on TestNet. Three +corrections to behaviour Zanzibar activated cannot simply be folded into +Zanzibar's own height — that would rewrite the semantics of blocks TestNet has +already committed — so they get a height of their own. + +1. **Fail closed on non-settleable epoch-settlement faults.** An epoch reward + grant that fails for a reason not every node derives from committed state + was still settled as a Failure receipt, so one validator could commit "this + epoch paid nobody" while the rest committed the full grant — two receipt + roots for one block. Only verdicts classified as settleable now keep the + receipt; anything else surfaces as an error. The same gate makes the IIP-59 + auto-deposit bucket lookup fail closed rather than silently routing a voter's + reward to the wrong destination. +2. **Emit era-freeze logs.** The per-candidate poll snapshot taken at an era + freeze now emits reward logs, so indexers can observe the frozen set directly + instead of inferring it from the payouts that follow. +3. **Require a DelegateProfile entry for the Hermes opt-in migration.** + +> **Correction 3 is inert on TestNet.** The Hermes opt-in migration runs in +> exactly one block — the one at Zanzibar's height — and never again. TestNet +> passed that block on 2026-08-21, so the migration has already run unguarded +> and no later height brings the guard back. It is listed here for completeness +> and for chains that have not yet activated Zanzibar, which should set +> `zanzibarBetaHeight` **equal to** `zanzibarHeight` and get all three. + +### TestNet balance grant + +`rc1` also adds a scheduled balance credit, applied at the Zanzibar Beta height +to keep TestNet faucets funded: + +```yaml +account: + testnetGrants: + - height: 47141281 + recipients: + - address: io1ycl9fzdve2l5yqwxywrtpvz2wtwlzfc349r7fc + amount: "1000000000000000000000000000" +``` + +The grant **adds to** the recipient's existing balance rather than overwriting +it, and is applied through the state manager like any other credit, so it is +part of consensus: a node whose genesis omits it will diverge at 47141281. This +is a TestNet-only mechanism — `genesis_mainnet.yaml` carries no `testnetGrants` +and the field is validated to be empty on any chain that is not TestNet. + ## Changes ### Feature @@ -99,20 +155,35 @@ Two IIP-59 parameters are left at their built-in defaults and do not appear in t ## Upgrade -The TestNet rollout runs the **`v2.5.0-rc0`** pre-release; `v2.5.0` proper is -tagged once the fork has been observed on TestNet. +The TestNet rollout runs the **`v2.5.0-rc1`** pre-release; `v2.5.0` proper is +tagged once both forks have been observed on TestNet. Nodes already on `rc0` +still need this upgrade — `rc0` does not know about Zanzibar Beta and will fork +at 47141281. ```bash export IOTEX_HOME=$HOME/iotex-var -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml -docker pull iotex/iotex-core:v2.5.0-rc0 +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +docker pull iotex/iotex-core:v2.5.0-rc1 ``` -Then restart your node against the `iotex/iotex-core:v2.5.0-rc0` image. Or non-interactively: +Then restart your node against the `iotex/iotex-core:v2.5.0-rc1` image. Or non-interactively: ```bash -bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0-rc0 +bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0-rc1 +``` + +Pull the image and restart **before** replacing the genesis: `rc0` cannot parse +a genesis containing `zanzibarBetaHeight` or `testnetGrants`, and will fail to +start if it is swapped in first with: + +``` +failed to unmarshal yaml genesis to struct: yaml: unmarshal errors: + field testnetGrants not found in type genesis.Account + field zanzibarBetaHeight not found in type genesis.Blockchain ``` -Confirm the node picked up the new genesis before the fork height — a node still on the old genesis will produce or accept a divergent block at 46880641. The height moved from an earlier draft, so re-download rather than assuming yours is current. +Confirm the node picked up the new genesis before the fork height — a node still +on the old genesis will produce or accept a divergent block at 47141281. Check +that your `genesis_testnet.yaml` contains both `zanzibarBetaHeight: 47141281` +and the `account.testnetGrants` entry above. diff --git a/scripts/all_in_one_testnet.sh b/scripts/all_in_one_testnet.sh index 9363b82..9fb0d1d 100644 --- a/scripts/all_in_one_testnet.sh +++ b/scripts/all_in_one_testnet.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -docker pull iotex/iotex-core:v2.5.0-rc0 +docker pull iotex/iotex-core:v2.5.0-rc1 mkdir -p ~/iotex-var cd ~/iotex-var @@ -12,8 +12,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc0/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml # Download core snapshot (for delegate node) — use multi-threaded aria2c for speed, fall back to curl command -v aria2c >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y aria2) || true @@ -31,7 +31,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc0 \ + iotex/iotex-core:v2.5.0-rc1 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml From 5a7fc72279769cd628b2b5adec7790bb8971b496 Mon Sep 17 00:00:00 2001 From: envestcc Date: Sat, 5 Sep 2026 00:47:57 +0800 Subject: [PATCH 13/15] docs: schedule Zanzibar on MainNet at 52813081 Zanzibar, Beta and Gamma all land on block 52813081, around 2026-09-28 10:30 CST. This release stops being TestNet-only, so the MainNet docs, scripts and archive guide move from v2.4.4 to v2.5.0 and the release note covers both networks. The banners lead with what makes a MainNet upgrade different: there is no genesis change. MainNet keeps its fork heights and both IIP-59 contract addresses in the binary rather than in genesis_mainnet.yaml, so operators pull the image and restart -- none of the re-download-and-order-it-right care the TestNet rollout needed. Verified by loading the unmodified genesis_mainnet.yaml against the scheduling change: all three heights, both contract addresses, epochsPerRewardEra, voterBudgetPerBlock and the two Hermes vaults come through from the code defaults. Adds a Gamma section, which the note had no entry for at all. Its four corrections are gated together, and letting Gamma trail Zanzibar costs something concrete: EnforceBLSPoP rides Zanzibar and candidate register writes its self-stake bucket before verifying the proof, so a rejected proof would leave that bucket behind until Gamma activates. It also records that TestNet has not scheduled Gamma -- it activated Zanzibar and Beta on builds predating the fork, so those four corrections stay off there until a height is set. The delegate-facing part is the Hermes migration, which runs in exactly the activation block and never again. Against the live candidate set at block 52,004,121: 88 of 123 candidates have a Hermes vault reward address and complete DelegateProfile portions and will be migrated, 9 have the vault but incomplete portions and are left on the Hermes path, and 26 are unaffected. Being left behind breaks nothing but forfeits on-chain distribution with no second chance, so both READMEs and the note tell Hermes delegates to check both portion fields before the fork. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 2 +- README.md | 49 +++++++++++++++------ README_CN.md | 40 ++++++++++++----- archive-node.md | 4 +- changelog/v2.5.0-release-note.md | 73 +++++++++++++++++++++++++++----- scripts/all_in_one_mainnet.sh | 14 +++--- 6 files changed, 138 insertions(+), 44 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d70a86b..cef52ae 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This is the **IoTeX Delegate Manual** repository - configuration and operational ## Version Alignment -This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0-rc1 on TestNet** and **v2.4.4 on MainNet** — v2.5.0-rc1 carries the Zanzibar hardfork, which is scheduled on TestNet only, so the MainNet docs deliberately still point at v2.4.4. When iotex-core releases a new version: +This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0-rc1 on TestNet** and **v2.5.0 on MainNet** — Zanzibar is now scheduled on both: TestNet activated it at 46880641 with Beta at 47141281, and MainNet takes Zanzibar, Beta and Gamma together at 52813081. MainNet carries its fork heights in the binary rather than in `genesis_mainnet.yaml`, so a MainNet upgrade is a binary roll with no genesis change. When iotex-core releases a new version: 1. Update version references in README.md, config files, and scripts 2. Add a release note in `changelog/` 3. Create a PR but do NOT merge until the final release is tagged in iotex-core diff --git a/README.md b/README.md index 2256f50..2981dc6 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,34 @@ - [Agent Guide](AGENT.md) - [Q&A](#qa) +> ### ⚠️ Zanzibar hardfork — MainNet block 52813081 (2026-09-28 ~10:30 CST) +> +> Upgrade to `v2.5.0` before that block. A node left on `v2.4.4` will fork off +> the network. +> +> **`genesis_mainnet.yaml` does not change.** MainNet carries its fork heights +> in the binary, not in the genesis file, so there is nothing to re-download — +> unlike the TestNet rollout, where the genesis had to be replaced. Pull the +> image, restart, done. `config_mainnet.yaml` is unchanged as well. +> +> Zanzibar activates IIP-59 on-chain voter reward distribution. Beta and Gamma +> ride the same block: MainNet has activated none of them, so it takes all +> three corrections from the first block IIP-59 is live rather than scheduling +> a window that knowingly runs behaviour already found to be wrong. +> +> **Delegates distributing through Hermes:** at that block the protocol +> auto-migrates every candidate whose reward address is a Hermes vault, but +> only if its DelegateProfile carries both reward-portion fields. A candidate +> missing either one is left on the Hermes path — nothing breaks, but it does +> not get on-chain distribution, and the migration runs in that one block and +> never again. Check yours before the fork. See the +> [v2.5.0 release note](changelog/v2.5.0-release-note.md). + ## Release Status Here are the software versions we use: -- MainNet: v2.4.4 +- MainNet: v2.5.0 ## Join TestNet To start and run a testnet node, please click [**Join Testnet**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_testnet.md) @@ -33,7 +56,7 @@ This is the recommended way to start an IoTeX node 1. Pull the docker image: ``` -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 ``` 2. Set the environment with the following commands: @@ -48,9 +71,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch ``` 3. Edit `$IOTEX_HOME/etc/config.yaml`, look for `externalHost` and `producerPrivKey`, uncomment the lines and fill in your external IP and private key. If you leave `producerPrivKey` empty, your node will be assgined with a random key. @@ -105,7 +128,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -126,7 +149,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -150,7 +173,7 @@ Same as [Join MainNet](#mainnet) step 2 ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.4.4 +git checkout v2.5.0 // optional export GOPROXY=https://goproxy.io @@ -312,7 +335,7 @@ The upgrade script supports a non-interactive mode for use with AI agents, CI/CD |---|---| | `--auto` | Non-interactive mode, skip all prompts | | `--home=/path` | Set `$IOTEX_HOME` directory | -| `--version=v2.4.4` | Target version (default: latest release) | +| `--version=v2.5.0` | Target version (default: latest release) | | `--force` | Reinstall even if already running the same version | | `--snapshot` | Download blockchain snapshot (recommended for fresh install) | | `--monitor` | Enable monitoring | @@ -326,7 +349,7 @@ bash setup_fullnode.sh --auto --home=/path/to/iotex-var --snapshot bash setup_fullnode.sh --auto --home=/path/to/iotex-var # Upgrade to a specific version -bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.4.4 +bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0 ``` **Notes:** @@ -339,12 +362,12 @@ Node with gateway plugin enabled will perform extra indexing to serve API reques ### Transaction-log patch (gateway / API / archive nodes) -Nodes that **serve transaction-log queries** (`GetTransactionLogByActionHash`, `GetTransactionLogByBlockHeight`) should apply the transaction-log patch shipped with v2.4.4, which corrects a set of historical in-contract-transfer records. Delegate / fullnodes that do not serve these queries do not need it. +Nodes that **serve transaction-log queries** (`GetTransactionLogByActionHash`, `GetTransactionLogByBlockHeight`) should apply the transaction-log patch shipped with v2.5.0, which corrects a set of historical in-contract-transfer records. Delegate / fullnodes that do not serve these queries do not need it. 1. Download the patch file into the node's data directory and verify its checksum: ``` -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch echo "dee9406afc991d5439ab4c27bc85fa658e1fb241ddabe1cc5fef18f27d728986 $IOTEX_HOME/data/txlog.db.patch" | sha256sum -c ``` @@ -357,7 +380,7 @@ chain: 3. Restart the node. -> **Important:** only set `patchTransactionLogPath` if the patch file exists at that path — a node configured with a missing patch file will **fail to start**. The patch is read-only and does not change balances, receipts, or block hashes. See the [v2.4.4 release note](changelog/v2.4.4-release-note.md) for details. +> **Important:** only set `patchTransactionLogPath` if the patch file exists at that path — a node configured with a missing patch file will **fail to start**. The patch is read-only and does not change balances, receipts, or block hashes. See the [v2.5.0 release note](changelog/v2.5.0-release-note.md) for details. ## Q&A Please refer [here](https://github.com/iotexproject/iotex-bootstrap/wiki/Q&A) for Q&A. diff --git a/README_CN.md b/README_CN.md index 06afa72..425b666 100644 --- a/README_CN.md +++ b/README_CN.md @@ -14,11 +14,29 @@ - [网关插件](#gateway) - [常见问题](#qa) +> ### ⚠️ Zanzibar 硬分叉 — 主网 52813081 块(2026-09-28 约 10:30 CST) +> +> 必须在该高度之前升级到 `v2.5.0`。停留在 `v2.4.4` 的节点会从网络分叉出去。 +> +> **`genesis_mainnet.yaml` 不变。** 主网的分叉高度写在二进制里、不在 genesis 文件中, +> 所以没有需要重新下载的东西——这与测试网那次不同(测试网必须替换 genesis)。 +> 拉镜像、重启,就完成了。`config_mainnet.yaml` 同样不变。 +> +> Zanzibar 启用 IIP-59 链上投票人奖励发放。Beta 和 Gamma 与它同一个高度:主网三者 +> 都未激活过,所以从 IIP-59 生效的第一个块起就带上全部修正,而不是安排一段明知 +> 行为有误的窗口。 +> +> **通过 Hermes 分发的 delegate 请注意:** 该高度上协议会自动迁移所有 reward +> address 指向 Hermes vault 的候选人,但**前提是其 DelegateProfile 已配置两个 +> 分成字段**。缺任一字段的候选人会被留在 Hermes 老路径——不会出错,但拿不到链上 +> 分发,而且这个迁移只在那一个块执行、之后不再重来。请在分叉前检查。 +> 详见 [v2.5.0 release note](changelog/v2.5.0-release-note.md)。 + ## 发布状态 以下是当前我们使用的软件版本: -- 主网:v2.4.4 +- 主网:v2.5.0 ## 加入测试网 如果你要启动节点加入测试网,请点击[**加入测试网**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_CN_testnet.md) @@ -32,7 +50,7 @@ 1. 提取(pull) docker镜像 ``` -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 ``` 2. 使用以下命令设置运行环境 @@ -47,9 +65,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch ``` 3. 编辑 `$IOTEX_HOME/etc/config.yaml`, 查找 `externalHost` 和 `producerPrivKey`, 取消注释行并填写您的外部 IP 和私钥。如果`producerPrivKey`放空,你的节点将被分配一个随机密钥。 @@ -103,7 +121,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -121,7 +139,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -141,7 +159,7 @@ docker run -d --restart on-failure --name iotex \ ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.4.4 +git checkout v2.5.0 // optional export GOPROXY=https://goproxy.io @@ -281,12 +299,12 @@ bash <(curl -s https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/ma ### 交易日志补丁(网关 / API / 归档节点) -**对外提供交易日志查询**(`GetTransactionLogByActionHash`、`GetTransactionLogByBlockHeight`)的节点应安装 v2.4.4 引入的交易日志补丁,它会修正一组历史合约内转账记录。不对外提供这些查询的 delegate / 全节点无需安装。 +**对外提供交易日志查询**(`GetTransactionLogByActionHash`、`GetTransactionLogByBlockHeight`)的节点应安装 v2.5.0 引入的交易日志补丁,它会修正一组历史合约内转账记录。不对外提供这些查询的 delegate / 全节点无需安装。 1. 将补丁文件下载到节点的 data 目录,并校验其 checksum: ``` -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch echo "dee9406afc991d5439ab4c27bc85fa658e1fb241ddabe1cc5fef18f27d728986 $IOTEX_HOME/data/txlog.db.patch" | sha256sum -c ``` @@ -299,7 +317,7 @@ chain: 3. 重启节点。 -> **重要:** 仅当补丁文件确实存在于该路径时才设置 `patchTransactionLogPath` —— 若配置了该路径但文件缺失,节点将**无法启动**。该补丁为只读,不会改变余额、收据或区块哈希。详见 [v2.4.4 release note](changelog/v2.4.4-release-note.md)。 +> **重要:** 仅当补丁文件确实存在于该路径时才设置 `patchTransactionLogPath` —— 若配置了该路径但文件缺失,节点将**无法启动**。该补丁为只读,不会改变余额、收据或区块哈希。详见 [v2.5.0 release note](changelog/v2.5.0-release-note.md)。 ## 常见问题 diff --git a/archive-node.md b/archive-node.md index f2fadec..363157c 100644 --- a/archive-node.md +++ b/archive-node.md @@ -151,7 +151,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/iotex-archive/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -194,7 +194,7 @@ git clone https://github.com/iotexproject/iotex-core.git cd iotex-core #checkout the code branch for archive node -git checkout v2.4.4 +git checkout v2.5.0 #build binary make build diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index 561c1e7..bb9ddd0 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -2,26 +2,39 @@ ## Summary -v2.5.0 is a **required** release for TestNet delegates. It introduces the **Zanzibar** hardfork, which activates IIP-59 on-chain voter reward distribution together with three correctness/security fixes. +v2.5.0 is a **required** release for both networks. It introduces the **Zanzibar** hardfork, which activates IIP-59 on-chain voter reward distribution. -Zanzibar is scheduled on **TestNet at block 46880641** (2026-08-21, roughly a day after this release). It is **not scheduled on MainNet**. +| Network | Zanzibar | Beta | Gamma | Approx. date | +|---|---|---|---|---| +| TestNet | 46880641 | 47141281 | *not yet scheduled* | activated 2026-08-21 / 08-29 | +| MainNet | **52813081** | **52813081** | **52813081** | 2026-09-28 ~10:30 CST | -v2.5.0 is therefore a **TestNet-only release**: the MainNet docs in this repository deliberately stay on v2.4.4, and MainNet operators should not upgrade yet. TestNet delegates **must** upgrade before block 46880641 or they will fork off the network. +**MainNet takes all three at one block.** Beta and Gamma exist to carry corrections to behaviour their predecessor turned on, and splitting them is only forced on a chain that has already committed blocks under the pre-correction behaviour — which is why TestNet had to run Beta 260,640 blocks after Zanzibar. A chain activating them together skips that cost and gets every correction from the first block IIP-59 is live. -Zanzibar has since activated on TestNet as scheduled. `v2.5.0-rc1` follows it with a second fork, **Zanzibar Beta at block 47141281**, carrying three corrections to what Zanzibar turned on plus a TestNet balance grant. +> **MainNet operators: `genesis_mainnet.yaml` does not change.** MainNet carries its fork heights and the two IIP-59 contract addresses in the binary, not in the genesis file, so there is nothing to re-download. Pull `v2.5.0`, restart. `config_mainnet.yaml` is unchanged too. This is the opposite of the TestNet rollout, where the genesis had to be replaced and the ordering mattered. -`genesis_testnet.yaml` must be refreshed as part of this upgrade — it carries the new activation height and two new contract addresses. `config_testnet.yaml` is unchanged in this release; an existing one can be kept. +> **TestNet operators: the genesis file *did* change in `rc1`.** Re-download `genesis_testnet.yaml`; keeping the old one forks your node at 47141281. Upgrade the binary **first** — a `v2.5.0-rc0` node cannot parse the new file, rejecting the two keys it does not know (`zanzibarBetaHeight` and `account.testnetGrants`) and refusing to start. -> **TestNet delegates:** the genesis file changed again in `rc1`. Re-download `genesis_testnet.yaml` when you upgrade; keeping the old one will fork your node at 47141281. -> -> **Order matters:** upgrade the binary *first*, then replace the genesis. A `v2.5.0-rc0` node cannot parse the new file — it rejects the two keys it does not know (`zanzibarBetaHeight` and `account.testnetGrants`) and refuses to start. +### What MainNet delegates should do before 52813081 + +At that block `migrateHermesRewardOptIn` runs **once and never again**. It auto-opts-in every candidate whose reward address is one of the two Hermes vaults — but only if that candidate's DelegateProfile carries both reward-portion fields. + +Measured against the live candidate set at block 52,004,121: + +| | count | at activation | +|---|---|---| +| Hermes vault + complete portions | 88 | migrated onto on-chain distribution | +| Hermes vault + incomplete portions | 9 | left on the Hermes path | +| not a vault reward address | 26 | unaffected; opt in with `ioctl stake2 voterrewardoptin` | + +Being left on the Hermes path breaks nothing — rewards keep flowing the way they do today — but the delegate does not get on-chain distribution, and there is no second chance at the migration. **If you distribute through Hermes, check that your DelegateProfile has both `blockRewardPortion` and `epochRewardPortion` set before the fork.** ## Hardfork: Zanzibar | Network | Height | Approx. date | |---------|--------|--------------| | TestNet | 46880641 | 2026-08-21 ~10:00 CST | -| MainNet | not scheduled | — | +| MainNet | 52813081 | 2026-09-28 ~10:30 CST | Zanzibar activates six changes at once: @@ -69,7 +82,7 @@ Two IIP-59 parameters are left at their built-in defaults and do not appear in t | Network | Height | Approx. date | |---------|--------|--------------| | TestNet | 47141281 | 2026-08-29 ~06:00 CST | -| MainNet | not scheduled | — | +| MainNet | 52813081 | 2026-09-28 ~10:30 CST — same block as Zanzibar | Zanzibar Beta exists because Zanzibar is already live on TestNet. Three corrections to behaviour Zanzibar activated cannot simply be folded into @@ -116,6 +129,24 @@ part of consensus: a node whose genesis omits it will diverge at 47141281. This is a TestNet-only mechanism — `genesis_mainnet.yaml` carries no `testnetGrants` and the field is validated to be empty on any chain that is not TestNet. +## Hardfork: Zanzibar Gamma + +| Network | Height | Approx. date | +|---------|--------|--------------| +| TestNet | *not yet scheduled* | — | +| MainNet | 52813081 | 2026-09-28 ~10:30 CST — same block as Zanzibar | + +Gamma carries four further corrections, gated together: + +1. **`ValidateHeaderGasUsed`** — the block header's `gasUsed` is validated rather than trusted. +2. **`CorrectStakeMigrationGas`** — corrects the gas accounted to a stake migration. +3. **`CheckedBlockGasDeduction`** — the block gas deduction is checked. +4. **`RevertStakingStateOnFailedReceipt`** — staking state written before a failure is reverted rather than left behind. + +The same equal-height rule applies as for Beta, and there is a concrete cost to letting Gamma trail. `EnforceBLSPoP` rides Zanzibar, and candidate register writes its self-stake bucket *before* it verifies the proof — so on a chain where Gamma trails Zanzibar, a rejected proof leaves that bucket behind until Gamma activates. MainNet avoids that window entirely by taking both at 52813081. + +> **TestNet has not scheduled Gamma.** It activated Zanzibar and Beta on builds that predate this fork, so a TestNet node running a build that contains Gamma inherits `MaxUint64` and these four corrections stay off until a height is set for them. That is a follow-up, not part of this release note. + ## Changes ### Feature @@ -155,6 +186,28 @@ and the field is validated to be empty on any chain that is not TestNet. ## Upgrade +### MainNet + +A binary roll. Nothing else changes — the fork heights and both IIP-59 contract +addresses live in the binary, so `genesis_mainnet.yaml` and +`config_mainnet.yaml` are both untouched. + +```bash +docker pull iotex/iotex-core:v2.5.0 +# restart your node against the new image +``` + +Or non-interactively: + +```bash +bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0 +``` + +Confirm the node reports `v2.5.0` before block 52813081. There is no genesis +file to verify, which removes the ordering trap the TestNet rollout had. + +### TestNet + The TestNet rollout runs the **`v2.5.0-rc1`** pre-release; `v2.5.0` proper is tagged once both forks have been observed on TestNet. Nodes already on `rc0` still need this upgrade — `rc0` does not know about Zanzibar Beta and will fork diff --git a/scripts/all_in_one_mainnet.sh b/scripts/all_in_one_mainnet.sh index 3975416..3742fa9 100644 --- a/scripts/all_in_one_mainnet.sh +++ b/scripts/all_in_one_mainnet.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -docker pull iotex/iotex-core:v2.4.4 +docker pull iotex/iotex-core:v2.5.0 mkdir -p ~/iotex-var cd ~/iotex-var @@ -12,9 +12,9 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/trie.db.patch > $IOTEX_HOME/data/trie.db.patch +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/config_mainnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/genesis_mainnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/trie.db.patch > $IOTEX_HOME/data/trie.db.patch # Download core snapshot (for delegate node) — use multi-threaded aria2c for speed, fall back to curl command -v aria2c >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y aria2) || true @@ -32,7 +32,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.4.4 \ + iotex/iotex-core:v2.5.0 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -40,9 +40,9 @@ docker run -d --restart on-failure --name iotex \ # --- Optional: gateway / API node only (not needed for a delegate / fullnode) --- # If you run this node as a gateway (add `-plugin=gateway` to the docker run above) so it # serves API / transaction-log queries, also apply the transaction-log patch shipped with -# v2.4.4 (see changelog/v2.4.4-release-note.md): +# v2.5.0 (see changelog/v2.5.0-release-note.md): # -# curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.4.4/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch +# curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0/txlog.db.patch > $IOTEX_HOME/data/txlog.db.patch # # then add the following to the chain: section of $IOTEX_HOME/etc/config.yaml and restart: # From 43e62d46081c7033ec78edfa4823c7413e4eaf06 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 7 Sep 2026 10:36:39 +0800 Subject: [PATCH 14/15] release: schedule Zanzibar Gamma on TestNet at 47468161 TestNet activated Zanzibar at 46880641 and Beta at 47141281 on builds that predate Gamma, so its four corrections -- ValidateHeaderGasUsed, CorrectStakeMigrationGas, CheckedBlockGasDeduction and RevertStakingStateOnFailedReceipt -- have been off since IIP-59 went live there. This schedules them. 47468161 starts an epoch: (h - 47141281) % 1440 == 0, exactly 227 epochs past Beta and on the same grid zanzibarHeight and zanzibarBetaHeight sit on. It is ~11,200 blocks ahead of the tip at the time of writing (47,456,979 on 2026-09-07 10:13 CST), which at 2.507 s/block lands around 18:00 CST the same day. Verified by loading this file under v2.5.0-rc2 (30714c91e): it reports 46880641/47141281/47468161 with the grant entry intact. Upgrade the binary before distributing this file. v2.5.0-rc1 rejects it -- "field zanzibarGammaHeight not found in type genesis.Blockchain" -- and refuses to start, the same trap the rc0-to-rc1 rollout had with zanzibarBetaHeight. Roll every node to v2.5.0-rc2 first, where Gamma stays unscheduled and behaviour is unchanged, then replace the genesis. The deferred-Gamma case this puts TestNet in was rehearsed locally at the same commit: a chain with Zanzibar and Beta at 200 and Gamma at 400 crossed 400 and kept producing, five nodes agreeing, zero digest mismatches. Every prior local round had activated all three together, so that path was untested until now. Co-Authored-By: Claude Opus 5 (1M context) --- genesis_testnet.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/genesis_testnet.yaml b/genesis_testnet.yaml index 31ed809..710fa77 100644 --- a/genesis_testnet.yaml +++ b/genesis_testnet.yaml @@ -47,6 +47,7 @@ blockchain: yapBetaHeight: 43361281 zanzibarHeight: 46880641 zanzibarBetaHeight: 47141281 + zanzibarGammaHeight: 47468161 autoDepositContractAddress: io1pvlpc02xft2va4f38ae2nvgqglcxtfytez75c4 numCandidateDelegates: 36 numDelegates: 24 From 0c953e0e0ddbb70092e9a498df2b033746e6aaa0 Mon Sep 17 00:00:00 2001 From: qevan <448293+guo@users.noreply.github.com> Date: Tue, 15 Sep 2026 11:59:22 -0700 Subject: [PATCH 15/15] docs(release): reschedule Zanzibar mainnet activation --- CLAUDE.md | 6 ++-- README.md | 2 +- README_CN.md | 2 +- README_CN_testnet.md | 33 ++++++++++----------- README_testnet.md | 39 +++++++++++------------- changelog/v2.5.0-release-note.md | 51 +++++++++++++++----------------- scripts/all_in_one_testnet.sh | 8 ++--- 7 files changed, 66 insertions(+), 75 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index cef52ae..7e52c48 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This is the **IoTeX Delegate Manual** repository - configuration and operational ## Version Alignment -This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0-rc1 on TestNet** and **v2.5.0 on MainNet** — Zanzibar is now scheduled on both: TestNet activated it at 46880641 with Beta at 47141281, and MainNet takes Zanzibar, Beta and Gamma together at 52813081. MainNet carries its fork heights in the binary rather than in `genesis_mainnet.yaml`, so a MainNet upgrade is a binary roll with no genesis change. When iotex-core releases a new version: +This repository is versioned in sync with [iotex-core](https://github.com/iotexproject/iotex-core). The current release is **v2.5.0-rc2 on TestNet** and **v2.5.0 on MainNet** — Zanzibar is now scheduled on both: TestNet activated it at 46880641, Beta at 47141281, and Gamma at 47468161; MainNet takes all three together at 53155801. MainNet carries its fork heights in the binary rather than in `genesis_mainnet.yaml`, so a MainNet upgrade is a binary roll with no genesis change. When iotex-core releases a new version: 1. Update version references in README.md, config files, and scripts 2. Add a release note in `changelog/` 3. Create a PR but do NOT merge until the final release is tagged in iotex-core @@ -38,7 +38,7 @@ See `release_flow.md` for the complete release process. ## Common Tasks ### Update for a new iotex-core release -1. Update `version` references in README.md (search for `v2.5.0-rc1`) +1. Update `version` references in README.md (search for `v2.5.0-rc2`) 2. Update docker image tags in `scripts/all_in_one_mainnet.sh` and `scripts/all_in_one_testnet.sh` 3. Add release note in `changelog/vX.Y.Z-release-note.md` 4. Update `config_mainnet.yaml` and `config_testnet.yaml` if needed @@ -56,7 +56,7 @@ bash <(curl -s https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/ma ### Non-interactive upgrade (AI agent / CI) ```bash bash setup_fullnode.sh --auto --home=/path/to/iotex-var -bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0-rc1 +bash setup_fullnode.sh --auto --home=/path/to/iotex-var --version=v2.5.0-rc2 bash setup_fullnode.sh --auto --home=/path/to/iotex-var --force # reinstall same version ``` Flags: `--auto` (skip prompts), `--home=` (IOTEX_HOME), `--version=` (target version), `--force` (bypass same-version check), `--monitor` (enable monitoring), `plugin=gateway` (enable gateway). diff --git a/README.md b/README.md index 2981dc6..c17ad4b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ - [Agent Guide](AGENT.md) - [Q&A](#qa) -> ### ⚠️ Zanzibar hardfork — MainNet block 52813081 (2026-09-28 ~10:30 CST) +> ### ⚠️ Zanzibar hardfork — MainNet block 53155801 (estimated 2026-10-08 02:00 UTC / 10:00 CST) > > Upgrade to `v2.5.0` before that block. A node left on `v2.4.4` will fork off > the network. diff --git a/README_CN.md b/README_CN.md index 425b666..a45126f 100644 --- a/README_CN.md +++ b/README_CN.md @@ -14,7 +14,7 @@ - [网关插件](#gateway) - [常见问题](#qa) -> ### ⚠️ Zanzibar 硬分叉 — 主网 52813081 块(2026-09-28 约 10:30 CST) +> ### ⚠️ Zanzibar 硬分叉 — 主网 53155801 块(预计 2026-10-08 02:00 UTC / 10:00 CST) > > 必须在该高度之前升级到 `v2.5.0`。停留在 `v2.4.4` 的节点会从网络分叉出去。 > diff --git a/README_CN_testnet.md b/README_CN_testnet.md index d263c7e..5d7689d 100644 --- a/README_CN_testnet.md +++ b/README_CN_testnet.md @@ -3,20 +3,17 @@ *最新版本请参考 https://github.com/iotexproject/iotex-bootstrap/blob/master/README.md* -> ### ⚠️ Zanzibar Beta 硬分叉 — 测试网 47141281 块(2026-08-29 约 06:00 CST) +> ### ⚠️ Zanzibar Gamma 硬分叉 — 测试网 47468161 块(已于 2026-09-07 10:00 UTC / 18:00 CST 激活) > -> 必须在该高度之前升级到 `v2.5.0-rc1` **并**重新下载 `genesis_testnet.yaml`。 -> 停留在旧二进制或旧 genesis 的节点会从网络分叉出去。 +> 测试网节点必须运行 `v2.5.0-rc2` 并使用当前的 `genesis_testnet.yaml`。 +> 停留在旧二进制或旧 genesis 的节点会继续执行 Gamma 之前的规则。 > -> **先升级二进制,再换 genesis。** `v2.5.0-rc0` 的节点根本读不了新的 -> `genesis_testnet.yaml`——它无法识别新增的两个字段(`zanzibarBetaHeight` 和 -> `account.testnetGrants`),会直接启动失败。 -> 请先拉取 `v2.5.0-rc1` 并重启,然后再替换 genesis。`config_testnet.yaml` -> 本次没有变化,可以沿用。 +> **先升级二进制,再换 genesis。** `v2.5.0-rc1` 无法识别当前 genesis 中的 +> `zanzibarGammaHeight`,会直接启动失败。请先拉取 `v2.5.0-rc2` 并重启, +> 然后再替换 genesis。`config_testnet.yaml` 本次没有变化,可以沿用。 > -> Zanzibar 已于 2026-08-21 在 46880641 块激活,目前已经生效。Zanzibar Beta -> 包含对 Zanzibar 所启用功能的三处修正,因此需要单独的激活高度——如果放在 -> Zanzibar 的高度上生效,会改写这条链已经出块确认过的历史。 +> Zanzibar 已在 46880641 块激活,Beta 已在 47141281 块激活。Gamma 包含另外四项 +> 修正;由于测试网已经按较早规则确认了区块,因此需要单独的激活高度。 > > 希望启用 IIP-59 链上投票人奖励发放的 delegate,需要用 > `ioctl stake2 voterrewardoptin` 开启,并在 DelegateProfile 合约中设置分成比例。 @@ -37,7 +34,7 @@ 以下是当前我们使用的软件版本: -- 测试网:v2.5.0-rc1 +- 测试网:v2.5.0-rc2 **Note** 如果你要启动节点加入主网,请点击[**加入主网**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README_CN.md) @@ -51,7 +48,7 @@ 1. 提取(pull) docker镜像 ``` -docker pull iotex/iotex-core:v2.5.0-rc1 +docker pull iotex/iotex-core:v2.5.0-rc2 ``` 2. 使用以下命令设置运行环境 @@ -66,8 +63,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. 编辑 `$IOTEX_HOME/etc/config.yaml`, 查找 `externalHost` 和 `producerPrivKey`, 取消注释行并填写您的外部 IP 和私钥。如果`producerPrivKey`放空,你的节点将被分配一个随机密钥。 @@ -120,7 +117,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc1 \ + iotex/iotex-core:v2.5.0-rc2 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -138,7 +135,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc1 \ + iotex/iotex-core:v2.5.0-rc2 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -158,7 +155,7 @@ docker run -d --restart on-failure --name iotex \ ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0-rc1 +git checkout v2.5.0-rc2 // optional export GOPROXY=https://goproxy.io diff --git a/README_testnet.md b/README_testnet.md index 29695d1..98c91a0 100644 --- a/README_testnet.md +++ b/README_testnet.md @@ -15,23 +15,20 @@ - [Q&A](#qa) -> ### ⚠️ Zanzibar Beta hardfork — TestNet block 47141281 (2026-08-29 ~06:00 CST) +> ### ⚠️ Zanzibar Gamma hardfork — TestNet block 47468161 (activated 2026-09-07 10:00 UTC / 18:00 CST) > -> Upgrading to `v2.5.0-rc1` **and** re-downloading `genesis_testnet.yaml` is -> required before that block. A node left on the old binary or the old genesis -> will fork off the network. +> TestNet operators must run `v2.5.0-rc2` with the current +> `genesis_testnet.yaml`. A node left on an older binary or genesis will follow +> the pre-Gamma rules. > -> **Upgrade the binary first, then the genesis.** A `v2.5.0-rc0` node cannot -> read the new `genesis_testnet.yaml` at all — it rejects the two keys it does -> not know (`zanzibarBetaHeight` and `account.testnetGrants`) and refuses to -> start. Pull `v2.5.0-rc1`, restart, and -> only then replace the genesis. `config_testnet.yaml` is unchanged and can be -> kept. +> **Upgrade the binary first, then the genesis.** A `v2.5.0-rc1` node cannot +> read the current `genesis_testnet.yaml` because it does not know +> `zanzibarGammaHeight`. Pull `v2.5.0-rc2`, restart, and only then replace the +> genesis. `config_testnet.yaml` is unchanged and can be kept. > -> Zanzibar itself activated at block 46880641 on 2026-08-21 and is already -> live. Zanzibar Beta carries three corrections to what Zanzibar turned on, so -> it needs a height of its own — applying them at Zanzibar's height would -> re-decide blocks this chain has already committed. +> Zanzibar activated at block 46880641 and Beta at 47141281. Gamma carries four +> further corrections and activated separately because TestNet had already +> committed blocks under the earlier rules. > > Delegates who want IIP-59 on-chain voter reward distribution need to opt in > with `ioctl stake2 voterrewardoptin` and set their reward portions in the @@ -42,7 +39,7 @@ Here are the software versions we use: -- TestNet: v2.5.0-rc1 +- TestNet: v2.5.0-rc2 **Note** To start and run a mainnet node, please click [**Join Mainnet**](https://github.com/iotexproject/iotex-bootstrap/blob/master/README.md) @@ -55,7 +52,7 @@ This is the recommended way to start an IoTeX node 1. Pull the docker image: ``` -docker pull iotex/iotex-core:v2.5.0-rc1 +docker pull iotex/iotex-core:v2.5.0-rc2 ``` 2. Set the environment with the following commands: @@ -70,8 +67,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml ``` 3. Edit `$IOTEX_HOME/etc/config.yaml`, look for `externalHost` and `producerPrivKey`, uncomment the lines and fill in your external IP and private key. If you leave `producerPrivKey` empty, your node will be assgined with a random key. @@ -125,7 +122,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc1 \ + iotex/iotex-core:v2.5.0-rc2 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml @@ -145,7 +142,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc1 \ + iotex/iotex-core:v2.5.0-rc2 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml \ @@ -166,7 +163,7 @@ Same as [Join TestNet](#testnet) step 2 ``` git clone https://github.com/iotexproject/iotex-core.git cd iotex-core -git checkout v2.5.0-rc1 +git checkout v2.5.0-rc2 // optional export GOPROXY=https://goproxy.io diff --git a/changelog/v2.5.0-release-note.md b/changelog/v2.5.0-release-note.md index bb9ddd0..e788efd 100644 --- a/changelog/v2.5.0-release-note.md +++ b/changelog/v2.5.0-release-note.md @@ -6,8 +6,8 @@ v2.5.0 is a **required** release for both networks. It introduces the **Zanzibar | Network | Zanzibar | Beta | Gamma | Approx. date | |---|---|---|---|---| -| TestNet | 46880641 | 47141281 | *not yet scheduled* | activated 2026-08-21 / 08-29 | -| MainNet | **52813081** | **52813081** | **52813081** | 2026-09-28 ~10:30 CST | +| TestNet | 46880641 | 47141281 | 47468161 | activated 2026-08-21 / 08-29 / 09-07 | +| MainNet | **53155801** | **53155801** | **53155801** | estimated 2026-10-08 02:00 UTC / 10:00 CST | **MainNet takes all three at one block.** Beta and Gamma exist to carry corrections to behaviour their predecessor turned on, and splitting them is only forced on a chain that has already committed blocks under the pre-correction behaviour — which is why TestNet had to run Beta 260,640 blocks after Zanzibar. A chain activating them together skips that cost and gets every correction from the first block IIP-59 is live. @@ -15,7 +15,7 @@ v2.5.0 is a **required** release for both networks. It introduces the **Zanzibar > **TestNet operators: the genesis file *did* change in `rc1`.** Re-download `genesis_testnet.yaml`; keeping the old one forks your node at 47141281. Upgrade the binary **first** — a `v2.5.0-rc0` node cannot parse the new file, rejecting the two keys it does not know (`zanzibarBetaHeight` and `account.testnetGrants`) and refusing to start. -### What MainNet delegates should do before 52813081 +### What MainNet delegates should do before 53155801 At that block `migrateHermesRewardOptIn` runs **once and never again**. It auto-opts-in every candidate whose reward address is one of the two Hermes vaults — but only if that candidate's DelegateProfile carries both reward-portion fields. @@ -34,7 +34,7 @@ Being left on the Hermes path breaks nothing — rewards keep flowing the way th | Network | Height | Approx. date | |---------|--------|--------------| | TestNet | 46880641 | 2026-08-21 ~10:00 CST | -| MainNet | 52813081 | 2026-09-28 ~10:30 CST | +| MainNet | 53155801 | estimated 2026-10-08 02:00 UTC / 10:00 CST | Zanzibar activates six changes at once: @@ -82,7 +82,7 @@ Two IIP-59 parameters are left at their built-in defaults and do not appear in t | Network | Height | Approx. date | |---------|--------|--------------| | TestNet | 47141281 | 2026-08-29 ~06:00 CST | -| MainNet | 52813081 | 2026-09-28 ~10:30 CST — same block as Zanzibar | +| MainNet | 53155801 | estimated 2026-10-08 02:00 UTC / 10:00 CST — same block as Zanzibar | Zanzibar Beta exists because Zanzibar is already live on TestNet. Three corrections to behaviour Zanzibar activated cannot simply be folded into @@ -133,8 +133,8 @@ and the field is validated to be empty on any chain that is not TestNet. | Network | Height | Approx. date | |---------|--------|--------------| -| TestNet | *not yet scheduled* | — | -| MainNet | 52813081 | 2026-09-28 ~10:30 CST — same block as Zanzibar | +| TestNet | 47468161 | activated 2026-09-07 10:00 UTC / 18:00 CST | +| MainNet | 53155801 | estimated 2026-10-08 02:00 UTC / 10:00 CST — same block as Zanzibar | Gamma carries four further corrections, gated together: @@ -143,9 +143,9 @@ Gamma carries four further corrections, gated together: 3. **`CheckedBlockGasDeduction`** — the block gas deduction is checked. 4. **`RevertStakingStateOnFailedReceipt`** — staking state written before a failure is reverted rather than left behind. -The same equal-height rule applies as for Beta, and there is a concrete cost to letting Gamma trail. `EnforceBLSPoP` rides Zanzibar, and candidate register writes its self-stake bucket *before* it verifies the proof — so on a chain where Gamma trails Zanzibar, a rejected proof leaves that bucket behind until Gamma activates. MainNet avoids that window entirely by taking both at 52813081. +The same equal-height rule applies as for Beta, and there is a concrete cost to letting Gamma trail. `EnforceBLSPoP` rides Zanzibar, and candidate register writes its self-stake bucket *before* it verifies the proof — so on a chain where Gamma trails Zanzibar, a rejected proof leaves that bucket behind until Gamma activates. MainNet avoids that window entirely by taking both at 53155801. -> **TestNet has not scheduled Gamma.** It activated Zanzibar and Beta on builds that predate this fork, so a TestNet node running a build that contains Gamma inherits `MaxUint64` and these four corrections stay off until a height is set for them. That is a follow-up, not part of this release note. +> **TestNet activated Gamma separately.** It had already activated Zanzibar and Beta on builds that predated Gamma, so `zanzibarGammaHeight` was set to 47468161 and the four corrections activated on 2026-09-07. ## Changes @@ -203,40 +203,37 @@ Or non-interactively: bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0 ``` -Confirm the node reports `v2.5.0` before block 52813081. There is no genesis +Confirm the node reports `v2.5.0` before block 53155801. There is no genesis file to verify, which removes the ordering trap the TestNet rollout had. ### TestNet -The TestNet rollout runs the **`v2.5.0-rc1`** pre-release; `v2.5.0` proper is -tagged once both forks have been observed on TestNet. Nodes already on `rc0` -still need this upgrade — `rc0` does not know about Zanzibar Beta and will fork -at 47141281. +The TestNet rollout runs the **`v2.5.0-rc2`** pre-release. Nodes on `rc1` must +upgrade before using the current genesis because `rc1` does not know about +Zanzibar Gamma. ```bash export IOTEX_HOME=$HOME/iotex-var -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml -docker pull iotex/iotex-core:v2.5.0-rc1 +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +docker pull iotex/iotex-core:v2.5.0-rc2 ``` -Then restart your node against the `iotex/iotex-core:v2.5.0-rc1` image. Or non-interactively: +Then restart your node against the `iotex/iotex-core:v2.5.0-rc2` image. Or non-interactively: ```bash -bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0-rc1 +bash setup_fullnode.sh --auto --home=$IOTEX_HOME --version=v2.5.0-rc2 ``` -Pull the image and restart **before** replacing the genesis: `rc0` cannot parse -a genesis containing `zanzibarBetaHeight` or `testnetGrants`, and will fail to -start if it is swapped in first with: +Pull the image and restart **before** replacing the genesis: `rc1` cannot parse +a genesis containing `zanzibarGammaHeight`, and will fail to start if it is +swapped in first with: ``` failed to unmarshal yaml genesis to struct: yaml: unmarshal errors: - field testnetGrants not found in type genesis.Account - field zanzibarBetaHeight not found in type genesis.Blockchain + field zanzibarGammaHeight not found in type genesis.Blockchain ``` -Confirm the node picked up the new genesis before the fork height — a node still -on the old genesis will produce or accept a divergent block at 47141281. Check -that your `genesis_testnet.yaml` contains both `zanzibarBetaHeight: 47141281` +Confirm the node picked up the current genesis. Check that it contains +`zanzibarGammaHeight: 47468161` together with `zanzibarBetaHeight: 47141281` and the `account.testnetGrants` entry above. diff --git a/scripts/all_in_one_testnet.sh b/scripts/all_in_one_testnet.sh index 9fb0d1d..01eb987 100644 --- a/scripts/all_in_one_testnet.sh +++ b/scripts/all_in_one_testnet.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -docker pull iotex/iotex-core:v2.5.0-rc1 +docker pull iotex/iotex-core:v2.5.0-rc2 mkdir -p ~/iotex-var cd ~/iotex-var @@ -12,8 +12,8 @@ mkdir -p $IOTEX_HOME/data mkdir -p $IOTEX_HOME/log mkdir -p $IOTEX_HOME/etc -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml -curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc1/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/config_testnet.yaml > $IOTEX_HOME/etc/config.yaml +curl https://raw.githubusercontent.com/iotexproject/iotex-bootstrap/v2.5.0-rc2/genesis_testnet.yaml > $IOTEX_HOME/etc/genesis.yaml # Download core snapshot (for delegate node) — use multi-threaded aria2c for speed, fall back to curl command -v aria2c >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y aria2) || true @@ -31,7 +31,7 @@ docker run -d --restart on-failure --name iotex \ -v=$IOTEX_HOME/log:/var/log:rw \ -v=$IOTEX_HOME/etc/config.yaml:/etc/iotex/config_override.yaml:ro \ -v=$IOTEX_HOME/etc/genesis.yaml:/etc/iotex/genesis.yaml:ro \ - iotex/iotex-core:v2.5.0-rc1 \ + iotex/iotex-core:v2.5.0-rc2 \ iotex-server \ -config-path=/etc/iotex/config_override.yaml \ -genesis-path=/etc/iotex/genesis.yaml