Skip to main content

Events notifier

Overview

A MultiversX observer node can push block events to a notifier service, which will process and forward the events to subscribers (via RabbitMQ). This way, one can subscribe to a RabbitMQ queue and receive block events, whenever a block is committed to the chain, instead of polling an API frequently.

The GitHub repository for the notifier service can be found here.

Architectural Overview

The observer node in the network will be connected to notifier service. The observer will send block events to notifier. The notifier service will receive and filter events, it will apply deduplication if enabled, and it will push the events to RabbitMQ instance, or push them to websocket subscribers.

info

Set up at least one observer for each shard in order to handle all the events in the chain.

img

In the figure above:

  • The observer nodes will push block events to Notifier instance, via HTTP POST requests. There are several endpoints for this:
    • /events/push (POST) -> it will handle all events for each round
    • /events/revert (POST) -> if there is a reverted block, the event will be pushed on this route
    • /events/finalized (POST) -> when the block has been finalized, the events will be pushed on this route
  • Notifier checks locker service (via Redis) and applies deduplication
  • Notifier will push events to RabbitMQ if enabled, or via Websockets. If Websockets will be enabled an additional endpoint will be available:
    • /hub/ws (GET) - this route can be used to manage the websocket connection subscription

Set up observer and notifier

Observer Client

On the observer side, there is a http client that will push block events to notifier service.

In the observer node's configuration directory, external.toml config file can be configured to enable notifier connector. The config file can be found here.

The supported config variables are as follows:

  • Enabled: signals whether a driver should be attached when launching the node.
  • UseAuthorization: signals whether to use authorization. For testing purposes it can be set to false.
  • ProxyUrl: host and port on which the eventNotifier will push the parsed event data.
  • Username: the username used for authorization, if enabled.
  • Password: the password used for authorization, if enabled.

The corresponding config section for enabling the driver:

[EventNotifierConnector]
# Enabled will turn on or off the event notifier connector
Enabled = true

# UseAuthorization signals the proxy to use authorization
# Never run a production setup without authorization
UseAuthorization = false

# ProxyUrl is used to communicate with the subscriptions hub
# The indexer instance will broadcast data using ProxyUrl
ProxyUrl = "http://localhost:5000"

# Username and Password need to be specified if UseAuthorization is set to true
Username = ""

# Password is used to authorize an observer to push event data
Password = ""
tip

Due to the possible high data volume, it's not recommended to use validators as nodes to push events to Notifier Service. Similar to Elasticsearch indexing, our implementation uses a concept of a queue and makes sure that everything is being processed. Consensus and synchronization mechanisms can have delays due to outport driver.

Notifier Service

In the notifier configuration directory (cmd/notifier/config), there is the config.toml file that can be used to configure the service.

The supported config variables are:

  • Port: the port on which the http server listens on. Should be the same as the port in the ProxyUrl described above.
  • Username: the username used to authorize an observer. Can be left empty for UseAuthorization = false.
  • Password: the password used to authorize an observer. Can be left empty for UseAuthorization = false.
  • CheckDuplicates: if true, it will check (based on a locker service using redis) if the event have been already pushed to clients

The ConnectorApi section has to be aligned with the one from observer node:

[ConnectorApi]
# The port on which the Hub listens for subscriptions
Port = "5000"

# Username is the username needed to authorize an observer to push data
Username = ""

# Password is the password needed to authorize an observer to push event data
Password = ""

# CheckDuplicates signals if the events received from observers have been already pushed to clients
# Requires a redis instance/cluster and should be used when multiple observers push from the same shard
CheckDuplicates = true

If CheckDuplicates will be set to true, notifier service will try to connect to a redis instance. In this context, redis will be used as a locker service mechanism for deduplication. This is useful in scenarios when multiple observer nodes from same shard are used to send events to the same notifier instance.

The Redis section includes the following parameters as described below:

[Redis]
# The url used to connect to a pubsub server
# Note: not required for running in the notifier mode
Url = "redis://localhost:6379/0"

# The pubsub channel used for publishing/subscribing
# Note: not required for running in the notifier mode
Channel = "pub-sub"

# The master name for failover client
MasterName = "mymaster"

# The sentinel url for failover client
SentinelUrl = "localhost:26379"

# The redis connection type. Options: | instance | sentinel |
# instance - it will try to connect to a single redis instance
# sentinel - it will try to connect to redis setup with master, slave and sentinel instances
ConnectionType = "sentinel"

# Time to live (in minutes) for redis lock entry
TTL = 30

For more details on notifier service setup, please follow the Install and Launching sections from README in the repository.

Subscribers

Currently there are 2 supported subscribing solutions:

  • RabbitMQ
  • Websocket

The subscribing solution is selected based on a CLI parameter, please check README from github repository for more info on the CLI parameters.

In the notifier configuration directory (cmd/notifier/config), in config.toml there is a separate section RabbitMQ, which can be used to set up rabbitMQ connection url and exchanges. The exchanges will be created automatically (if they are not already created) on notifier service start.

[RabbitMQ]
# The url used to connect to a rabbitMQ server
# Note: not required for running in the notifier mode
Url = "amqp://guest:guest@localhost:5672"

# The exchange which holds all logs and events
[RabbitMQ.EventsExchange]
Name = "all_events"
Type = "fanout"

# The exchange which holds revert events
[RabbitMQ.RevertEventsExchange]
Name = "revert_events"
Type = "fanout"

...
tip

It is recommended to use the setup with RabbitMQ, if it is very important to avoid losing any event.

Events

There are multiple event types:

  • Push Block event: when the block is committed, it contains logs and events
  • Revert Block event: when the block is reverted
  • Finalized Block event: when the block is finalized

In RabbitMQ there is a separate exchange for each event type. In Websockets setup, there is a event type field in each message.

The WS event is defined as follows:

FieldDescription
TypeThe type field defines the event type, it can be one of the following: all_events, revert_events, finalized_events. all_events refers to all logs and events.
DataSerialized data corresponding to the event type.

Push Block Event

Each time a block is committed on the chain, an event will be triggered with basic information on the block together with logs and events. The structure data fields are as following:

Push Block Event

FieldDescription
hashThe hash field represents the hash of the committed block.
eventsThe events field holds a list of events.

Event structure

FieldDescription
identifierThis field represents the identifier of the event.
addressThe address field holds the address in a bech32 encoding. It can be the address of the smart contract that generated the event or the address of the receiver address of the transaction.
topicsThe topics field holds a list with extra information. They don't have a specific order because the smart contract is free to log anything that could be helpful.
dataThe data field can contain information added by the smart contract that generated the event.
orderThe order field represents the index of the event indicating the execution order.

Revert Block Event

When there is a revert for a particular block on the chain, a revert event will be triggered, containing basic info on the block.

FieldDescription
hashThe hash field represents the hash of the committed block.
nonceThe nonce field represents the sequence number of the block.
roundThe round field represents the round when the block was proposed and executed.
epochThe epoch field represents the epoch when the block was proposed and executed.

Finalized Block Event

When a block is completely finalized, including intra-shard transactions, a finalized event will be triggered containing the hash of the block.

FieldDescription
hashThe hash field represents the hash of the committed block.