Skip to main content

Closer Look at Snapshots

Let's take a closer look at how base snapshots and aggregates are generated by the Snapshotter Node for Pooler.

Base Snapshots

info

Before you dive into this section, please make sure you take a look into the Snapshot Generation Section.

Snapshotter node has several interfaces defined to handle the heavy lifting so that you can focus on just writing computes modules. For example, TradeVolumeProcessor, located in the Snapshotter-computes snapshotter-computer/trade_volume.py, is one of the base Processor computes for Pooler. This class uses the GenericProcessorSnapshot structure found in snapshotter/utils/callback_helpers.py.

Any processor for base snapshots needs to implement the compute function.

trade_volume.py
loading...

The compute function is the main part where we create and process snapshots. It uses these inputs:

  • epoch: Epoch details for which the snapshot is being generated.
  • redis: Redis connection object.
  • rpc_helper: RPC Helper object.

epoch is PowerloomSnapshotProcessMessage object which contains the following information:

snapshotter/utils/models/message_models.py
loading...

The TradeVolumeProcessor collects and stores information about trades that happen within a specific range of blocks in the blockchain, known as the epoch. This range is defined by the lowest block number (min_chain_height) and the highest block number (max_chain_height) in that epoch.

The format of the output data can vary based on what you need it for. However, the return type must always be a pydantic model, it helps organize and define the data structure clearly.

info

Pydantic Model is a Python Library that helps data validation and parsing, by using Python type annotations.

Aggregated Snapshots

In the preceding section, we delved into the TradeVolumeProcessor logic, responsible for capturing snapshots of Uniswap v2 trade information between block heights min_chain_height and max_chain_height.

The epoch size, as detailed in the earlier section on epoch generation, remains constant for this specific implementation of the Uniswap v2 use case on the Powerloom Protocol. This consistency extends to the time duration encompassed within each epoch.

To access the finalized state and data CID corresponding to each epoch, refer to the smart contract on the anchor chain holding the protocol state. The relevant helpers for this can be located in get_project_epoch_snapshot() within pooler/snapshotter/utils/data_utils.py.

snapshotter/utils/data_utils.py
loading...

To figure out the end point (or tail) for a 24-hour period of snapshots and trade data, starting from a given epoch ID (the beginning or head of this time span), we use a specific formula.

time_in_seconds = 86400
tail_epoch_id = current_epoch_id - int(time_in_seconds / (source_chain_epoch_size * source_chain_block_time))
snapshotter/utils/data_utils.py
loading...

The worker class for such aggregation is defined in config/aggregator.json in the following manner:

aggregator.example.json
loading...

AggregateTradeVolumeProcessor, located in the Snapshotter-computes snapshotter-computer/aggregate/single_uniswap_trade_volume_24h.py is one of the aggregate computes for Pooler. This class uses the GenericProcessorAggregate structure found in snapshotter/utils/callback_helpers.py.

Any processor for aggregate snapshots needs to implement the compute function.

aggregate/single_uniswap_trade_volume_24h.py
loading...

The compute function is the main part where we create and process snapshots. It uses these inputs:

  • msg_obj: Underlying message object that contains the details of the aggregate snapshot composition.
  • redis: Redis connection object.
  • rpc_helper: RPC Helper object.
  • anchor_rpc_helper: RPC Helper object for the anchor chain.
  • ipfs_reader: IPFS Client object.
  • protocol_state_contract: Protocol state contract Web3 object.
  • project_id: Project ID for which the aggregate snapshot is being generated.

msg_object is either of type PowerloomSnapshotSubmittedMessage or PowerloomCalculateAggregateMessage for even more complex aggregates.

PowerloomSnapshotSubmittedMessage contains the following information:

snapshotter/utils/models/message_models.py
loading...

PowerloomCalculateAggregateMessage contains the following information:

snapshotter/utils/models/message_models.py
loading...

For a comprehensive understanding of Pooler computes, refer to the snapshotter-computes repository.

Extending Pooler for Additional Datapoints

It's straightforward to implement custom data points on top of the existing pooler. Our Extending UniswapV2 dashboard section provides detailed coverage on this topic.