privval

package
v0.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 1, 2026 License: Apache-2.0, UNKNOWN not legal advice Imports: 0 Imported by: 0

Documentation

Overview

* PrivValidator * * Package privval implements the BFT validator interface defined in tm2/pkg/bft/types.PrivValidator. * The validator role is to sign votes and proposals for the consensus protocol, ensuring that it never * double-signs, even in the case of a crash during the signing process or a malicious attack. * * To achieve this, the PrivValidator relies on two components: * - a signer that generates cryptographic signatures for arbitrary byte slices without any checks. * - a state that both stores and verifies the last signature and signed data to prevent double-signing. * * * Signer * * The signer implements the BFT signer interface defined in tm2/pkg/bft/types.Signer. Two implementations * are provided in this package: * - a local signer that uses a keypair encoded with amino and persisted to disk (default for gnoland nodes). * - a remote signer that uses a client sending signing requests to a remote signer server. * * Both the remote signer client and server are provided in tm2/pkg/bft/privval/signer/remote. The current * implementation supports TCP and UNIX socket connections. * * TCP connections are secured using the cryptographic handshake defined in tm2/pkg/p2p/conn.MakeSecretConnection * which is an implementation of the STS protocol described in this whitepaper: * https://github.com/tendermint/tendermint/blob/0.1/docs/sts-final.pdf * TCP connections can optionally be mutually authenticated using a whitelist of authorized public keys for both * the client and the server. * * By default, the remote signer client will indefinitely try to connect to the remote signer server for each * request it sends. Consequently, a node using a private validator with a remote signer will not fail due to * temporary network issues or a crash of the remote signer server. * * The remote signer server provided by this package is a generic bridge that take any types.Signer as a * parameter and proxies the client requests to it. Additionally, gnokms is a CLI tool available in * contribs/gnokms that aims to provide a remote signer server along with a set of backend signers, including * one based on gnokey. * * * State * * The state manager defined in tm2/pkg/bft/privval/state does not implement any interface. It basically keeps * track of the last signature and signed data to prevent double-signing. The state is persisted to disk in a * file encoded with amino and all checks are performed locally.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewPrivValidatorFromConfig

func NewPrivValidatorFromConfig(
	config *PrivValidatorConfig,
	clientPrivKey ed25519.PrivKeyEd25519,
	clientLogger *slog.Logger,
) (types.PrivValidator, error)

NewPrivValidatorFromConfig returns a types.PrivValidator chosen by config:

  • if TmkmsListener is enabled, build the upstream-protocol listener stack (TCPListener → SignerListenerEndpoint → SignerClient → RetrySignerClient);
  • otherwise return the existing local-or-remote-signer concrete *PrivValidator (with FileState-backed HRS gating).

Return type is the interface so callers don't need to special-case the listener path. The concrete *PrivValidator type is still accessible via type assertion for paths that need it (e.g., tests poking at the inner signer).

The clientPrivKey is the validator's node identity key; it's used as the SecretConnection identity for both remote-signer-client and tmkms-listener modes.

func NewSignerFromConfig

func NewSignerFromConfig(
	ctx context.Context,
	config *PrivValidatorConfig,
	clientPrivKey ed25519.PrivKeyEd25519,
	clientLogger *slog.Logger,
) (types.Signer, error)

NewSignerFromConfig returns a new Signer instance based on the configuration. The ctx and clientLogger are only used for the remote signer client. The clientPrivKey is only used for the remote signer client using a TCP connection.

Types

type PrivValidator

type PrivValidator struct {
	// contains filtered or unexported fields
}

PrivValidator signs votes and proposals for the consensus protocol using a signer (which can be either local or remote) and a state file to ensure that the validator never double sign, even in the case of a crash.

func NewPrivValidator

func NewPrivValidator(signer types.Signer, stateFilePath string) (*PrivValidator, error)

NewPrivValidator returns a new PrivValidator instance with the given signer and state file path. If the state file does not exist, it will be created.

func (*PrivValidator) Close

func (pv *PrivValidator) Close() error

Close implements types.PrivValidator.

func (*PrivValidator) PubKey

func (pv *PrivValidator) PubKey() crypto.PubKey

PubKey returns the public key of the private validator signer.

func (*PrivValidator) SignProposal

func (pv *PrivValidator) SignProposal(chainID string, proposal *types.Proposal) error

SignProposal signs a proposal using the private validator's signer and updates the state file to prevent double signing.

func (*PrivValidator) SignVote

func (pv *PrivValidator) SignVote(chainID string, vote *types.Vote) error

SignVote signs a vote using the private validator's signer and updates the state file to prevent double signing.

func (*PrivValidator) String

func (pv *PrivValidator) String() string

String implements fmt.Stringer.

type PrivValidatorConfig

type PrivValidatorConfig struct {
	// File path configuration.
	RootDir     string `json:"home" toml:"home"`
	SignState   string `` /* 129-byte string literal not displayed */
	LocalSigner string `` /* 138-byte string literal not displayed */

	// Remote Signer configuration (tm2-native protocol; validator dials gnokms).
	RemoteSigner *rsclient.RemoteSignerClientConfig `json:"remote_signer" toml:"remote_signer" comment:"Configuration for the remote signer client (gnokms)"`

	// TmkmsListener configures the upstream-Tendermint-protocol listener (validator
	// listens for tmkms / Horcrux to dial in). Mutually exclusive with RemoteSigner;
	// see upstream_config.go.
	TmkmsListener *TmkmsListenerConfig `` /* 164-byte string literal not displayed */
}

PrivValidatorConfig defines the configuration for the PrivValidator, with a local signer (file-based key), a gnokms remote signer (tm2-native protocol), or a tmkms listener (upstream Tendermint privval protocol — the validator listens for tmkms to dial in). At most one of RemoteSigner or TmkmsListener may be enabled.

func DefaultPrivValidatorConfig

func DefaultPrivValidatorConfig() *PrivValidatorConfig

DefaultPrivValidatorConfig returns a default configuration for the PrivValidator.

func TestPrivValidatorConfig

func TestPrivValidatorConfig() *PrivValidatorConfig

TestPrivValidatorConfig returns a configuration for testing the PrivValidator.

func (*PrivValidatorConfig) LocalSignerPath

func (cfg *PrivValidatorConfig) LocalSignerPath() string

LocalSignerPath returns the complete path for the local signer file.

func (*PrivValidatorConfig) SignStatePath

func (cfg *PrivValidatorConfig) SignStatePath() string

SignStatePath returns the complete path for the sign state file.

func (*PrivValidatorConfig) ValidateBasic

func (cfg *PrivValidatorConfig) ValidateBasic() error

ValidateBasic performs basic validation (checking param bounds, etc.) and returns an error if any check fails.

type TmkmsListenerConfig

type TmkmsListenerConfig struct {
	// ListenAddr is the validator's listen address for inbound signer
	// connections. Format: "tcp://0.0.0.0:26659" or
	// "unix:///var/run/gnoland/privval.sock". An empty value disables
	// this mode (the existing local/remote-client paths apply).
	ListenAddr string `` /* 141-byte string literal not displayed */

	// AllowedKMSPubKeys is the allowlist of expected signer pubkeys.
	// Each entry is a hex-encoded ed25519 pubkey (32 bytes → 64 hex
	// chars), optionally with an "ed25519:" prefix. It is the only
	// authorization control on a tcp:// listener and is required there
	// (an empty list would accept any peer that completes the
	// SecretConnection handshake). On a unix:// listener it is ignored —
	// the boundary is filesystem permissions, not the pubkey allowlist.
	AllowedKMSPubKeys []string `` /* 204-byte string literal not displayed */

	// ChainID is sent in PubKeyRequest/SignVoteRequest/SignProposalRequest.
	// tmkms verifies its configured chain_id matches, refusing to sign
	// for a different network. Required for production; equivalent to
	// the chain_id field in tmkms's [[validator]] block.
	ChainID string `json:"chain_id" toml:"chain_id" comment:"Chain ID sent to the signer; must match tmkms.toml's [[validator]] chain_id."`

	// ProtocolVersion pins the upstream Tendermint privval dialect.
	// Today only "v0.34" is supported — the canonical sign-bytes in
	// upstreampb are wired to v0.34's protobuf shape. Mirrors tmkms's
	// [[validator]].protocol_version; both sides MUST agree. We refuse
	// any other value at startup rather than silently misencode votes.
	ProtocolVersion string `` /* 186-byte string literal not displayed */

	// TimeoutReadWrite is the read/write deadline applied to the held
	// signer connection. Default 5s, matching cometbft.
	TimeoutReadWrite time.Duration `json:"timeout_read_write" toml:"timeout_read_write" comment:"Read/write deadline for signer connections (default 5s)."`

	// WaitForConnectionTimeout caps how long Init() blocks waiting for
	// the signer to dial in at startup. Default 60s.
	WaitForConnectionTimeout time.Duration `` /* 144-byte string literal not displayed */

	// Retries is the per-Sign retry budget on transient errors. Zero
	// means retry forever (matches cometbft's RetrySignerClient
	// convention). Default 5.
	Retries int `json:"retries" toml:"retries" comment:"Per-Sign retry attempts on transient errors. 0 = infinite (default 5)."`

	// RetryTimeout is the sleep between retry attempts. Default 1s.
	RetryTimeout time.Duration `json:"retry_timeout" toml:"retry_timeout" comment:"Sleep between retry attempts (default 1s)."`
}

TmkmsListenerConfig configures the upstream-Tendermint-protocol listener. Field types and JSON/TOML tags chosen to match cometbft's config style for operator familiarity.

func DefaultTmkmsListenerConfig

func DefaultTmkmsListenerConfig() *TmkmsListenerConfig

DefaultTmkmsListenerConfig returns a config with reasonable defaults but ListenAddr unset (so the mode is OFF by default — operator must opt in). AllowedKMSPubKeys is an empty slice (not nil) so TOML round- trip is byte-stable; matches the convention in rsclient.DefaultRemoteSignerClientConfig.

func (*TmkmsListenerConfig) IsEnabled

func (c *TmkmsListenerConfig) IsEnabled() bool

IsEnabled reports whether the listener mode is configured (i.e., ListenAddr is set). Used by NewPrivValidatorFromConfig to decide which factory branch to take.

func (*TmkmsListenerConfig) ParseAllowlist

func (c *TmkmsListenerConfig) ParseAllowlist() ([]ed25519.PubKeyEd25519, error)

ParseAllowlist decodes AllowedKMSPubKeys into typed ed25519 pubkeys. An entry may be a bare 64-hex-char string or prefixed with "ed25519:". An empty list returns nil — the caller treats nil as "accept any".

func (*TmkmsListenerConfig) ValidateBasic

func (c *TmkmsListenerConfig) ValidateBasic() error

ValidateBasic is invoked by the parent PrivValidatorConfig.ValidateBasic. Only checks fields when the mode is enabled.

The allowlist requirement is scheme-dependent. On a tcp:// listener the allowlist is the only authorization control: an empty allowlist accepts any peer that completes the SecretConnection handshake — a footgun in production (a misconfigured firewall plus an attacker who can mint an ed25519 keypair would be enough to substitute the signer), so a non-empty allowlist is required. On a unix:// listener the allowlist is not enforced at all (NewUnixListener does no SecretConnection); the boundary there is filesystem permissions, so we neither require nor honor it — if one is configured, newTmkmsListenerPrivValidator logs that it is ignored.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL