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:
substreams buildNow, 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 +1In 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 +1Inspect 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_paramsfunction parses the parameters passed to the module. In this example, the parameter passed is defined in thesubstreams.yamlfile 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_filterfunction to only keep instruction whereprogram_id=Stake11111111111111111111111111111111111111.Create an
Instructionobject, which will be the output of the Substreams. This object is declared as a Protobuf in theprotofolder of the project.
Last updated
Was this helpful?

