Documentation
¶
Overview ¶
Package admin serves the voting-config endpoint by proxying the GitHub Pages CDN (valargroup/token-holder-voting-config) and exposes HTTP endpoints for validator join registration (pending queue in SQLite).
Published vote_servers URLs are updated via manual PRs on the config repo; this package does not write to GitHub.
Index ¶
- Constants
- func AddressToValoper(address string) (string, error)
- func RegisterRoutes(router *mux.Router, getAdmin func() *Admin, logger log.Logger)
- func RegisterUIConfigRoutes(router *mux.Router, logger log.Logger)
- func RunPendingSweeper(ctx context.Context, a *Admin, interval time.Duration, logger log.Logger)
- func RunWatchdog(ctx context.Context, adm *Admin, interval time.Duration, logger log.Logger)
- func VerifyArbitrarySignature(signerAddress, payload string, signatureB64, pubKeyB64 string) error
- type Admin
- type BondingChecker
- type Config
- type PendingRegistration
- type PendingValidatorPublic
- type ServiceEntry
- type Store
- func (s *Store) Close() error
- func (s *Store) EvictExpiredPending() (int64, error)
- func (s *Store) ListPendingRegistrations() ([]PendingRegistration, error)
- func (s *Store) RemovePendingRegistration(operatorAddress string) (bool, error)
- func (s *Store) UpsertPendingRegistration(r PendingRegistration) error
- type UIConfigResponse
- type UIMode
- type VotingConfig
Constants ¶
const PendingEvictionSweepInterval = time.Hour
PendingEvictionSweepInterval is how often expired pending_registrations rows are deleted (not configurable).
const PendingRegistrationTTL = 7 * 24 * time.Hour
PendingRegistrationTTL is how long an operator remains in the pending join queue before the row expires (SQLite; not configurable).
Variables ¶
This section is empty.
Functions ¶
func AddressToValoper ¶
AddressToValoper converts an account bech32 address to a valoper address.
func RegisterRoutes ¶
RegisterRoutes registers admin HTTP routes on the given mux router.
func RegisterUIConfigRoutes ¶ added in v0.5.6
RegisterUIConfigRoutes registers GET /api/ui-config on the given router.
All values are resolved once at registration time from environment vars. Changing them requires a restart, which matches how the rest of the daemon reads its configuration.
func RunPendingSweeper ¶ added in v0.5.12
RunPendingSweeper periodically deletes expired pending_registrations rows. It blocks until ctx is cancelled.
func RunWatchdog ¶ added in v0.5.7
RunWatchdog periodically probes every vote server and PIR endpoint listed in voting-config.json and fires Sentry alerts on failure. It blocks until ctx is cancelled.
func VerifyArbitrarySignature ¶
VerifyArbitrarySignature verifies a Keplr-style ADR-036 signArbitrary signature. It checks that:
- The secp256k1 signature is valid over the amino sign doc.
- The public key derives to the claimed signer address.
Hashing note: secp256k1.PubKey.VerifySignature already SHA-256s its input before ECDSA verification, mirroring secp256k1.PrivKey.Sign on the signing side (which is what `svoted sign-arbitrary` and any Keplr/ADR-036 signer invoke via Keyring.Sign). We therefore pass the raw amino sign doc here — pre-hashing it would cause a double-hash and reject every real signature.
Types ¶
type Admin ¶
type Admin struct {
// contains filtered or unexported fields
}
Admin fetches and caches voting-config from the CDN and stores pending validator registrations in SQLite.
func New ¶
New creates a new Admin from the given configuration. homeDir is used to resolve default DBPath when cfg.DBPath is empty. checkBonded may be nil; in that case bonding checks always return false.
func (*Admin) GetVotingConfig ¶ added in v0.5.0
func (a *Admin) GetVotingConfig() (*VotingConfig, error)
GetVotingConfig returns the cached voting config, refreshing if stale.
func (*Admin) IsBonded ¶ added in v0.5.12
IsBonded reports whether the operator account (bech32) is bonded as a validator.
func (*Admin) RefreshConfig ¶ added in v0.5.7
func (a *Admin) RefreshConfig() (*VotingConfig, error)
RefreshConfig forces a reload of voting-config from the CDN and returns the new value. Used by the fleet health watchdog on every tick so it picks up newly added/removed servers without a process restart.
type BondingChecker ¶
BondingChecker returns whether the validator with the given valoper bech32 is currently bonded.
type Config ¶
type Config struct {
// Disable turns off the admin server entirely.
Disable bool `mapstructure:"disable"`
// ConfigURL is the GitHub Pages CDN URL for the voting-config JSON.
ConfigURL string `mapstructure:"config_url"`
// WatchdogInterval is how often the fleet health watchdog probes all
// vote servers and PIR endpoints listed in voting-config.json. Set to
// 0 to disable the watchdog. Default: 5 minutes.
WatchdogInterval time.Duration `mapstructure:"watchdog_interval"`
// DBPath is the SQLite path for pending validator registrations.
// Default: $HOME/.svoted/admin.db (resolved in New).
DBPath string `mapstructure:"db_path"`
}
Config holds the admin server configuration, read from app.toml admin.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the default admin configuration.
type PendingRegistration ¶
type PendingRegistration struct {
OperatorAddress string `json:"operator_address"`
URL string `json:"url"`
Moniker string `json:"moniker"`
Timestamp int64 `json:"timestamp"`
Signature string `json:"signature,omitempty"`
PubKey string `json:"pub_key,omitempty"`
FirstSeenAt int64 `json:"first_seen_at"`
LastSeenAt int64 `json:"last_seen_at"`
ExpiresAt int64 `json:"expires_at"`
}
PendingRegistration is a row in pending_registrations and the API shape for GET /api/pending-validators.
type PendingValidatorPublic ¶ added in v0.5.12
type PendingValidatorPublic struct {
OperatorAddress string `json:"operator_address"`
URL string `json:"url"`
Moniker string `json:"moniker"`
Timestamp int64 `json:"timestamp"`
FirstSeenAt int64 `json:"first_seen_at"`
LastSeenAt int64 `json:"last_seen_at"`
ExpiresAt int64 `json:"expires_at"`
}
PendingValidatorPublic is returned by GET /api/pending-validators (no secrets).
type ServiceEntry ¶
type ServiceEntry struct {
URL string `json:"url"`
Label string `json:"label"`
OperatorAddress string `json:"operator_address,omitempty"`
}
ServiceEntry is the wire format for a server in the voting-config response.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a SQLite-backed store for pending validator registrations.
func (*Store) EvictExpiredPending ¶ added in v0.5.12
EvictExpiredPending deletes rows whose expires_at is in the past.
func (*Store) ListPendingRegistrations ¶
func (s *Store) ListPendingRegistrations() ([]PendingRegistration, error)
ListPendingRegistrations returns non-expired pending registrations.
func (*Store) RemovePendingRegistration ¶
RemovePendingRegistration deletes a pending row by operator address. Returns true if a row was deleted.
func (*Store) UpsertPendingRegistration ¶
func (s *Store) UpsertPendingRegistration(r PendingRegistration) error
UpsertPendingRegistration inserts or updates a pending registration. first_seen_at is preserved on conflict; last_seen_at is always updated.
type UIConfigResponse ¶ added in v0.5.6
type UIConfigResponse struct {
// Mode is "dev" or "prod". The UI uses this to gate developer-only widgets.
Mode UIMode `json:"mode"`
// DevPIRControls is a denormalised flag for the most common gate so the UI
// does not need to know the meaning of each mode value.
DevPIRControls bool `json:"dev_pir_controls"`
// PrecomputedBaseURL is the bucket origin that this svoted's PIR siblings
// fetch their snapshots from. The UI composes the manifest URL as
// "<base>/snapshots/<height>/manifest.json" using a shared subpath
// constant. Resolved at startup from SVOTE_PRECOMPUTED_BASE_URL with a
// production-bucket default. Has no trailing slash.
PrecomputedBaseURL string `json:"precomputed_base_url"`
}
UIConfigResponse is the wire format returned by GET /api/ui-config.
It carries everything the static admin UI bundle needs to know about the svoted instance it's served by. New fields should be additive — older UI builds must continue to work against newer servers.
type UIMode ¶ added in v0.5.6
type UIMode string
UIMode controls which features the admin UI exposes.
"prod" hides developer-only controls such as the in-process PIR rebuild triggers. "dev" enables them. Production deployments must explicitly set SVOTE_UI_MODE=dev to opt in to the developer surface; the default is "prod" so a forgotten environment file can never accidentally expose them.
const ( UIModeProd UIMode = "prod" UIModeDev UIMode = "dev" // DefaultPrecomputedBaseURL is the production DigitalOcean Spaces bucket // where the publish-snapshot workflow uploads pre-computed PIR snapshots. // Per-deployment overrides go through SVOTE_PRECOMPUTED_BASE_URL so a // staging svoted can point at a staging bucket. DefaultPrecomputedBaseURL = "https://vote.fra1.digitaloceanspaces.com" )
type VotingConfig ¶
type VotingConfig struct {
Version int `json:"version"`
VoteServers []ServiceEntry `json:"vote_servers"`
PIRServers []ServiceEntry `json:"pir_endpoints"`
// SnapshotHeight is the canonical Orchard nullifier-tree snapshot height
// for the current voting round. PIR servers must serve this exact height,
// and the admin UI auto-populates round drafts from it.
SnapshotHeight *uint64 `json:"snapshot_height,omitempty"`
}
VotingConfig is the wire format returned by GET /api/voting-config.