Skip to content

serviceability: add ip_verifier_authority_pk to GlobalState and rotate it via SetAuthority - #4207

Open
elitegreg wants to merge 1 commit into
mainfrom
gm/globalstate-ip-verifier-authority
Open

serviceability: add ip_verifier_authority_pk to GlobalState and rotate it via SetAuthority#4207
elitegreg wants to merge 1 commit into
mainfrom
gm/globalstate-ip-verifier-authority

Conversation

@elitegreg

Copy link
Copy Markdown
Contributor

Closes #4196. Part of RFC-27 (rfcs/rfc27-ip-verification.md); tracker #4194.

Summary

  • GlobalState carries ip_verifier_authority_pk, the trust root for RFC-27 IP ownership proof validation, so the verifier key rotates without a program upgrade.
  • SetAuthority gains an optional ip_verifier_authority_pk; authorization is unchanged (GLOBALSTATE_ADMIN permission or the legacy foundation path).
  • doublezero global-config authority set --ip-verifier-authority <pubkey|me> rotates the key, and authority get reports it in both the table and JSON views.
  • The Rust SDK SetAuthorityCommand forwards the new field.
  • Pubkey::default() means "no verifier configured". Enforcement, which lands with the onchain validation issue, must treat that as a hard reject rather than as "any signature passes".

Details

The field is append-only, so accounts written before it existed deserialize with Pubkey::default() through the same unwrap_or_default() path feed_authority_pk uses. On the instruction side, BorshDeserializeIncremental keeps transactions built against the old argument layout decoding, with the new field defaulting to None.

SDK deserializer work for Go, TypeScript, and Python is tracked separately. The global_state fixture is regenerated here because CI's make check-fixtures diffs the goldens against the Rust producer; all three readers ignore trailing bytes and skip meta fields they do not map, so they stay green until that work lands. Running the generator also refreshed its Cargo.lock from 0.31.0 to 0.36.0.

smartcontract/cli/src/init.rs needed no change: it sends InitGlobalState and carries no authority arguments, and the program's initializer seeds the new field to Pubkey::default().

Testing Verification

  • New tests/setauthority_test.rs: rotating the verifier key leaves the other authorities, the foundation allowlist, and the feature flags untouched; a second rotation replaces the previous key; and a later SetAuthority passing None does not clear it. It also asserts a freshly initialized GlobalState reads Pubkey::default(), the state enforcement must reject.
  • Backwards compatibility against the committed base64 vector: it reads back Pubkey::default(), and re-serialized with the field set it round-trips with every other field identical. Note that this stored vector is old enough that its bytes end at user_airdrop_lamports, so appending 32 bytes to it would not have exercised the new field.
  • SetAuthorityArgs unit tests: a pre-field four-option encoding still decodes with ip_verifier_authority_pk: None, and the new field round-trips.
  • Go, TypeScript, and Python SDK suites pass against the regenerated fixture.

…e it via SetAuthority

The RFC-27 verifier public key is the trust root for IP ownership proof
validation. Storing it in onchain global state lets it rotate without a
program upgrade.

The field is appended to GlobalState, so accounts written before it existed
deserialize with Pubkey::default() through the same unwrap_or_default() path
feed_authority_pk uses. Pubkey::default() means no verifier is configured,
which enforcement must treat as a hard reject rather than as a bypass.

SetAuthority gains an optional ip_verifier_authority_pk;
BorshDeserializeIncremental keeps transactions built against the old argument
layout decoding, with the new field defaulting to None. Authorization is
unchanged: GLOBALSTATE_ADMIN or the legacy foundation path.

The CLI surfaces the key through global-config authority set/get, and the
Rust SDK SetAuthority command builder forwards it. SDK deserializer work for
Go, TypeScript, and Python is tracked separately; the regenerated
global_state fixture already carries the field for that work to land against.
@elitegreg
elitegreg marked this pull request as ready for review August 18, 2026 00:56
@elitegreg
elitegreg enabled auto-merge (squash) August 18, 2026 00:56
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.

serviceability: add ip_verifier_authority_pk to GlobalState and rotate it via SetAuthority

1 participant