Query_blocks <-- ICP ledger Candid 🙌

query_blocks for the ICP ledger canister works. It even gives you an index for archive canisters if the record is too old.

Looks like this was added to the repo March 3rd. No idea when it went live on mainnet, but it is there now.

DFINITY folks, you’ve got to shout this kind of stuff from the rooftops. This feature drastically reduces complexity and basically enables all kinds of new functionality. THANK YOU!!!

If I missed the announcement for this please point me to it, I don’t want to miss stuff like this again.

To query the main ledger(last couple thousand blocks or so, if not in range you get the index:

dfx canister --network ic call ryjl3-tyaaa-aaaaa-aaaba-cai query_blocks '(record {start = 1: nat64; length = 2:nat64})'

To query the index:

dfx canister --network ic call qjdve-lqaaa-aaaaa-aaaeq-cai get_blocks '(record {start = 1: nat64; length = 2:nat64})'
1 Like

I’m using the get_blocks() method and everything functions without any errors, but I’m only getting empty arrays back, no blocks are being returned. what am I missing? Below is the relevant code.

how I instantiate the ledger index canister:

private let ledgerIndex : Ledger.InterfaceIndex = actor("qjdve-lqaaa-aaaaa-aaaeq-cai");

Where I call the function:

let tipOfChainIndex = await tipOfChainDetails();
let startIndex : Nat64 = tipOfChainIndex.0 - 1000;
let queryLength : Nat64 = 999;
let queryResult = await ledgerIndex.get_blocks({
    start = startIndex;
    length = queryLength;

On the main node it is query_blocks. On the archive nodes it is get_blocks. Make sure you have your did file right, AccountIdentfiers are blobs in these structures.

1 Like

Are you able to answer any of the following:

how far back on the blockchain we can query?

What’s the maximum range?

How does one go about retrieving the transaction history of a particle principal?

Up to 2000 blocks on the main node, all the way back on the archive.

The maximum size of a response is 2MB, sonic it bigger than that you’ll have to chunk.

Scan the chain and index it so you don’t have to donut a second time. I’d love for dfinity to offer some meta data Canisters for stuff like this. I think the Rosetta server lets you do those queries, but your canister can’t get to them.

1 Like

When I try to use the web Candid UI to interact with the ledger archive canister, I get an error that I can’t resolve.

If I enter for example 1 at start and 2 at length (like you did in the example above), I get the response Not an option type.

What am I missing here?

I’m not sure where this candid came from, but in the latest version the to and from is a blob an and not a [Nat8]

Try this one: https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.ic0.app/?id=ryjl3-tyaaa-aaaaa-aaaba-cai

Thank you. That’s the ledger canister, it doesn’t store all the blocks but only the latest ones. The one that I was referring to is the archive which stores all ledger transactions. Did you try the candid UI and get the same error? I’m not sure what I’m doing wrong when calling the candid directly with the candid UI.

In any case, I get the same error when calling the query_blocks method on the ledger canister. It tells me the error Not an option type.

Does dfx work? ………………

Yes, dfx works. That’s why I’m a bit lost about what may be wrong here.

I’m trying query the transaction history via an httpAgent in typescript. See a small example below

import {Actor, HttpAgent} from '@dfinity/agent';

const {idlFactory: ledgerIDL} = require('../lib/canisters/ledger.did.js');
const {idlFactory: archiveIDL} = require('../lib/canisters/ledger-archive.did.js');

const agent = new HttpAgent({host: 'https://ic0.app'});
const ledger = Actor.createActor(ledgerIDL, {
  canisterId: 'ryjl3-tyaaa-aaaaa-aaaba-cai',
const ledgerArchive = Actor.createActor(archiveIDL, {
  canisterId: 'qjdve-lqaaa-aaaaa-aaaeq-cai',

const queryBlocks = async (start: bigint, length: bigint) => {
  const GetBlocksArgs = {
    start: start,
    length: length,
  const res: any = await ledger.query_blocks(GetBlocksArgs);

const queryArchiveBlocks = async (start: bigint, length: bigint) => {
  const GetBlocksArgs = {
    start: start,
    length: length,
  const res: any = await ledgerArchive.get_blocks(GetBlocksArgs);

queryBlocks(20000n, 2n); // returns an object with no blocks
queryArchiveBlocks(20000n, 2n); // returns the error "Not an option type"

The candid of the ledger and archive canisters are taken from here

Do you see any issue with the code?

Is it possible that the candid of the ledger canister on canlista and icscan are not correct? Does anyone know the latest version?

I got mine from the latest version of the ic repo. GitHub.com/dfinity/ic/rs/Rosetta-api/somewhereinthere.