Skip to main content

Fields selection

setFields(options) {#set-fields}

Set the fields to be retrieved for data items of each supported type. The options object has the following structure:
{
  event?:     // field selector for logs
  call?:      // field selector for transactions
  extrinsic?: // field selector for state diffs
  block?:     // field selector for block headers
}
Every field selector is a collection of boolean fields mapping one-to-one to the fields of data items within the batch context iterables. Setting a field of a field selector of a given type to true, like this
let processor = new SubstrateBatchProcessor()
  .setFields({
    call: {
      origin: true
    }
  })
will cause the processor to populate the corresponding field (in this case origin) of all data items of that type (in this case Call). The field will be available in all data items of the type, including nested items. Suppose we used the processor defined above to subscribe to some calls as well as some events, and for each event we requested a parent call:
processor
  .addEvent({
    // some event data requests
    call: true
  })
  .addCall({
    // some call data requests
  })
As a result, the origin field would be available both within the call items retrieved due to .addCall() and within the call items that provide parent call information for the events:
processor.run(db, async ctx => {
  for (let block of ctx.blocks) {
    for (let call of block.calls) {
      let callOrigin = call.origin // OK
    }
    for (let event of block.events) {
      let parentCallOrigin = event.call?.origin // also OK!
    }
  }
})
Some data fields are enabled by default but can be disabled by setting a field of a field selector to false. For example, this code will not compile:
let processor = new SubstrateBatchProcessor()
  .setFields({
    call: {
      name: false
    }
  })
  .addCall({
    // some call data requests
  })

processor.run(db, async ctx => {
  for (let block of ctx.blocks) {
    for (let call of block.calls) {
      let callName = call.name // ERROR: no such field
    }
  }
})
Disabling unused fields will improve sync performance, as the disabled fields will not be fetched from SQD Network.

Data item types and field selectors

Most IDEs support smart suggestions to show the possible field selectors. For VS Code, press Ctrl+Space:
Here we describe the data item types as functions of the field selectors. In SubstrateBatchProcessor each field of a field selector maps to the eponymous field of its corresponding data item type. Item data fields are divided into three categories:
  • Fields that are added independently of the setFields() call. These are either fixed or depend on the related data retrieval flags (e.g. call for events).
  • Fields that can be disabled by setFields(). E.g. the args field will be fetched for calls by default, but can be disabled by setting args: false within the call field selector.
  • Fields that can be requested by setFields(). E.g. the tip field will only be available in extrinsics if the extrinsic field selector sets tip: true.
In addition to data fields, data items have methods that simplify access to related data, e.g. Call.getExtrinsic().

Events

Event data items may have the following fields:
Event {
  // can be requested with field selectors
  phase: 'ApplyExtrinsic' | 'Initialization' | 'Finalization'

  // can be disabled with field selectors
  name: string
  args: any

  // independent of field selectors
  id: string
  index: number
  block: BlockHeader
  callAddress?: number[]
  call?: Call
  extrinsicIndex?: number
  extrinsic?: Extrinsic

  // methods
  getCall(): Call
  getExtrinsic(): Extrinsic
}
Definition of the types mentioned are available in their respective sections:

Calls

Call data items may have the following fields:
Call {
  // can be requested with field selectors
  error?: any
  origin?: any
  success: boolean
  
  // can be disabled with field selectors
  name: string
  args: any

  // independent of field selectors
  id: string
  address: number[]
  block: BlockHeader
  events: Event[]
  parentCall?: Call
  subcalls: Call[]
  extrinsicIndex: number
  extrinsic?: Extrinsic

  // methods
  getParentCall(): Call
  getExtrinsic(): Extrinsic
}
Definition of the types mentioned are available in their respective sections:

Extrinsics

Extrinsic data items may have the following fields:
Extrinsic {
  // can be requested with field selectors
  success: boolean
  error?: unknown
  fee?: bigint
  hash: string
  signature?: {
    // no per-field selection here:
    // "signature: true" gets all fields
    address: unknown
    signature: unknown
    signedExtensions: unknown
  }
  tip?: bigint
  version: number
  
  // independent of field selectors
  id: string
  index: number
  block: BlockHeader
  events: Event[]
  call?: Call
  subcalls: Call[]

  // methods
  getCall(): Call
}
Definition of mentioned types are available in their respective sections:

Block headers

BlockHeader data items may have the following fields:
BlockHeader{
  // can be requested with field selectors
  digest: { // request with "digest: true"
    logs: string[]
  }
  extrinsicsRoot: string
  stateRoot: string
  timestamp?: number
  validator?: string

  // independent of field selectors
  id: string
  hash: string
  height: number
  implName: string
  implVersion: number
  parentHash: string
  specName: string
  specVersion: number
  _runtime: Runtime
  _runtimeOfPrevBlock: Runtime
  
  // methods
  getParent(): {
    _runtime: Runtime
    hash: string
    height: number
  }
}
Runtime is an internal type that tools like squid-substrate-typegen use for dealing with Substrate runtime versions. The curious may take a look at the definition here.

A complete example

Fetch Balances.Transfer events and Balances.transfer_keep_alive calls along with their parent extrinsics. Enrich the extrinsics with hashes, fees and success flags:
const processor = new SubstrateBatchProcessor()
  .addEvent({
    name: ['Balances.Transfer'],
    extrinsic: true
  })
  .addCall({
    name: ['Balances.transfer_keep_alive'],
    extrinsic: true
  })
  .setFields({
    extrinsic: {
      hash: true,
      fee: true,
      success: true
    }
  })