Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

beacon package

Overview

Package beacon is SPLASH's on-chain record of the drand evmnet randomness beacon.

WHAT CHANGED, AND WHY IT IS NOT A REFACTOR (2026-09-28). This realm used to verify signatures from a beacon SPLASH itself ran: one compiled-in BLS key, held by this project, publishing a round every five minutes. The key holder could sign ANY round at will and therefore knew every future round's randomness permanently, which is r/splash/arcade/raffle/AUDIT-2026-09-28.md findings 4 and 10 and was the single worst property of the product. It now verifies drand evmnet, a threshold beacon this project does not control. Two consequences run through every comment below:

  • NOBODY CAN SIGN A FUTURE ROUND. Round r's signature does not exist before its time, and no party below the DKG threshold can make it exist. That is what the games' round bindings are for and it is now true rather than assumed.
  • NOBODY CAN DESTROY A PAST ROUND. Every round from 1 to the head is served forever by at least three independent relays, and Publish is permissionless, so anything deleted here is re-creatable by anyone. "The randomness is lost" stopped being a reachable state, which is why Prune, PruneWindow and the raffle's resolvable() are gone -- see DRAND-MIGRATION.md section 3.

THIS REALM IS NOT A MIRROR OF DRAND AND MUST NEVER BECOME ONE. At a three-second cadence, keeping up would mean one Publish every three seconds at 16,970,375 gas each: 0.62% of EVERY BLOCK on the chain, for ever, for data that is read about fifty times a year (DRAND-MIGRATION.md sections 2 and 9.5 have the measured arithmetic; 9.5 also records that this said 2.4% until 2026-09-30, off by the same 4.4x as every other gas figure derived from the pre-optimisation VerifyDrand, and that at 0.62% the STORAGE cost rather than the gas share is what rules mirroring out). It is an ON-DEMAND RECORD: a round is stored when something on this chain has a reason to look at it, and nothing else is stored at all.

There is no owner, no pause and no upgrade path. Once a round is published its randomness is fixed for ever.

Function

Publish

func Publish(cur realm, round int64, sigHex string)
Ask AI Claude ChatGPT

Publish verifies sig for round against drand evmnet's group key and stores it. PERMISSIONLESS: anyone may relay any round, because validity is what matters and not the sender. Panics if the round is already published or the signature does not verify — including if sigHex is not valid hex, which is just another shape of "not a valid signature".

THE ROUND NUMBER IS THE MESSAGE and the caller supplies nothing else: the signed digest is keccak256 of the round as a big-endian uint64 (bls254.DrandRoundMessage), so a relayer cannot choose what a round's randomness is, only whether to relay it. The chain is UNCHAINED, so no previous signature is needed and any round verifies on its own.

bls254.VerifyDrand, NOT bls254.Verify. The two implement different schemes and each rejects every signature of the other; Verify is the retired SPLASH try-and-increment scheme and is left untouched, still exercised by p/splash/bls254's own suite.

COST: 16,970,375 gas measured on this toolchain (zz_gas_test.gno), 0.57% of the 3e9 block limit — about 176 to a block. Of it, 13,396,451 is bls254.VerifyDrand and 12,004,207 of THAT is the RFC 9380 hash-to-curve rather than the pairing: 90% of the verification, 71% of the whole Publish. (CORRECTED 2026-09-30: this said "98%", which was the pre-optimisation ratio; DRAND-MIGRATION.md section 9.5.) It fits with a wide margin, and it is also the reason this realm cannot mirror drand.

A RELAYER CANNOT PUSH latestRound INTO THE FUTURE, and a great deal now rests on that. Under the SPLASH key one Publish of a far-future round moved latest arbitrarily far in a single transaction, which was the operator-triggered half of AUDIT-2026-09-28.md finding 7. drand cannot sign a round whose time has not come, so latestRound is bounded above by drand's real head, and that attack is dead.

Params

Command

# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.

gnokey maketx call -pkgpath "gno.land/r/g1r4aw43kagaaquhegxw6xr346h9f2qu2ezf0jar/beacon" -func "Publish" -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -chainid "onyx-1" -remote "https://rpc.onyx.testnets.gno.land" ADDRESSgnokey query -remote "https://rpc.onyx.testnets.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/g1r4aw43kagaaquhegxw6xr346h9f2qu2ezf0jar/beacon" -func "Publish" -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "onyx-1" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.onyx.testnets.gno.land" call.tx