GossipSub

Gossip-based message propagation

XE uses GossipSub for broadcasting messages to all peers in the network. Each category of data has its own topic, and each topic has a dedicated gossip type with Publish() and Subscribe() methods.

#Topics

TopicConstantData TypeChannel Buffer
xe/blocksBlockTopicBlockMsg (wraps core.Block)256
xe/votesVoteTopicVoteMsg (wraps core.Vote)256
xe/marketplaceMarketplaceTopicMarketplaceMsg256
xe/statechainStateChainTopicStateChainMsg (wraps statechain.Block)16
xe/directoryDirectoryTopicdirectory.Registration256
xe/certificatesCertificateTopicperf.Certificate64

#Message Size Limit

go
const MaxGossipMessageSize = 262144 // 256 KB

The 256 KB limit accommodates state chain blocks which can carry large key-value data. Block lattice messages are much smaller but share the same PubSub instance.

#Gossip Types

All gossip types share a common PubSub instance created with NewPubSub():

go
func NewPubSub(ctx context.Context, h host.Host) (*pubsub.PubSub, error)

Each gossip type joins its respective topic and provides Publish() and Subscribe() methods.

#Block Gossip (Gossip)

Broadcasts and receives block lattice blocks.

go
type Gossip struct { /* ... */ } func NewGossip(ctx context.Context, h host.Host, ps ...*pubsub.PubSub) (*Gossip, error)func (g *Gossip) Publish(ctx context.Context, b *core.Block) errorfunc (g *Gossip) Subscribe(ctx context.Context) <-chan *core.Blockfunc (g *Gossip) PubSub() *pubsub.PubSub

The PubSub() accessor returns the underlying PubSub instance for sharing with other gossip types.

#Vote Gossip (VoteGossip)

Broadcasts and receives conflict resolution votes.

go
type VoteGossip struct { /* ... */ } func NewVoteGossip(ps *pubsub.PubSub) (*VoteGossip, error)func (vg *VoteGossip) Publish(ctx context.Context, v *core.Vote) errorfunc (vg *VoteGossip) Subscribe(ctx context.Context) <-chan *core.Vote

#State Chain Gossip (StateChainGossip)

Broadcasts and receives state chain blocks (governance operations).

go
type StateChainGossip struct { /* ... */ } func NewStateChainGossip(ps *pubsub.PubSub) (*StateChainGossip, error)func (sg *StateChainGossip) Publish(ctx context.Context, b *statechain.Block) errorfunc (sg *StateChainGossip) Subscribe(ctx context.Context) <-chan *statechain.Block

#Directory Gossip (DirectoryGossip)

Broadcasts and receives account directory registrations (human-readable name mappings).

go
type DirectoryGossip struct { /* ... */ } func NewDirectoryGossip(ps *pubsub.PubSub) (*DirectoryGossip, error)func (dg *DirectoryGossip) Publish(ctx context.Context, reg *directory.Registration) errorfunc (dg *DirectoryGossip) Subscribe(ctx context.Context) <-chan *directory.Registration

#Marketplace Gossip (MarketplaceGossip)

Broadcasts and receives marketplace messages (resource advertisements, requests, and offers).

go
type MarketplaceGossip struct { /* ... */ } func NewMarketplaceGossip(ps *pubsub.PubSub) (*MarketplaceGossip, error)func (mg *MarketplaceGossip) Publish(ctx context.Context, msg *MarketplaceMsg) errorfunc (mg *MarketplaceGossip) Subscribe(ctx context.Context) <-chan *MarketplaceMsg

#Pre-Validation

Messages are validated before being passed to consumers. This rejects malformed data before expensive cryptographic verification.

#Block Validation

text
// Hash and Account are 64 hex chars (32 bytes), Signature is 128 hex chars (64-byte ed25519)if len(b.Hash) != 64 || len(b.Signature) != 128 || len(b.Account) != 64 {    continue // drop}
FieldExpected LengthEncoding
Hash64 charsHex (32 bytes)
Signature128 charsHex (64 bytes)
Account64 charsHex (32 bytes)

#Vote Validation

text
// RepPubKey and BlockHash are 64 hex chars, Signature is 64 raw bytes (ed25519)if len(v.RepPubKey) != 64 || len(v.BlockHash) != 64 || len(v.Signature) != 64 {    continue // drop}

#State Chain Block Validation

text
// Hash must be 64 hex chars, at least one signature requiredif len(scm.Block.Hash) != 64 || len(scm.Block.Signatures) == 0 {    continue // drop}

#Directory Validation

text
// Account and Signature must be non-emptyif reg.Account == "" || reg.Signature == "" {    continue // drop}

#Marketplace Validation

text
// Type field must be non-emptyif mm.Type == "" {    continue // drop}

#Message Flow

diagram
Publisher Node                          Subscriber Node─────────────                          ───────────────     │                                       │     │  Publish(ctx, block)                  │     │     │                                 │     │     ▼                                 │     │  JSON marshal                         │     │     │                                 │     │     ▼                                 │     │  topic.Publish() ──── GossipSub ────▶ sub.Next()     │                                       │     │                                       ▼     │                                  JSON decode     │                                       │     │                                       ▼     │                                  Pre-validate     │                                       │     │                                  ┌────┴────┐     │                                  │ Valid?  │     │                                  └────┬────┘     │                                   yes │ no     │                                       │  └─▶ drop     │                                       ▼     │                                  ch <- block     │                                  (or drop if full)

#Backpressure

Each Subscribe method creates a buffered channel. If the consumer is slow and the channel fills up, incoming messages are dropped with a log warning:

text
gossip: block channel full, dropping block a1b2c3d4e5f6...

#JSON Encoding

All gossip messages use JSON encoding with encoding/json. Block and vote decoders use DisallowUnknownFields() for strict parsing. State chain and marketplace decoders use standard json.Unmarshal.

#Shared PubSub Instance

All gossip types share a single PubSub instance. The typical initialization order is:

go
// 1. Create shared PubSubps, err := xenet.NewPubSub(ctx, host) // 2. Create block gossip (can also create PubSub internally)blockGossip, err := xenet.NewGossip(ctx, host, ps) // 3. Create other gossip types sharing the same PubSubvoteGossip, err := xenet.NewVoteGossip(ps)stateChainGossip, err := xenet.NewStateChainGossip(ps)directoryGossip, err := xenet.NewDirectoryGossip(ps)marketplaceGossip, err := xenet.NewMarketplaceGossip(ps)