Scanning blockchain events

Test predicates by scanning historical blockchain data before deploying them in production.

This guide shows you how to use Chainhook's scanning mode to test predicates against historical blockchain data. Scanning helps validate your predicate logic and understand what events will be captured before going live.

Basic scanning

Test your predicate against historical data by scanning the blockchain:

Terminal
$
chainhook predicates scan my-predicate.json --mainnet

The scan command downloads blockchain data from Hiro Archive (cached after first run) and evaluates your predicate against each block in the specified range.

Scan with specific networks

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

Block range scanning

Limit scanning to specific blocks for faster testing and targeted analysis:

Terminal
$
chainhook predicates scan my-predicate.json \
--start-block 150000 \
--end-block 150100 \
--mainnet

Configure ranges in predicates

block-range-predicate.json
{
"chain": "stacks",
"networks": {
"mainnet": {
"start_block": 150000,
"end_block": 151000,
"if_this": {
"scope": "contract_call",
"contract_identifier": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-dao"
}
}
}
}

This predicate scans only blocks 150,000 to 151,000, significantly reducing scan time.

Output configuration

Control where scan results are written using the then_that section.

File output

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

Console output

console-output-predicate.json
{
"then_that": {
"file_append": {
"path": "-" // Writes to stdout
}
}
}

Performance optimization

Speed up your scans by being specific about what you're looking for.

Use specific scopes

optimized-scope.json
{
"if_this": {
"scope": "contract_call",
"contract_identifier": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-dao",
"method": "collateralize-and-mint"
}
}

Targeting specific contracts and methods scans much faster than broad scopes.

Limit occurrences

limited-occurrences.json
{
"networks": {
"mainnet": {
"expire_after_occurrence": 100,
"if_this": {
"scope": "nft_event",
"actions": ["mint"]
}
}
}
}

Stop scanning after finding 100 matching events.

Common scanning patterns

Learn from these practical examples of scanning for specific blockchain events.

Find first contract deployment

find-deployment.json
{
"chain": "stacks",
"networks": {
"mainnet": {
"expire_after_occurrence": 1,
"if_this": {
"scope": "contract_deployment",
"deployer": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR"
}
}
}
}
Terminal
$
chainhook predicates scan find-deployment.json --mainnet

Collect NFT activity

nft-activity.json
{
"if_this": {
"scope": "nft_event",
"asset_identifier": "SP32AEEF6WW5Y0NMJ1S8SBSZDAY8R5J32NBZFPKKZ.free-punks-v0::free-punks",
"actions": ["mint", "transfer", "burn"]
},
"then_that": {
"file_append": {
"path": "./nft-activity.json"
}
}
}

Monitor address transactions

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

Track all STX transfers involving a specific address as sender or recipient.

Debug scanning

Enable verbose output to understand why events match or don't match:

Terminal
$
chainhook predicates scan my-predicate.json --mainnet --verbose

Further reading