Event scanning

Test predicates by scanning historical blockchain data.


Chainhook's scanning mode lets you test predicates against historical blockchain data before deploying them in production. This is essential for validating predicate logic and understanding what events will be captured.

Basic scanning

Scan the blockchain using a predicate file:

Terminal
$
chainhook predicates scan my-predicate.json --mainnet
[33mDownloading chain archive...[0m
[32mScanning blocks 100000 to 150000[0m
[32mFound 234 matching events[0m
[32mResults written to output.json[0m

The scan command:

  1. 1Downloads blockchain data from Hiro Archive (first run only)
  2. 2Evaluates your predicate against each block
  3. 3Outputs matching events to the specified destination

Scan specific block ranges

Limit scanning to specific blocks for faster testing:

Terminal
$
chainhook predicates scan my-predicate.json \
--start-block 150000 \
--end-block 150100 \
--mainnet
[32mScanning 100 blocks[0m
[32mCompleted in 2.3s[0m

Network selection

Scan different networks using flags:

Terminal
$
chainhook predicates scan predicate.json --mainnet
$
chainhook predicates scan predicate.json --testnet
$
chainhook predicates scan predicate.json --devnet

Output formats

File output

Write results to a file:

predicate-file-output.json
{
"then_that": {
"file_append": {
"path": "./scan-results.json"
}
}
}

Console output

Use - for stdout:

predicate-console-output.json
{
"then_that": {
"file_append": {
"path": "-"
}
}
}

Scan performance

Optimize scanning speed with these techniques:

1. Use specific scopes

// Slower - scans all transactions
{
"if_this": {
"scope": "txid"
}
}
// Faster - only contract calls
{
"if_this": {
"scope": "contract_call",
"contract_identifier": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-dao"
}
}

2. Set block boundaries

{
"networks": {
"mainnet": {
"start_block": 150000,
"end_block": 151000,
"if_this": { ... }
}
}
}

3. Limit occurrences

{
"networks": {
"mainnet": {
"expire_after_occurrence": 100,
"if_this": { ... }
}
}
}

Debugging scans

Enable verbose output to debug predicate matching:

Terminal
$
chainhook predicates scan my-predicate.json --mainnet --verbose
[90mEvaluating block 150000 (0x3a4b5c...)[0m
[90m Transaction 0x1a2b3c... - No match (wrong contract)[0m
[32m Transaction 0x4d5e6f... - MATCH[0m
[90mEvaluating block 150001 (0x7d8e9f...)[0m

Common scan scenarios

Find first occurrence

Locate when a contract was first called:

Terminal
$
chainhook predicates scan find-first.json \
--start-block 100000 \
--mainnet

With predicate:

{
"expire_after_occurrence": 1,
"if_this": {
"scope": "contract_deployment",
"contract_identifier": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-dao"
}
}

Collect all NFT mints

Gather all mint events for analysis:

nft-mints.json
{
"if_this": {
"scope": "nft_event",
"asset_identifier": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.bitcoin-monkeys::bitcoin-monkeys",
"actions": ["mint"]
},
"then_that": {
"file_append": {
"path": "./all-mints.json"
}
}
}

Monitor specific address

Track all STX transfers for an address:

address-monitor.json
{
"if_this": {
"scope": "stx_event",
"actions": ["transfer"],
"predicate": {
"or": [
{ "equals": { "sender": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR" } },
{ "equals": { "recipient": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR" } }
]
}
}
}

Troubleshooting

IssueSolution
Archive download failedCheck internet connection and disk space
No events foundVerify block range contains expected activity
Scan terminates earlyCheck expire_after_occurrence setting
Memory issuesReduce block range or output to file

Next steps