Filter Instructions
The map_filter_instructions
module of the Solana Substreams Explorer extracts instruction of a given Program ID. For example, consider that you want to extract all the Stake11111111111111111111111111111111111111
instructions.
Run the Substreams
Run From Source Code
In the substreams-explorer
project, move to the solana-explorer
folder, which contains the source of the Solana Substreams. Then, build the Rust code:
make build
Now, you can run the Substreams by using the substreams gui
command. To avoid iterating over the whole blockchain, the following command extracts instructions from the Stake Program only at block 243830383
:
substreams gui ./substreams.yaml \
map_filter_instructions -e mainnet.sol.streamingfast.io:443 \
--start-block 243830383 --stop-block +1
In the Output
screen of the GUI, you can see two Stake11111111111111111111111111111111111111
instructions were retrieved at block 243830383
:

The map_filter_instructions
allows you to filter any Program ID, and this is configurable as a parameter in the Substreams Manifest (substreams.yaml
):
params:
map_filter_instructions: "program_id=Stake11111111111111111111111111111111111111"
You can replace Stake11111111111111111111111111111111111111
by any instruction of your choice.
Run the Package From the Substreams Registry
The Solana Explorer package is also available on the Substreams Registry. You can run it by using the following command, achieving the same result:
substreams gui https://spkg.io/streamingfast/solana-explorer-v0.2.0.spkg \
map_filter_instructions -e mainnet.sol.streamingfast.io:443 \
--start-block 243830383 --stop-block +1
Inspect the Code
The map_filter_instructions.rs
file contains the source of the module. The output of the Substreams module is the Instructions
object, which is defined in the /proto/transactions.proto
file of the project. This is a custom object defined by the user, and you can modify at your will.
message Instructions {
repeated Instruction instructions = 1;
}
message Instruction {
string program_id = 1;
repeated string accounts = 2;
string data = 3;
}
Let's inspect the module function:
#[substreams::handlers::map]
fn map_filter_instructions(params: String, blk: Block) -> Result<Instructions, substreams::errors::Error> {
let filters = parse_filters_from_params(params)?; // 1.
let instructions : Vec<Instruction> = blk.transactions().flat_map(|tx| { // 2.
let msg = tx.transaction.as_ref().unwrap().message.as_ref().unwrap(); // 3.
let acct_keys = tx.resolved_accounts(); // 4.
msg.instructions.iter() // 5.
.filter(|inst| apply_filter(inst, &filters, &acct_keys)) // 6.
.map(|inst| { // 7.
Instruction {
program_id: bs58::encode(acct_keys[inst.program_id_index as usize].to_vec()).into_string(),
accounts: inst.accounts.iter().map(|acct| bs58::encode(acct_keys[*acct as usize].to_vec()).into_string()).collect(),
data: bs58::encode(&inst.data).into_string(),
}
}).collect::<Vec<_>>()
}).collect();
Ok(Instructions { instructions })
}
The
parse_filters_from_params
function parses the parameters passed to the module. In this example, the parameter passed is defined in thesubstreams.yaml
file asprogram_id=Stake11111111111111111111111111111111111111
.Iterate over the transactions of the blocks.
Extract the Message object, which contains relevant information, such as the instructions of the transaction.
Get accounts of the transaction (the
resolved_accounts()
method contains also accounts stored in the Address Lookup Tables).Iterate over the instructions.
Use the
apply_filter
function to only keep instruction whereprogram_id=Stake11111111111111111111111111111111111111
.Create an
Instruction
object, which will be the output of the Substreams. This object is declared as a Protobuf in theproto
folder of the project.
Last updated
Was this helpful?