Skip to content

Fix development devnet on 3.1: pact service dies with "fork cannot be at genesis"#30

Closed
DaisukeFlowers wants to merge 1 commit into
kda-community:masterfrom
DaisukeFlowers:fix/development-devnet-31
Closed

Fix development devnet on 3.1: pact service dies with "fork cannot be at genesis"#30
DaisukeFlowers wants to merge 1 commit into
kda-community:masterfrom
DaisukeFlowers:fix/development-devnet-31

Conversation

@DaisukeFlowers

Copy link
Copy Markdown

Symptom

A fresh-genesis devnet with --chainweb-version development cannot produce any block on 3.1 (and current master). The pact service dies on the first new-block attempt, before block 1 is ever mined:

[Info]  [chainwebVersion=development|chain=16|component=pact|pact-request=execNewBlock] (parent height = 0) (parent hash = "kZqcd4YzShC58UF5dJJlQPogv3wSd3TrdOVzXrUmAB0")
[Error] [chainwebVersion=development|chain=16|component=pact] Received exception running pact service (execNewBlock): fork cannot be at genesis
CallStack (from HasCallStack):
  error, called at src/Chainweb/Version/Guards.hs:113:32 in chainweb-3.1-inplace:Chainweb.Version.Guards
...
chainweb-node: fork cannot be at genesis

(captured on ghcr.io/kda-community/chainweb-node/ubuntu:3.1; seeded databases are affected the same way). Found while testing on 3.1 — recap-development still works because it stages forks at real heights.

Root cause

  1. 3.1 introduced the MigratePlatformShare fork, guarded by atNotGenesis, which hard-errors when the fork is configured at genesis: src/Chainweb/Version/Guards.hs:118 (atNotGenesis _ ForkAtGenesis = error "fork cannot be at genesis", used at Guards.hs:326).
  2. The development version configures every fork as ForkAtGenesis: src/Chainweb/Version/Development.hs:35.
  3. applyUpgrades consults the guard on every block: src/Chainweb/Pact5/TransactionExec.hs:545 — so the first execNewBlock throws and no block can ever be produced.

--fork-upper-bound is not a workaround: it filters later forks out of the version map and getForkHeight then hits an unsafe lookup (^?!).

Fix

Stage MigratePlatformShare just above genesis in development instead of the blanket ForkAtGenesis, mirroring how recap-development stages it at 700 (src/Chainweb/Version/RecapDevelopment.hs:81).

Why height 2: atNotGenesis fires the one-shot migration exactly once at that height; every other fork stays genesis-active, preserving development's "everything on immediately" purpose, and the migration still lands within seconds of a fresh start. No existing history can break — no 3.1 development chain can exist, since it cannot mine block 1.

Rejected alternative: making atNotGenesis tolerate ForkAtGenesis (e.g. treat it as height 1). That would silently change one-shot migration semantics for all versions and defeat the guard's intent; the version-local fix seemed safer.

Verification

Built exe:chainweb-node from this branch (GHC 9.10.2, repo cabal.project.freeze) and ran a fresh-genesis single-node devnet (--chainweb-version development, --disable-pow, constant-delay mining client, 20 chains):

[Info] [chainwebVersion=development|cluster=f8-patched|chain=17|component=pact|pact-request=execNewBlock] (parent height = 1) (parent hash ...
[Info] [chainwebVersion=development|cluster=f8-patched|chain=14|component=pact|pact-request=execNewBlock] (parent height = 2) (parent hash ...
cut: chains 20  min-height 141  max-height 143   (still climbing; 0 errors/exceptions in the node log)
  • All 20 chains mine past the migration height and keep going.
  • The migration executed: after height 2, (describe-keyset "ns-admin-keyset") returns the platform-share keyset (user.pred.keys-3, the 5 migration keys) — same effect as on recap-development at 700.
  • Functional smoke against the patched node (service API, @kadena/client):
  [PASS] S1  node is KDA-CE 3.1 line  — nodePackageVersion=3.1
  [PASS] S2  network is development  — nodeVersion=development
  [PASS] S3  20 chains  — chains=20
  [PASS] S4  all 20 chains past MigratePlatformShare (min height >= 3)  — minHeight=89 chains=20
  [PASS] S5  sender00 funded on chain 0  — 100000000 KDA
  [PASS] S6  sender00 funded on chain 15  — 100000000 KDA
  [PASS] S7  free namespace exists on chain 0
    ✓ coin transfer sender00 -> miner @c0 (gas 220)
  [PASS] S8  real tx confirms
    ✓ coin xchain 0->15 step0 @ 0 (gas 250)
    • coin xchain 0->15 step1 @ 15 -> success (gas 234)
  [PASS] S9  SPV cross-chain 0->15 works
  [PASS] S10 MigratePlatformShare executed (ns-admin-keyset reset)  — {"pred":"user.pred.keys-3",...}

  === F8 PATCHED-NODE development SMOKE: 10/10 pass, 0 fail ===

Negative control: the unpatched ghcr.io/kda-community/chainweb-node/ubuntu:3.1 image with the identical config produces the failure log at the top — zero blocks, fresh or seeded.

The development version sets every fork ForkAtGenesis, but
MigratePlatformShare's guard (atNotGenesis) hard-errors on
ForkAtGenesis and is consulted by applyUpgrades on every block.
The pact service therefore dies on the first execNewBlock and a
development devnet can never mine a block, fresh or seeded.

Stage the one-shot migration at block height 2 (as recap-development
does at 700); every other fork stays genesis-active. Verified with a
fresh-genesis 20-chain devnet: blocks mine past the migration height,
the platform-share keyset reset applies, and coin transfers plus SPV
cross-chain succeed.
@DaisukeFlowers

Copy link
Copy Markdown
Author

Closing in favor of #28, which Pascal opened first and correctly disables MigratePlatformShare for devnet (ForkNever) rather than staging it above genesis. Running this migration on devnet hands namespace admin (ns-admin-keyset, etc.) to the mainnet platform-share keyset, which isn't what a devnet should do — my fix solved the crash but not the underlying issue. Sorry for the noise.

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.

1 participant