hecate_plumtree (macula v10.8.0)

View Source

Plumtree push-lazy gossip (Leitão, Pereira, Rodrigues 2007 — Part 3 §7.2).

Disseminates realm-scoped messages over HyParView's active view with a tree-emergent topology and lazy-push recovery.

State

  • eager_push — peers receiving full GOSSIP payloads. The eager-push set is the Plumtree spanning tree.
  • lazy_push — peers receiving only IHAVE announcements. They graft into eager_push when they GRAFT in response to an IHAVE.
  • receivedMsgId => Payload map of messages we've delivered locally. Used to dedup repeat GOSSIPs and to answer GRAFTs.
  • missingMsgId => [Peer] for peers who sent IHAVE for messages we have not yet received in full.

Message handling

  • Local publish — record the message, deliver locally, GOSSIP to every eager peer, IHAVE to every lazy peer.
  • Receive GOSSIP — if first time: deliver, remove from missing, eager-forward to every other eager peer, IHAVE-forward to every lazy peer, ensure sender is eager. If duplicate: PRUNE the sender + move sender from eager to lazy.
  • Receive IHAVE — if already received, ignore. Else: record sender in missing and emit a GRAFT to the sender right away (Phase 5.3 MVP — a real deployment delays the GRAFT briefly to give the eager push a chance to win the race; the MVP eager-grafts which is correct but slightly heavier).
  • Receive GRAFT — sender becomes eager; reply with the GOSSIP payload if we have it, drop silently if not.
  • Receive PRUNE — move sender from eager to lazy.

This module is pure. The wrapping process is responsible for transmitting the action list and feeding deliveries to the local consumer.

Reference: plans/PLAN_MACULA_V2_PART3_DISCOVERY.md §7.2; plans/PLAN_PHASE_5_BREAKDOWN.md Session 5.3.

Summary

Functions

When HyParView promotes a peer to active, the Plumtree layer adds it to the eager-push set. Any GOSSIP we publish will reach the new peer immediately.

When HyParView removes a peer from active, the Plumtree layer removes it from both push sets.

Types

action/0

-type action() :: {send, peer(), macula_frame:frame()}.

delivery/0

-type delivery() :: {msg_id(), term()}.

msg_id/0

-type msg_id() :: <<_:128>>.

peer/0

-type peer() :: macula_identity:pubkey().

state/0

-type state() ::
          #{self_id := peer(),
            realm := <<_:256>>,
            identity := macula_identity:key_pair(),
            eager_push := sets:set(peer()),
            lazy_push := sets:set(peer()),
            received := #{msg_id() => term()},
            missing := #{msg_id() => sets:set(peer())}}.

Functions

add_peer(S, Peer)

-spec add_peer(state(), peer()) -> state().

When HyParView promotes a peer to active, the Plumtree layer adds it to the eager-push set. Any GOSSIP we publish will reach the new peer immediately.

eager_peers(_)

has_received(MsgId, _)

lazy_peers(_)

missing_count(_)

new(Identity, Realm)

-spec new(macula_identity:key_pair(), <<_:256>>) -> state().

process(State, From, F)

-spec process(state(), peer(), macula_frame:frame()) -> {state(), [action()], [delivery()]}.

publish(State, MsgId, Payload)

-spec publish(state(), msg_id(), term()) -> {state(), [action()], [delivery()]}.

realm(_)

received_count(_)

remove_peer(S, Peer)

-spec remove_peer(state(), peer()) -> state().

When HyParView removes a peer from active, the Plumtree layer removes it from both push sets.

self_id(_)