Skip to content

feat: fund the founding validator set with a 1,000 GNOT gas float - #78

Merged
moul merged 1 commit into
mainfrom
feat/genesis-validator-float
Sep 11, 2026
Merged

moul merged 1 commit into
mainfrom
feat/genesis-validator-float

Conversation

@moul

@moul moul commented Sep 11, 2026

Copy link
Copy Markdown
Member

Summary

The four founding validators of gnoland-1 are seeded as (signing address, operator address) pairs — gnogenesis fork valoper-seed requires the two to be distinct, so that compromising a signing key does not collapse into control of the validator slot. That is eight addresses, and six of them held nothing in the sheet:

slot signing operator
gno-core-validator-1 g1mmgvcs… ❌ g1aeddlf… ✅ founders grant
onbloc-validator-1 g1hqhetn… ❌ g12gtvlc… ❌
samourai-crew-validator-1 g15t7f9q… ❌ g1n9y62a… ❌
berty-validator-1 g1l983yy… ❌ g1qynsu9… ✅ signer float

Every management action on a validator is a paid transaction: rotating the signing key, editing the valoper profile in r/gnops/valopers, signalling opt-out through r/sys/validators. There is no mainnet faucet, and Constitution §126 locks ugnot transfers to the §127 exemption list — so an address that lands at zero at genesis can never be funded afterwards and can never act. This closes the INITIAL_VALSET_OPERATORS TODO(mainnet) in gnolang/gno's misc/deployments/mainnet.gno.land/gen-genesis.sh, which asks for exactly this decision.

1,000 GNOT each — the same tier as the GovDAO founders grant and the multisig signer float in mkgenesis/non-airdrop.txt. It is a float so a genesis validator can act, not a payment for validating.

Which bucket pays

§122, the Validator Services Treasury. A float that exists solely so a founding validator can rotate its key, edit its profile or opt out is a validator service. The alternatives both fail §226's purpose test: §346 restricts Ecosystem to "contributors whose real human identity is known and recorded" — the clause that removed the faucet — and Core already carries the founders.

Two of the eight are skipped because they are already funded to the same tier; their 1,000 simply stays in §122, exactly the shape of Jae's skipped founders grant staying in Core (#62 / the govdaoFoundersSkipped precedent):

  • g1aeddlf… — gno-core operator (aeddi), holds the 1,000 GNOT govdaoFounders grant. Funding again would panic in assign().
  • g1qynsu9… — berty operator, holds the 1,000 GNOT multisig signer float. Funding again would silently become 2,000 via accumulate().

Supply-neutral

before after
Validator Services Treasury (§122) 20,000,000 19,994,000
balances.txt.gz accounts 3,262,473 3,262,479
balances.txt.gz total 1,332,999,998.328067 1,332,999,998.328067

The float is charged out of §122, not added beside it, so the cap does not move. The six new rows are whole GNOT, so the truncation residual is unchanged too.

New artifact checksums (SHA256SUMS updated in this PR):

4228b52fafa4bb09f7fbb88a5e8c6a13fbf04acd7b617997a01ddab56fb4de3f  allocate/genbalance.txt.gz
517c17546fba721dcbfcaa01d51a5772be253df4afe9499bdc5206f131021ab3  mkgenesis/balances.txt.gz

Vesting

The six new rows carry the standard §132 schedule like every other row (4% at genesis, linear to 2028-09-11). That is deliberate and does not weaken the float: genesis-time fees are collected with SendCoinsUnrestricted, which bypasses both the vesting lock and the §126 restriction. No §132 exemption is claimed here — §136 admits exactly one, and this is not it.

Guards

  • TestGenesisValidatorFloatMatchesSkipList — the amount charged to §122 is exactly what is paid out, with no remainder. Adding a validator without raising the budget, or skipping one without lowering it, is a red build.
  • TestGenesisValidatorsAreFunded — asserts the end state on the shipped sheet: all eight addresses hold ≥ 1,000 GNOT, whichever line put it there. A skip is only safe while the other funding line exists; delete either one and this fails here rather than at launch.
  • validateHardcodedAddresses() — the valset is its own namespace (a duplicated slot is a transcription error and is caught even when both copies are skipped), a skip-list entry that is not in the valset panics, and no address may be paid by two roles.
  • TestSplitPreservesTheAggregate — everything charged out of the three treasuries still sums inside the 120M.

Each was verified by tripping it: an unfunded validator address, a budget one off the skip list, a skip-list entry absent from the valset, a slot listed twice, and an address paid by two roles.

Testing

make verify green — 47 tests, independent cross-check reports Balance files match., make checksums OK. The pipeline was run twice end to end and produced byte-identical artifacts (GNU gzip 1.12, darwin/arm64).

Note for review

genesisValidators is a mirror of gnolang/gno's INITIAL_VALSET + INITIAL_VALSET_OPERATORS. If the valset changes there, it must change here. Funding the signing addresses as well as the operators is a judgement call: it puts 1,000 GNOT on keys that live in tmkms/horcrux/an HSM. The reasoning is that §126 makes an unfunded address permanently unfundable, so the cost of guessing wrong in that direction is unrecoverable and the cost of guessing wrong in this direction is 4,000 GNOT. Dropping the four signing rows is four deleted lines if that trade is unwanted.

The four gnoland-1 founding validators are seeded as (signing address,
operator address) pairs -- `gnogenesis fork valoper-seed` requires the two to
be distinct so that a compromised signing key does not become control of the
validator slot. Six of those eight addresses held nothing in the sheet.

Every management action on a validator is a paid transaction: rotating the
signing key, editing the valoper profile, signalling opt-out. There is no
mainnet faucet and Constitution §126 locks ugnot transfers to the §127
exemption list, so an address that lands at zero at genesis can never be
funded afterwards and can never act. This closes the INITIAL_VALSET_OPERATORS
TODO(mainnet) in gnolang/gno's misc/deployments/mainnet.gno.land.

1,000 GNOT each, the same tier as the founders grant and the multisig signer
float, charged to the §122 Validator Services Treasury (§346 rules Ecosystem
out; Core already carries the founders). Two of the eight are skipped because
they are already funded -- aeddi by the founders grant, the Berty operator by
the signer float -- and their 1,000 stays in §122, exactly as Jae's skipped
founders grant stays in Core.

Supply-neutral: the Validator Services Treasury goes 20,000,000 ->
19,994,000 and the sheet total is unchanged at 1,332,999,998.328067 GNOT.
Account count 3,262,473 -> 3,262,479.

  balances.txt.gz  517c17546fba721dcbfcaa01d51a5772be253df4afe9499bdc5206f131021ab3
  genbalance.txt.gz 4228b52fafa4bb09f7fbb88a5e8c6a13fbf04acd7b617997a01ddab56fb4de3f
@moul
moul merged commit e37caa6 into main Sep 11, 2026
1 check passed
@moul
moul deleted the feat/genesis-validator-float branch September 11, 2026 13:30
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