Solana · Arazzo Workflow

Solana Discover the Available Ledger Range and Backfill Blocks

Version 1.0.0

Find the node's earliest available block and minimum retained slot, then walk a page of blocks.

1 workflow 1 source API 1 provider
View Spec View on GitHub BlockchainCryptocurrencyWeb3DeFiTransactionsTokensArazzoWorkflows

Provider

solana

Workflows

ledger-backfill-range
Establish the retained ledger window and page confirmed slots from its floor.
Resolves what history a node actually holds, then walks the first page of blocks inside that window.
5 steps inputs: pageLimit, rangeSpan outputs: firstAvailableSlot, floorBlockSignatures, minimumLedgerSlot, pagedSlots, slotsInRange
1
firstAvailableBlock
getFirstAvailableBlock
Find the lowest slot for which the node can still serve a confirmed block. This is the true floor for any backfill against this endpoint.
2
minimumLedgerSlot
minimumLedgerSlot
Read the lowest slot the node still retains in its ledger. This can differ from the first available block, and the higher of the two is the safe starting point.
3
pageSlotsFromFloor
getBlocksWithLimit
List a bounded page of confirmed slots starting at the floor. Using a limit rather than an open-ended range is what keeps a backfill from requesting more than the node will return.
4
listSlotsInRange
getBlocks
List the confirmed slots between an explicit start and end slot. Skipped slots simply do not appear, which is how an indexer learns which slots produced no block.
5
fetchFloorBlock
getBlock
Fetch the block at the first paged slot with signatures only, the cheapest form that still proves the block is retrievable before a full backfill is launched against it.

Source API Descriptions

Arazzo Workflow Specification

Raw ↑
arazzo: 1.0.1
info:
  title: Solana Discover the Available Ledger Range and Backfill Blocks
  summary: Find the node's earliest available block and minimum retained slot, then walk a page of blocks.
  description: >-
    The bootstrap sequence every Solana indexer runs before backfilling. An RPC
    node only retains part of the ledger, so the workflow first establishes the
    floor from two directions — the lowest slot with an available block and the
    lowest slot the node still keeps in its ledger — then lists a bounded page
    of confirmed slots from that floor, lists the slots inside an explicit
    range, and fetches the first available block itself in signature-only form
    to keep the payload small. Asking for blocks below this floor is the most
    common cause of a failed backfill. Every step spells out its JSON-RPC
    request inline so the flow can be read and executed without opening the
    underlying OpenAPI description.
  version: 1.0.0
sourceDescriptions:
- name: solanaRpcApi
  url: ../openapi/solana-rpc-api-openapi.yml
  type: openapi
workflows:
- workflowId: ledger-backfill-range
  summary: Establish the retained ledger window and page confirmed slots from its floor.
  description: >-
    Resolves what history a node actually holds, then walks the first page of
    blocks inside that window.
  inputs:
    type: object
    properties:
      pageLimit:
        type: integer
        description: How many confirmed slots to return when paging from the floor.
        default: 10
      rangeSpan:
        type: integer
        description: >-
          How many slots past the floor to bound the explicit start/end slot
          listing with.
        default: 100
  steps:
  - stepId: firstAvailableBlock
    description: >-
      Find the lowest slot for which the node can still serve a confirmed block.
      This is the true floor for any backfill against this endpoint.
    operationId: getFirstAvailableBlock
    requestBody:
      contentType: application/json
      payload:
        jsonrpc: "2.0"
        id: 1
        method: getFirstAvailableBlock
        params: []
    successCriteria:
    - condition: $statusCode == 200
    outputs:
      firstSlot: $response.body#/result
  - stepId: minimumLedgerSlot
    description: >-
      Read the lowest slot the node still retains in its ledger. This can differ
      from the first available block, and the higher of the two is the safe
      starting point.
    operationId: minimumLedgerSlot
    requestBody:
      contentType: application/json
      payload:
        jsonrpc: "2.0"
        id: 1
        method: minimumLedgerSlot
        params: []
    successCriteria:
    - condition: $statusCode == 200
    outputs:
      minimumSlot: $response.body#/result
  - stepId: pageSlotsFromFloor
    description: >-
      List a bounded page of confirmed slots starting at the floor. Using a
      limit rather than an open-ended range is what keeps a backfill from
      requesting more than the node will return.
    operationId: getBlocksWithLimit
    requestBody:
      contentType: application/json
      payload:
        jsonrpc: "2.0"
        id: 1
        method: getBlocksWithLimit
        params:
        - $steps.firstAvailableBlock.outputs.firstSlot
        - $inputs.pageLimit
    successCriteria:
    - condition: $statusCode == 200
    - context: $response.body
      condition: $.result
      type: jsonpath
    outputs:
      slots: $response.body#/result
      firstPagedSlot: $response.body#/result/0
  - stepId: listSlotsInRange
    description: >-
      List the confirmed slots between an explicit start and end slot. Skipped
      slots simply do not appear, which is how an indexer learns which slots
      produced no block.
    operationId: getBlocks
    requestBody:
      contentType: application/json
      payload:
        jsonrpc: "2.0"
        id: 1
        method: getBlocks
        params:
        - $steps.firstAvailableBlock.outputs.firstSlot
        - $inputs.rangeSpan
    successCriteria:
    - condition: $statusCode == 200
    - context: $response.body
      condition: $.result
      type: jsonpath
    outputs:
      slotsInRange: $response.body#/result
  - stepId: fetchFloorBlock
    description: >-
      Fetch the block at the first paged slot with signatures only, the cheapest
      form that still proves the block is retrievable before a full backfill is
      launched against it.
    operationId: getBlock
    requestBody:
      contentType: application/json
      payload:
        jsonrpc: "2.0"
        id: 1
        method: getBlock
        params:
        - $steps.pageSlotsFromFloor.outputs.firstPagedSlot
        - encoding: json
          transactionDetails: signatures
          maxSupportedTransactionVersion: 0
    successCriteria:
    - condition: $statusCode == 200
    - context: $response.body
      condition: $.result.blockhash
      type: jsonpath
    outputs:
      blockhash: $response.body#/result/blockhash
      parentSlot: $response.body#/result/parentSlot
      blockHeight: $response.body#/result/blockHeight
      signatures: $response.body#/result/signatures
      blockTime: $response.body#/result/blockTime
  outputs:
    firstAvailableSlot: $steps.firstAvailableBlock.outputs.firstSlot
    minimumLedgerSlot: $steps.minimumLedgerSlot.outputs.minimumSlot
    pagedSlots: $steps.pageSlotsFromFloor.outputs.slots
    slotsInRange: $steps.listSlotsInRange.outputs.slotsInRange
    floorBlockSignatures: $steps.fetchFloorBlock.outputs.signatures