Skip to content

v1.35

Choose a tag to compare

@rotilho rotilho released this 06 Sep 13:25
· 19 commits to main since this release
f9f59ff

Keeping consensus moving under pressure

More reliable elections, bounded network work, and a native container health-check command.

A node must keep processing transactions while representative weights change, database writes fail temporarily, and peers connect or send more work than it can handle at once. Version 1.35 strengthens these paths with current-weight election tallies, persistent retries, tighter resource limits, and more complete cleanup.

Highlights

  • Elections now use current representative weights when calculating consensus.
  • Failed election persistence keeps retrying with backoff instead of dropping work after a fixed number of attempts.
  • Votes can be accepted again after a recoverable transaction rejection.
  • Network requests, WebSocket queues, and asynchronous event execution now have explicit resource bounds.
  • Peer connection timeouts cancel abandoned sessions and resolve authentication races.
  • Voter REST isolation now uses the actual local listening port.
  • Container images include a native health-check command, with dedicated health probes available for Kubernetes.

Consensus and recovery

  • Both regular elections and bootstrap head elections calculate vote totals using current representative weights rather than weights captured when votes arrived.
  • Representative-weight updates retry when prerequisite updates have not arrived yet, avoiding incorrect initialization from out-of-order events.
  • Confirmed election results remain queued for persistence retry within the running process. Retry delays increase up to the configured maximum backoff.
  • Losing election candidates release their tracked dependencies when an election reaches consensus, expires, or is resolved by a saved transaction.
  • Recoverable transaction rejections no longer add transactions to the rejected-vote cache, allowing subsequent votes to be processed when dependencies become available.
  • Common block validation now also covers open blocks.

Bounded work and peer connections

  • Handshake processing now limits concurrent requests, body sizes, and body-read time. Callback responses also have explicit payload limits.
  • Incoming and outgoing WebSocket queues are bounded; connections close when their queues overflow.
  • Transaction lookups, vote requests, vote streams, and bootstrap head processing have concurrency limits. Historical transaction streams decline additional work while the stream handler is busy.
  • Asynchronous application events use a bounded virtual-thread executor that blocks publishers at capacity.
  • Outbound connections to non-default peers are capped, and duplicate connection attempts are suppressed before starting asynchronous work.
  • Connection timeouts cover validation and connection establishment, cancel abandoned sessions, and coordinate atomically with authentication.
  • Vote rebroadcast tracking is bounded by size and lifetime, and validated votes release their cached holders immediately.

Request validation and API isolation

  • Transaction-stream range validation rejects invalid heights and prevents arithmetic overflow from bypassing the range limit.
  • Non-historical voters enforce REST API isolation using the local listening port, independently of the request URI. The existing force-api override remains available.
  • Configured and remote peer public URIs are limited to 266 UTF-8 bytes.

Build, health checks, and configuration

  • Added /app/node healthcheck, which probes the local aggregate /health endpoint and returns a failing exit status when the endpoint is unavailable or unhealthy.

  • The published 1.35-live image includes the command and its health-check configuration. Podman 5.8.4 ignores that configuration in the OCI image; Podman Compose deployments should explicitly configure it:

    healthcheck:
      test: ["CMD", "/app/node", "healthcheck"]
      interval: 60s
      timeout: 5s
      start_period: 180s
      retries: 5
  • Enabled /health/liveness and /health/readiness on the management port. Kubernetes deployments should use liveness for startup and liveness probes, and readiness for readiness probes.

  • The health-check command uses port 8081 by default and respects MANAGEMENT_SERVER_PORT.

  • Refreshed GraalVM reachability metadata.

ATTO_ELECTION_PROCESSING_RETRY_MAX_ATTEMPTS has been removed because election persistence no longer stops after a fixed number of failures. Retry timing remains configurable through ATTO_ELECTION_PROCESSING_RETRY_INITIAL_BACKOFF_IN_SECONDS and ATTO_ELECTION_PROCESSING_RETRY_MAX_BACKOFF_IN_SECONDS, with defaults of 1 and 30 seconds respectively.

Full changelog: v1.34...v1.35