Deploying to devnet/mainnet-beta: the modexp-free build
The default domain_program.so — the one the surfpool test harness and every
cargo build-sbf build produce — cannot be deployed to devnet or
mainnet-beta today. Not because of anything wrong with it, but because of a
single syscall the DNSSEC-proof instructions reference. This page explains why,
and how to build a .so that does deploy there when you need to.
Historical note: before the domain-program split, the DNSSEC-proof instructions — and this whole problem — lived in
mail_program, and the modexp-free build was the only way to get any mail-program instruction (above all the postmaster reclaim tool) onto those clusters. Since the split,mail_programandalias_programare unconditionally modexp-free — their default builds deploy everywhere, no feature juggling — and only the domain program carries the proof path and its syscall.
Why the default build won’t deploy
When you deploy an SBF program, the Solana ELF loader resolves every syscall referenced anywhere in the binary, atomically, at deploy time. If the binary names a syscall the target cluster does not have active, the whole deploy is rejected — the loader will not deploy a program that references a syscall it cannot honour, even in a code path you never intend to call.
The DNSSEC-proof instructions —
AuthorizeDomainByProof,
WriteProofWitness, CloseProofWitness, and the three
…ReclaimByProof variants — verify RSA-2048
RRSIG signatures with the sol_big_mod_exp syscall (RSA modular
exponentiation; see the
proving-behaviour design note for the full chain-walk).
That syscall is gated behind Solana’s enable_big_mod_exp_syscall feature,
which is inactive on devnet and mainnet-beta today. So the default
domain_program.so, which contains those instructions, is undeployable there —
the loader rejects it on the sol_big_mod_exp reference alone. A single
undeployable instruction blocks everything: a program is deployed as a
whole, so the whole domain registry — CreateDomain, the marketplace, the
lot — is held up by the proof path’s syscall.
The fix: --no-default-features
The proof path lives behind the domain program’s dnssec-proof Cargo feature,
which is on by default. Turning it off drops the six proof instructions
from the binary — and with them the only sol_big_mod_exp reference — so the
resulting .so deploys cleanly on devnet/mainnet-beta:
cargo build-sbf --manifest-path domain_program/Cargo.toml --no-default-features
solana program deploy target/deploy/domain_program.so
In this build the six proof instructions stay in the (unchanging) on-chain ABI
enum — the discriminants do not move — but their handlers are compiled out. A
transaction that sends one is rejected at runtime with
InvalidInstructionData rather than dispatched. Every other instruction,
including AdminCloseAccount, is present and behaves exactly as in the default
build.
Note: the default (feature-on) build is unchanged and remains the one the surfpool/test harness deploys and the shipping bytecode on any cluster where
enable_big_mod_exp_syscallis active.--no-default-featuresis a deploy-target build, not a new default.mail_programandalias_programneed no equivalent — their default builds contain nosol_big_mod_expreference at all.
Verifying the binary is modexp-free
You can confirm the sol_big_mod_exp reference is truly gone — rather than
trust the build flag — by dumping the ELF’s dynamic symbols:
llvm-readelf --dyn-syms target/deploy/domain_program.so | grep -i mod_exp
The default build lists sol_big_mod_exp; the --no-default-features build
prints nothing. Zero matches is the deployable state. The same check against
target/deploy/mail_program.so prints nothing on every build — that
program is unconditionally modexp-free since the split.
The honest trade-off
A modexp-free binary is a deploy-unblock for the non-proof domain instructions, not a way to ship DNSSEC proof without RSA. Be clear-eyed about what it gives up:
- It cannot authorize or reclaim domains by proof at all — those
six instructions return
InvalidInstructionData. On such a cluster, domain authorization falls back to the delegate-signedCreateDomainpath. - Even if the six instructions were somehow reached, a binary without
sol_big_mod_expcan only verify a DNSSEC chain in which every link — including the ICANN root — signs with ECDSA P-256 (algorithm 13) or Ed25519 (algorithm 15), never RSA. The root KSK and most TLDs sign with RSA/SHA-256 (algorithm 8) today, so the modexp-free build has near-zero real-world domain-authorization-by-proof coverage. It is not a leaner DNSSEC verifier; it is a DNSSEC verifier with its most-used algorithm removed.
So this build exists for exactly one job: getting the domain registry’s non-proof instructions — domain lifecycle, the marketplace, the reclaim tool — onto a cluster where the proof path’s syscall is not yet available. It is not a configuration you would run a proof-carrying deployment on.
When to revisit
This whole workaround is temporary — it exists only because
enable_big_mod_exp_syscall is inactive on devnet/mainnet-beta. Check a
cluster’s feature status directly:
solana feature status | grep -i big_mod_exp
Once enable_big_mod_exp_syscall shows active on your target cluster, the
default (feature-on) domain_program.so deploys there with the full
DNSSEC-proof path intact, and there is no further reason to build
--no-default-features. The modexp-free build is a bridge for the window in
which that syscall is pending, not a permanent shape of the program.
See also
- Devnet-only vanity program IDs — a companion
devnet-deploy workaround for a separate problem (a bricked postoffice
singleton under the mainnet-track ID); a real devnet deploy of
domain_programcomposes both. - The Postmaster —
postmaster reclaim— theAdminCloseAccountreclaim tooling, present in both builds. - Closing accounts — the everyday (non-admin) account-close and rent-refund paths, all present in both builds.
- Authorize a domain by proof and Reclaim a domain by proof — the proof-carrying instructions the modexp-free build drops.
- Proving behaviour to the chain — the DNSSEC chain-walk
and its
sol_big_mod_expuse, in full. - Running a mail server — the
solana program deploystep these builds feed.