membership

package
v1.0.26 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package membership provides a transport-independent, signed membership protocol reference for CRDT replication groups. Gossip reports liveness but never changes the active set; only a signed View may fence a replica or change the tombstone-GC membership epoch.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidReceipt = errors.New("membership: invalid tombstone receipt")
	ErrReceiptReplay  = errors.New("membership: tombstone receipt replay")
)
View Source
var (
	ErrInvalidView      = errors.New("membership: invalid view")
	ErrInvalidSignature = errors.New("membership: invalid signature")
	ErrViewRollback     = errors.New("membership: view epoch rollback")
	ErrViewFork         = errors.New("membership: view predecessor mismatch")
	ErrGroupMismatch    = errors.New("membership: replication group mismatch")
	ErrMissingView      = errors.New("membership: missing persisted view")
)
View Source
var ErrInvalidGossip = errors.New("membership: invalid gossip message")

Functions

func ManifestHash

func ManifestHash(manifest replica.Manifest) [sha256.Size]byte

ManifestHash returns the control-plane binding digest for a replication manifest. It includes the membership/data-plane epoch, schema, codec, frame IDs, semantics version, and negotiated outer frame version; changing any of them requires a new signed View.

func MarshalGossipMessage

func MarshalGossipMessage(message GossipMessage) ([]byte, error)

MarshalGossipMessage returns a bounded canonical signed heartbeat.

func MarshalReceipt

func MarshalReceipt(receipt Receipt) ([]byte, error)

MarshalReceipt returns a bounded canonical signed tombstone receipt.

func MarshalView

func MarshalView(view View) ([]byte, error)

MarshalView returns the bounded canonical wire representation of a signed View. Call VerifyView with the configured authority key after decoding.

func SortedTags

func SortedTags(tags []crdt.Tag) ([]crdt.Tag, error)

SortedTags returns a sorted, duplicate-free copy suitable for a receipt. It is a convenience for producers that take tags from multiple chunks; it never infers a receipt from a frontier.

func VerifyView

func VerifyView(view View, authorityKey ed25519.PublicKey) error

VerifyView checks structure and authority signature. It does not decide whether the view follows a local predecessor; Manager.Install performs that stateful check after loading the durable current view.

Types

type GCBridge

type GCBridge[T comparable] struct {
	// contains filtered or unexported fields
}

GCBridge accepts authenticated receipts only for the active signed view and feeds their exact tags to Coordinator. It serializes each member's sequence to reject stale/replayed packets before they reach the GC path.

func NewGCBridge

func NewGCBridge[T comparable](manager *Manager[T]) (*GCBridge[T], error)

func (*GCBridge[T]) Apply

func (b *GCBridge[T]) Apply(receipt Receipt, target *set.ORSet[T]) (int, error)

Apply verifies receipt and performs exact acknowledgement/compaction on target. Callers must persist target's resulting OR-Set snapshot and HLC state before pruning acknowledgement records.

type Gossip

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

Gossip is a compact SWIM-style heartbeat/reference fanout engine. It signs source heartbeats, verifies them against the active View, and exposes deterministic peer selection for embedding transports. It does not open a socket, decide membership, or make a failure detector authoritative.

func NewGossip

func NewGossip(view View, selfID string, privateKey ed25519.PrivateKey, suspectAfter time.Duration) (*Gossip, error)

func NewGossipAt

func NewGossipAt(view View, selfID string, privateKey ed25519.PrivateKey, suspectAfter time.Duration, startedAt time.Time) (*Gossip, error)

NewGossipAt is NewGossip with an explicit local start time. It makes failure detector tests reproducible and starts the suspect timer for every active peer, including peers that have not yet sent a heartbeat.

func (*Gossip) Heartbeat

func (g *Gossip) Heartbeat() (GossipMessage, error)

Heartbeat returns a newly signed heartbeat. The embedding transport sends it to some or all targets returned by Peers; no membership state is changed.

func (*Gossip) Observe

func (g *Gossip) Observe(message GossipMessage, now time.Time) (LivenessEvent, bool, error)

Observe verifies and records a received heartbeat. Duplicate/out-of-order messages are harmless. A later valid heartbeat transitions a suspect peer back to Alive but cannot change the signed membership view.

func (*Gossip) Peers

func (g *Gossip) Peers(fanout int) []string

Peers deterministically selects up to fanout active peers. Determinism keeps simulations reproducible; changing heartbeat counters rotates selection without using a global random source.

func (*Gossip) Suspects

func (g *Gossip) Suspects(now time.Time) []LivenessEvent

Suspects returns newly suspected members. It never includes self and it never modifies the active-member set used by Coordinator.

type GossipMessage

type GossipMessage struct {
	GroupID     string
	Epoch       uint64
	ViewHash    [sha256.Size]byte
	From        string
	Incarnation uint64
	Counter     uint64
	Signature   []byte
}

GossipMessage is a signed heartbeat that may be forwarded over any application-selected transport. Counter is monotonic within an incarnation.

func UnmarshalGossipMessage

func UnmarshalGossipMessage(data []byte) (GossipMessage, error)

UnmarshalGossipMessage decodes a bounded canonical heartbeat. Observe verifies its signature against the current View before recording liveness.

type Liveness

type Liveness uint8

Liveness is deliberately separate from membership authorization. Suspect means an observer has not heard a heartbeat recently; it never permits the observer to remove a replica from a signed View or from tombstone GC.

const (
	Alive Liveness = iota + 1
	Suspect
)

type LivenessEvent

type LivenessEvent struct {
	MemberID string
	State    Liveness
}

LivenessEvent is emitted on a local state transition and is intended for observability or an external authority's decision process.

type Manager

type Manager[T comparable] struct {
	// contains filtered or unexported fields
}

Manager is the bridge from a signed authoritative View to a Coordinator. It persists a valid next view before fencing the local data plane at that epoch. The caller must use the same epoch in replica.Manifest during its authenticated handshake.

func NewManager

func NewManager[T comparable](initial View, authorityKey ed25519.PublicKey, store ViewStore) (*Manager[T], error)

NewManager verifies and durably installs initial before exposing a coordinator. It is suitable for first bootstrap and for a process that has obtained the currently authoritative view from its control plane.

func OpenManager

func OpenManager[T comparable](authorityKey ed25519.PublicKey, store ViewStore) (*Manager[T], error)

OpenManager restores a previously persisted signed view. Receipt state is intentionally not restored: losing it delays GC, while restoring an untrusted or stale receipt could compact too early.

func (*Manager[T]) Coordinator

func (m *Manager[T]) Coordinator() *tombstonegc.Coordinator[T]

Coordinator exposes the local exact-acknowledgement coordinator. All membership changes must continue through Install, never through direct ReplaceMembership calls.

func (*Manager[T]) Install

func (m *Manager[T]) Install(next View) error

Install verifies a direct successor, persists it, and then advances the coordinator epoch. A process crash after persistence is safe because OpenManager restores the newer fence; a crash before persistence leaves the older in-memory state and therefore only delays collection.

func (*Manager[T]) View

func (m *Manager[T]) View() View

View returns an immutable copy of the active view.

type Member

type Member struct {
	ID          string
	PublicKey   ed25519.PublicKey
	Incarnation uint64
}

Member is one stable logical replica authorized by a View. Incarnation must advance when a previously fenced replica is admitted again; a process must never silently resume replication with an older incarnation.

type MemoryStore

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

MemoryStore is a concurrency-safe store for tests, examples, and embedding applications that already provide their own durable control-plane store. It intentionally makes no durability claim.

func (*MemoryStore) LoadView

func (s *MemoryStore) LoadView() (View, bool, error)

func (*MemoryStore) SaveView

func (s *MemoryStore) SaveView(view View) error

type Receipt

type Receipt struct {
	GroupID      string
	Epoch        uint64
	ViewHash     [sha256.Size]byte
	MemberID     string
	Incarnation  uint64
	Sequence     uint64
	CheckpointID [sha256.Size]byte
	Tags         []crdt.Tag
	Signature    []byte
}

Receipt is an authenticated assertion by one crash-fault-trusted member that it has durably installed the listed tombstones in a non-zero checkpoint ID. A signature establishes origin and replay scope; it cannot prove honesty or durable storage against a Byzantine signer.

func SignReceipt

func SignReceipt(receipt Receipt, privateKey ed25519.PrivateKey) (Receipt, error)

SignReceipt returns a canonical signed copy. Tags must be sorted and unique so a receipt has exactly one byte representation and cannot inflate GC accounting through duplicate acknowledgements.

func UnmarshalReceipt

func UnmarshalReceipt(data []byte) (Receipt, error)

UnmarshalReceipt decodes a bounded canonical receipt. GCBridge.Apply verifies signature, view binding, member incarnation, and replay sequence.

type View

type View struct {
	GroupID      string
	Epoch        uint64
	PreviousHash [sha256.Size]byte
	ManifestHash [sha256.Size]byte
	Members      []Member
	Signature    []byte
}

View is the authoritative active-member set for exactly one replication group. ManifestHash binds this control-plane decision to the application replication manifest. PreviousHash forms an append-only view chain.

func SignView

func SignView(view View, privateKey ed25519.PrivateKey) (View, error)

SignView returns a canonical signed copy of view. The signing key is owned by the application's membership authority, not by an ordinary replica.

func UnmarshalView

func UnmarshalView(data []byte) (View, error)

UnmarshalView decodes a bounded canonical View. It validates only structure; callers must invoke VerifyView before treating it as authoritative.

func (View) Hash

func (v View) Hash() [sha256.Size]byte

Hash returns a stable digest of the signed view. It is the predecessor and receipt binding value, not a substitute for signature verification.

func (View) MatchesManifest

func (v View) MatchesManifest(manifest replica.Manifest) bool

MatchesManifest reports whether view fences exactly manifest. It is intended for an authenticated handshake before a replica accepts state, delta, or GC receipt traffic. A matching group ID alone is not sufficient.

func (View) Member

func (v View) Member(id string) (Member, bool)

Member returns a detached copy of the active member identified by id.

type ViewStore

type ViewStore interface {
	LoadView() (View, bool, error)
	SaveView(View) error
}

ViewStore persists a signed view before it is made active in memory. A real implementation must make Save durable before returning nil; a lost view could otherwise allow a restarted process to accept an old epoch.

Jump to

Keyboard shortcuts

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