Issue with Index Canister, not showing any transaction history for it's respective ledger

This is the repository that has my code in rust, which I have problem with:

So, basically the flow is whenever you run my “deploy.sh”, it’ll first ask to deploy wasm of icrc2 ledger and index canister, on giving any values, the wasm are generated and I use them for later creation in icplaunchpad_backend canister.
So my issue is that, whenever create_token is called, a two canisters are deployed. One is the token canister and other’s the index canister of that ledger. Now, I just did the process normally, created a new token, I did few transactions, and I opened my index canister candid to check the functions, just to query transaction history, and it returns NOTHING.
I checked the same in my ledger id, it’s returning the transactions I made.
But, the icrc1_balance_of and get_account_transactions these functions return null/nothing.
I’ve even double checked. But, I’m sure the index canister is deployed with the ledger id, as I’ve tried querying this function: ledger_id
and it returned my exact icrc2ledger id. I request you to please look into this, as I’ve tried all possible ways of installing the latest wasm, .did and everything. The issue keeps persisting. I really want to know where I’ve gone wrong. Please take some time to resolve this. Thank you!

1 Like

I know the index canister has an endpoint to force it to index. Have you tried calling that? Not sure if it starts a timer when you do that or not. If you’re launching them at the same time the ledger may not be ready to answer when it spins up so it waits for a command.

Also, of course, double check the ledger if is correct. I’m sure you’ve checked it but I’m pretty sure I’ve made that mistake before :smile:

Finally, check cycles? I feel like the index canister is a bit of a hungry canister And it could hit freezing if you give it too few cycles.

1 Like

I’m a bit confused - I see that you have src/token_deployer/ic-icrc1-ledger.wasm.gz, but then you also have a download_latest_icp_ledger.sh script, and a src/index_canister/index_canister.wasm.gz.

Are you trying to deploy an ICP or ICRC ledger suite? Where do you specify the init arguments when deploying the canisters, especially the one for the index, which needs to include the canister ID of the ledger it is indexing? If you are deploying an ICRC ledger+index, you should use an ic-icrc1-index-ng.wasm.gz archive (note the -ng - the “old” index is no longer supported).

EDIT: I now saw that you did query the index to get the ledger_id, so at least that sounds like it is configured correctly.

1 Like

Hey @skilesare
I don’t see any endpoint to force it to index, can you give more context there?
Yea, the ledger id is perfect. I coded it actually. So, my code creates a new canister with icrc2 ledger, and after the canister id is returned, I created another canister- index canister passing the above ledger, so there are no mistakes in ledger id (as I’ve tried querying the function: ledger id in index canister and no mistakes there as well.)
Also, regarding cycles, this is just local deployment of all, and I did check cycles. I have enough and didn’t get a out of cycles error anywhere like I said I performed many transactions in the ledger so.

I’m so sorry for that confusion. That download icp ledger script for some other purpose. It’s not included in the issue I’m facing right now. The ICRC ledger suite is what I’m deploying now.
Basically, with the help of create canister, we’re making the user launch their own token, and it’s respective index canister. The only issue I’m facing is, I can’t use any endpoints of index canister except the ledger id endpoint- which returns me the perfect icrc ledger canister id, but the rest are null.
I believe the code below can help you with some context:
async fn create_canister(
arg: CreateCanisterArgument, // cycles: u128,
) → CallResult<(CanisterIdRecord,)> {
let extended_arg = CreateCanisterArgumentExtended {
settings: arg.settings,
sender_canister_version: Some(canister_version()),
};
let cycles: u128 = 100_000_000_000;

call_with_payment128(
    Principal::management_canister(),
    "create_canister",
    (extended_arg,),
    cycles,
)
.await

}

async fn deposit_cycles(arg: CanisterIdRecord, cycles: u128) → CallResult<()> {
call_with_payment128(
Principal::management_canister(),
“deposit_cycles”,
(arg,),
cycles,
)
.await
}

async fn install_code(arg: InstallCodeArgument, wasm_module: Vec) → CallResult<()> {
let cycles: u128 = 10_000_000_000;

let extended_arg = InstallCodeArgumentExtended {
    mode: arg.mode,
    canister_id: arg.canister_id,
    wasm_module: WasmModule::from(wasm_module),
    arg: arg.arg,
    sender_canister_version: Some(canister_version()),
};

call_with_payment128(
    Principal::management_canister(),
    "install_code",
    (extended_arg,),
    cycles,
)
.await

}

async fn index_install_code(arg: IndexInstallCodeArgument, wasm_module: Vec) → CallResult<()> {
let cycles: u128 = 10_000_000_000;

let extended_arg = IndexInstallCodeArgumentExtended {
    mode: arg.mode,
    arg: arg.arg,
    canister_id: arg.canister_id,
    wasm_module: WasmModule::from(wasm_module),
    sender_canister_version: Some(canister_version()),
};

call_with_payment128(
    Principal::management_canister(),
    "install_code",
    (extended_arg,),
    cycles,
)
.await

}

#[derive(CandidType, Deserialize, Serialize, Debug)]
pub struct TokenCreationResult {
pub ledger_canister_id: Principal,
pub index_canister_id: Principal,
}

#[ic_cdk::update]
pub async fn create_token(user_params: UserInputParams) → Result<TokenCreationResult, String> {

let arg = CreateCanisterArgument { settings: None };

// Create ledger canister
let (canister_id,) = match create_canister(arg.clone()).await {
    Ok(id) => id,
    Err((_, err_string)) => {
        ic_cdk::println!("error in canister id");
        return Err(format!("Error: {}", err_string));
    }
};

// Create index canister
let (index_canister_id,) = match create_canister(arg.clone()).await {
    Ok(id) => id,
    Err((_, err_string)) => {
        ic_cdk::println!("error in canister id");
        return Err(format!("Error: {}", err_string));
    }
};

let _addcycles = deposit_cycles(canister_id, 150_000_000_000).await.unwrap();
let _addcycles_index = deposit_cycles(index_canister_id, 100_000_000_000).await.unwrap();
let canister_id_principal = canister_id.canister_id;
let index_canister_id_principal = index_canister_id.canister_id;

let minting_account = params::MINTING_ACCOUNT.lock().unwrap().clone().map_err(|e| e.to_string())?;

// Handle potential error from FEE_COLLECTOR_ACCOUNT
let fee_collector_account = params::FEE_COLLECTOR_ACCOUNT.lock().unwrap().clone().map_err(|e| e.to_string())?;

// Handle potential error from ARCHIVE_OPTIONS
let archive_options = params::ARCHIVE_OPTIONS.lock().unwrap().clone().map_err(|e| e.to_string())?;


// Ledger Init Args
let init_args = LedgerArg::Init(InitArgs {
    minting_account, // Hardcoded value from params.rs
    fee_collector_account: Some(fee_collector_account), // Hardcoded value from params.rs
    transfer_fee: params::TRANSFER_FEE.clone(), // Hardcoded value
    decimals: user_params.decimals, // User-supplied value
    max_memo_length: Some(params::MAX_MEMO_LENGTH), // Hardcoded value
    token_symbol: user_params.token_symbol.clone(),  // User-supplied value
    token_name: user_params.token_name.clone(),  // User-supplied value
    metadata: vec![], // Empty or pre-defined metadata if needed
    initial_balances: user_params.initial_balances, // User-supplied value
    feature_flags: Some(params::FEATURE_FLAGS), // Hardcoded value
    maximum_number_of_accounts: Some(params::MAXIMUM_NUMBER_OF_ACCOUNTS), // Hardcoded value
    accounts_overflow_trim_quantity: Some(params::ACCOUNTS_OVERFLOW_TRIM_QUANTITY), // Hardcoded value
    archive_options, // Hardcoded value from params.rs
});

let init_arg: Vec<u8> = encode_one(init_args).map_err(|e| e.to_string())?;

let wasm_module =
    include_bytes!("../../../.dfx/local/canisters/token_deployer/token_deployer.wasm.gz")
        .to_vec();
let index_wasm_module =
    include_bytes!("../../../.dfx/local/canisters/index_canister/index_canister.wasm.gz")
        .to_vec();

let arg1: InstallCodeArgument = InstallCodeArgument {
    mode: CanisterInstallMode::Install,
    canister_id: canister_id_principal,
    wasm_module: WasmModule::from(wasm_module.clone()),
    arg: init_arg.clone(),
};

// Index Init Args
let index_init_args = IndexInitArgs {
    ledger_id: canister_id_principal,
};
let index_init_arg: Vec<u8> = encode_one(index_init_args).map_err(|e| e.to_string())?;

let arg2: IndexInstallCodeArgument = IndexInstallCodeArgument {
    mode: CanisterInstallMode::Install,
    canister_id: index_canister_id_principal,
    wasm_module: WasmModule::from(index_wasm_module.clone()),
    arg: index_init_arg,
};

// Install code for the ledger canister
match install_code(arg1.clone(), wasm_module).await {
Ok(_) => {
    mutate_state(|state| {
        state.canister_ids.insert(canister_id_principal.to_string(), CanisterIdWrapper {
            canister_ids: canister_id_principal,
            token_name: user_params.token_name.clone(),  // Store token name
            token_symbol: user_params.token_symbol.clone(),  // Store token symbol
            image_id: None,  // Set image_id as None for now
            ledger_id: Some(canister_id_principal),  // Set ledger_id to the canister ID
        });
    });
}
Err((code, msg)) => {
    ic_cdk::println!("Error installing code: {} - {}", code as u8, msg);
    return Err(format!("Error installing code: {} - {}", code as u8, msg));
}

}

// Install code for the index canister
match index_install_code(arg2, index_wasm_module).await {
Ok(_) => {
mutate_state(|state| {
state.index_canister_ids.insert(
index_canister_id_principal.to_string(),
IndexCanisterIdWrapper {
index_canister_ids: index_canister_id_principal,
},
)
});

    Ok(TokenCreationResult {
        ledger_canister_id: canister_id_principal,
        index_canister_id: index_canister_id_principal,
    })
}
Err((code, msg)) => {
    Err(format!("Error installing index code: {} - {}", code as u8, msg))
}

}
}

There are two index canisters. Do you have the right one for the ledger you are deploying?

See: Index canisters | Internet Computer

I could not find the update call I remembered. It must have been an old version or I’m misrembering.

1 Like

@skilesare The wasm and .did links are access denied links, and I’ve just noticed that on using those curl commands to download my wasm and .did, I just found out there’s an optional init argument that index canister takes:
type InitArg = record {
ledger_id: principal;
retrieve_blocks_from_ledger_interval_seconds : opt nat64;
};

I’m trying by including this in my code, by passing some seconds there. Hopefully I resolve the issue.

UPDATE:

I solved it!!!
It’s the init arguments only. I think they’ve updated the canister, and somehow I haven’t noticed.
Checked the .did file, found this new argument they’re passing,
let index_init_args = IndexInitArgs {
ledger_id: canister_id_principal, // Ledger canister ID
retrieve_blocks_from_ledger_interval_seconds: Some(10), // 10 seconds
};

and apparently:
// The interval in seconds in which to retrieve blocks from the ledger. A lower value makes the index more
// responsive in showing new blocks, but increases the consumption of cycles of both the index and ledger canisters.
// A higher values means that it takes longer for new blocks to show up in the index.

So, I gave initially 600 seconds, which failed, blocks didn’t sync.
But then, switched to 10 seconds, and it did work!!!
Also I just wanted to ask, is there a way for me to raise any query to change the docs here:
https://internetcomputer.org/docs/current/developer-docs/defi/tokens/indexes

It’d be really helpful for someone who’s also using index canister and is stuck with it not working.

1 Like

Ping @Jessie Looks like the link wants you to plug in an IC Version. It would be nice if the docs did that for you to the latest stable build so the link works.

I think that is new! I wonder what the default was. Should save a ton of cycles.

1 Like

Great that you managed to figure it out, and thanks for posting your solution, @Ray04 ! I’ll look into this in more detail - at first glance, I couldn’t spot an issue where omitting the new, optional parameter, or setting a large value (600s) would result in the index not syncing at all, but I may have missed something.

@skilesare The original fixed value, as well as the current default, is 1 second.

1 Like