SNS Governance - Neuron Disbursement Testing

I’m implementing integration tests using PocketIC and attempting to test neuron maturity disbursement. Instead of setting up the entire SNS, I installed only the governance canister with a valid ledger canister.

Here are the parameters used to install the governance canister:

Governance {
    deployed_version: None,
    neurons: neuron_data_with_neuron_keys,
    proposals: BTreeMap::new(),
    parameters: Some(NervousSystemParameters {
        default_followees: Some(DefaultFollowees { followees: BTreeMap::new() }),
        reject_cost_e8s: Some(10000u64),
        neuron_minimum_stake_e8s: Some(20000u64),
        transaction_fee_e8s: Some(10000u64),
        max_proposals_to_keep_per_action: Some(10),
        initial_voting_period_seconds: Some(2591000),
        wait_for_quiet_deadline_increase_seconds: Some(60 * 60),
        max_number_of_neurons: Some(1000u64),
        neuron_minimum_dissolve_delay_to_vote_seconds: Some(1u64),
        max_followees_per_function: Some(10),
        max_dissolve_delay_seconds: Some(10000000u64),
        max_neuron_age_for_age_bonus: Some(10000000),
        max_number_of_proposals_with_ballots: Some(100u64),
        neuron_claimer_permissions: Some(NeuronPermissionList {
            permissions: vec![1, 2, 3, 4, 5, 6, 7, 8, 9],
        }),
        neuron_grantable_permissions: Some(NeuronPermissionList {
            permissions: vec![1, 2, 3, 4, 5, 6, 7, 8, 9],
        }),
        max_number_of_principals_per_neuron: Some(10),
        voting_rewards_parameters: Some(VotingRewardsParameters {
            round_duration_seconds: Some(1000),
            reward_rate_transition_duration_seconds: Some(100),
            initial_reward_rate_basis_points: Some(5),
            final_reward_rate_basis_points: Some(5),
        }),
        max_dissolve_delay_bonus_percentage: Some(10u64),
        max_age_bonus_percentage: Some(10u64),
        maturity_modulation_disabled: Some(true),
    }),
    latest_reward_event: None,
    in_flight_commands: BTreeMap::new(),
    genesis_timestamp_seconds: 1713271942u64,
    ledger_canister_id: Some(sns_ledger_canister_id.clone()),
    root_canister_id: Some(sns_root_canister_id.clone()),
    id_to_nervous_system_functions: BTreeMap::new(),
    mode: 1,
    swap_canister_id: Some(sns_swap_canister_id.clone()),
    sns_metadata: Some(SnsMetadata {
        logo: None,
        url: Some("https://simgov.simgov".to_string()),
        name: Some("Simulation Gov".to_string()),
        description: Some("Simulation Gov desc".to_string()),
    }),
    sns_initialization_parameters: "".to_string(),
    pending_version: None,
    is_finalizing_disburse_maturity: None,
    maturity_modulation: None,
}

I also simulated the neuron maturity obtaining with reinstalling the canister with changed neuron parameters.
After running the test, I got the following neuron response:

neurons: Response { neurons: NeuronList { ogy_neurons: [], wtn_neurons: [Neuron {
    id: Some(NeuronId { id: [...] }),
    permissions: [NeuronPermission { principal: Some(Principal { bytes: [...] }), permission_type: [1, 2, 3, 4, 5, 6, 7, 8, 9] }],
    cached_neuron_stake_e8s: 20000,
    neuron_fees_e8s: 0,
    created_timestamp_seconds: 1713271942,
    aging_since_timestamp_seconds: 1713271942,
    followees: {},
    maturity_e8s_equivalent: 0,
    voting_power_percentage_multiplier: 1,
    source_nns_neuron_id: None,
    staked_maturity_e8s_equivalent: None,
    auto_stake_maturity: Some(false),
    vesting_period_seconds: Some(100000),
    disburse_maturity_in_progress: [DisburseMaturityInProgress {
        amount_e8s: 500000,
        timestamp_of_disbursement_seconds: 1713476194,
        account_to_disburse_to: Some(Account { owner: Some(Principal { bytes: [...] }) })
    }],
    dissolve_state: None
}]} }

The neuron has DisburseMaturityInProgress , and the timestamp is 1713476194 . However, despite advancing time in PocketIC, the disbursement event never triggers.

For reliability, I decided to create a test where the entire SNS initialization occurs, but it takes some time. However, if there is a faster solution, that would be great.

Has anyone encountered this issue before? Is there something missing in my governance setup, or is additional configuration required for maturity disbursement to complete successfully in PocketIC? I would appreciate any ideas on this!

2 Likes

Hi @VictoriaGrasshopper,

Note that PocketIC does not automatically “tick” when time progresses, i.e., new ICP blocks are produced only when you also call pocket_ic.tick() in addition to pocket_ic.advance_time(...). Could this be the missing step?

You might need multiple ticks to get the periodic tasks executed enough times so that the expected effect takes place. To simplify the awaiting logic, take a look at the await_with_timeout helper function (it allows the programmer to abstract a little bit more and not think it terms of individual ICP blocks while specifying test scenarios), maybe that’s something you could use in your setup.

Otherwise, I’d recommend sharing the code of your PocketIC-based test so that someone can take a closer look.

2 Likes

Thank you for your prompt response!

I have reworked the entire test setup structure and, just in case, added multiple ticks, as you suggested. I also found a couple of mistakes in the canister itself, so in the end, everything worked out

Lots of thanks!

Great — glad to hear firsthand success stories such as this. Keep rocking!

1 Like