I am trying to determine the block level of the stake snapshot applicable to a given cycle.

The documentation states:

Stake snapshots are taken (and stored) every BLOCKS_PER_STAKE_SNAPSHOT levels. More precisely, a snapshot is taken at a level if and only if its cycle position modulo BLOCKS_PER_STAKE_SNAPSHOT is BLOCKS_PER_STAKE_SNAPSHOT - 1.

I tried the following (Python):

snapshot_index = rpc_query(f'{rpc_address}/chains/main/blocks/{previous_cycle_last_block}/context/selected_snapshot?cycle={previous_cycle}')
snapshot_block = previous_cycle_first_block + (snapshot_index * blocks_per_stake_snapshot) - 1
snapshot_metadata = rpc_query(f'{rpc_address}/chains/main/blocks/{snapshot_block}/metadata')

The resulting block level modulo 1024 (blocks_per_stake_snapshot) actually gives 1023 (blocks_per_stake_snapshot - 1), but when I look at the details of that block (specifically the delegates' balances), they do not correspond to those selected by indexers.

As I'm not sure of how to interpret the snapshot index, I also tried with the following but it didn't give me the proper result either:

snapshot_block = previous_cycle_first_block + ((snapshot_index + 1) * blocks_per_stake_snapshot) - 1

What did I miss?

EDIT: After having read this excellent article (thanks DMir from Baking Bad!) I tried another approach by digging into the raw data instead of looking at the snapshot's balances, but it gives strictly the same results:


EDIT 2: Further to Julien's answer below, I tested this:

# Summary of the result of the code below:
# Tested cycle: 730
# Last block of cycle: 5529600 
# First block of cycle: 5513217
# Snapshot: 5527552 (index 13)

snapshot_index = rpc_query(f'{rpc_address}/chains/main/blocks/{tested_cycle_last_block}/context/selected_snapshot?cycle={tested_cycle}')
snapshot_block = tested_cycle_first_block + ((snapshot_index + 1) * blocks_per_stake_snapshot) - 1
  • With rpc_query(f'{rpc_address}/chains/main/blocks/{tested_cycle_last_block}/context/raw/json/staking_balance/snapshot/{snapshot_index}?depth=2')

    Snapshot staking balance: [
            "own_frozen": "20963143811",
            "staked_frozen": "0",
            "delegated": "188836328409"
  • With rpc_query(f'{rpc_address}/chains/main/blocks/{tested_cycle_last_block}/context/raw/json/staking_balance/snapshot/{snapshot_index}?depth=2')

    Last block's snapshot staking balance: []

That's strange as these two methods are supposed to give the same result. Also, if I sum the baker's own stake and its delegated balance I end up with:

>>> 20963143811+188836328409

This does not correspond to what TZKT shows: TZKT screenshot

  • Note that this is all going away in Paris. Quoting release notes: "The protocol no longer relies on stake snapshots to compute rights." May 15 at 17:07
  • Oh, I missed that, thanks! Maybe I should just be a little patient. Does this mean that the balances included in the last block will be those to rely on?
    – LaBoulange
    May 15 at 19:30

1 Answer 1


Correct snapshot block is

snapshot_block = previous_cycle_first_block + ((snapshot_index+1) * blocks_per_stake_snapshot) - 1

you can check this by comparing

and /chains/main/blocks/{snapshot_block}/context/raw/json/staking_balance/current?depth=2

They return the same values.

The reason is that the first snapshot (index 0) is taken BLOCKS_PER_STAKE_SNAPSHOT after the cycle starts.

  • Thanks a lot for this. This is not what I can observe though, I updated my question with the results of that test ("EDIT 2"). Maybe the problem resides in something I'm not doing right.
    – LaBoulange
    May 17 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.