Subscription Registry

Purpose

The Subscription Registry addresses the challenge of efficiently managing real-time blockchain event subscriptions on a per-client and per-address basis. Within the broader context of real-time subscription management, it provides a centralized mechanism to track which WebSocket clients have subscribed to updates for specific blockchain addresses. This ensures that when new transactions or blocks arrive, only the relevant clients receive notifications, optimizing resource usage and improving event delivery precision.

Functionality

At its core, the Subscription Registry maintains two complementary mappings:

This bidirectional structure allows quick lookup and efficient broadcasting of events.

Key Workflows

  1. Subscription Management:

    When a client subscribes to a set of addresses, the registry:

    • Normalizes addresses (e.g., lowercasing) for consistent matching.

    • Records the client’s unique subscription ID alongside each subscribed address.

    • Updates internal maps to reflect these associations.

  2. Unsubscription:

    Clients can unsubscribe from specific addresses or all addresses associated with a subscription. The registry removes these links and cleans up any empty records to avoid stale entries.

  3. Event Handling:

    Upon receiving new blockchain data (blocks or individual transactions) from the server-side WebSocket connection to the blockchain node or indexer, the registry:

    • Uses a customizable transaction handler to extract the relevant addresses involved in the transaction.

    • Identifies clients subscribed to those addresses.

    • Dispatches the transaction payloads directly to those clients via their connection handlers.

This targeted event propagation ensures clients receive timely updates only for the addresses they monitor.

Core Methods (Illustrative Snippets)

subscribe(clientId, subscriptionId, connection, addresses) {
  addresses.forEach(address => {
    address = this.formatAddress(address)
    this.clients[id].add(address)
    this.addresses[address].set(id, connection)
  })
}

async onTransaction(msg) {
  const { addresses, tx } = await this.handleTransaction(msg)
  this.publishTransaction(addresses, tx)
}

private publishTransaction(addresses, tx) {
  addresses.forEach(address => {
    address = this.formatAddress(address)
    for (const [id, connection] of this.addresses[address].entries()) {
      const { subscriptionId } = Registry.fromId(id)
      connection.publish(subscriptionId, address, tx)
    }
  })
}

Integration

The Subscription Registry operates as a core component within the parent topic of real-time subscription management. It complements the **Connection Handling** subtopic, which manages the lifecycle and health of WebSocket client connections, by focusing specifically on the subscriptions clients hold.

Together, these subtopics form a layered architecture:

Unlike Connection Handling, which deals with connection state and messaging protocols, the Registry specializes in subscription data structures and event filtering logic. This separation of concerns enhances modularity and scalability.

The Registry also interfaces with blockchain node or indexer event streams by consuming raw block or transaction messages and transforming them into filtered notifications tailored to client subscriptions. Its use of customizable address formatters and transaction handlers allows adaptation across multiple blockchain implementations supported in the platform’s multi-blockchain architecture.

Diagram

flowchart TD
  subgraph Client Side
    C1[WebSocket Client 1]
    C2[WebSocket Client 2]
  end

  subgraph Subscription Registry
    SR1[clients: Map<ClientSubId, Set<Addresses>>]
    SR2[addresses: Map<Address, Map<ClientSubId, ConnectionHandler>>]
  end

  subgraph Blockchain Event Stream
    BlockEvent[New Block / Transaction Message]
    TxHandler[Transaction Handler extracts addresses]
  end

  C1 -->|subscribe(addrs)| SR1
  C1 -->|subscribe(addrs)| SR2
  C2 -->|subscribe(addrs)| SR1
  C2 -->|subscribe(addrs)| SR2

  BlockEvent --> TxHandler
  TxHandler -->|addresses + tx| SR2
  SR2 -->|publish to matching clients| C1
  SR2 -->|publish to matching clients| C2

The flowchart illustrates how clients register subscriptions for addresses, the registry maintains bidirectional maps, and how incoming blockchain transaction events are processed and dispatched only to interested clients. This targeted delivery mechanism is key to efficient real-time event subscription management in the system.