Skip to content

Fix node abort (SIGABRT) when spending a post-founders-reward coinbase#23

Merged
wo01 merged 1 commit into
KotoDevelopers:masterfrom
ROZ-MOFUMOFU-ME:fix/founders-reward-assert-coinbase-shield
Jun 21, 2026
Merged

Fix node abort (SIGABRT) when spending a post-founders-reward coinbase#23
wo01 merged 1 commit into
KotoDevelopers:masterfrom
ROZ-MOFUMOFU-ME:fix/founders-reward-assert-coinbase-shield

Conversation

@emerauda

Copy link
Copy Markdown

Summary

CheckInputs() aborts the node (SIGABRT) when a coinbase mined after the founders‑reward period is spent to/with transparent outputs.

Details

To enforce "coinbase must be shielded", CheckInputs() permits a coinbase to be spent to transparent outputs only when its output is the founders‑reward script:

if (output.scriptPubKey != ::Params().GetFoundersRewardScriptAtHeight(coins->nHeight)) {
    return state.Invalid(..., "bad-txns-coinbase-spend-has-transparent-outputs");
}

But CChainParams::GetFoundersRewardScriptAtHeight() asserts the height is inside the founders‑reward period:

assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight));

Once the chain passes the last founders‑reward block, coins->nHeight of a spent coinbase is beyond that period, the assert fails, and abort() kills the whole daemon.

Impact

On current mainnet (founders reward ended long ago; tip ~4,450,000) this reproduces reliably: any node that spends a matured coinbase to/with transparent outputs crashes with Main process exited, code=killed, status=6/ABRT. Mining pools spending their own coinbase hit it ~every time a coinbase matures — observed as kotod crashing roughly every couple of hours:

kotod: chainparams.cpp:695: CScript CChainParams::GetFoundersRewardScriptAtHeight(int) const:
  Assertion `nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight)' failed.

Fix

Guard the height before calling GetFoundersRewardScriptAtHeight() (via short‑circuit, so it is only called within the founders‑reward period). Past the period there is no founders reward, so the coinbase‑must‑be‑shielded rule simply applies and the transparent spend is rejected — the same consensus outcome, without the abort. The other caller (ConnectBlock() founders/dev‑fee check) is already height‑guarded. GetFoundersRewardScriptAtHeight() itself (and its EXPECT_DEATH tests) is unchanged.


日本語補足

Founders Reward 期間終了後に採掘されたコインベースを透明(transparent)出力へ使おうとすると、CheckInputs() 内の GetFoundersRewardScriptAtHeight(coins->nHeight) が「height は Founders Reward 期間内」という assert に違反し、abort() でノード全体が落ちます(SIGABRT / status=6/ABRT)。

現行メインネット(Founders Reward は既に終了、tip ~445万)では確実に再現し、特にマイニングプールが自分のコインベースを使うたびにクラッシュします(実際に kotod が数時間ごとに落ちるのを確認)。

修正は、関数を呼ぶ前に height をガードするだけです(短絡評価で Founders 期間内のときのみ呼ぶ)。期間後は Founders Reward が存在しないため「コインベースは shielded 必須」のルールがそのまま適用され、透明使用は reject されます=consensus の結果は同一で、abort だけが無くなります。もう一方の呼び出し元(ConnectBlock の Dev Fee 検証)は既に height ガード済みのため変更不要です。関数本体および EXPECT_DEATH テストは変更していません。

…heights

CheckInputs() enforces "coinbase must be shielded" by permitting a coinbase to
be spent to transparent outputs only when its output is the founders-reward
script. It called CChainParams::GetFoundersRewardScriptAtHeight(coins->nHeight)
unconditionally, but that function asserts the height is within the
founders-reward period. Once the chain passes the last founders-reward block,
spending any matured coinbase to transparent outputs (e.g. a mining pool
spending its own coinbase) calls it with a post-period height and the assert
aborts the entire node (SIGABRT). On mainnet (founders reward long ended,
height ~4.45M) this crashes kotod ~whenever a pool-mined coinbase is spent.

Guard the height before calling it: past the founders-reward period there is no
founders reward, so the coinbase-must-be-shielded rule applies and the
transparent spend is rejected (identical consensus outcome) without aborting.
The other caller (ConnectBlock founders/dev-fee check) is already guarded.
@wo01
wo01 merged commit f712579 into KotoDevelopers:master Jun 21, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants