State Migration Error

Hi, so there’s a problem with migration:
We trying to migrate state structure with one additional argument.
We’ve used examples for migration, but our state derives HasStateApi to store StateMap inside. So, we have generic with trait bounds and such simple example doesn’t works for us.
We have problems with using read_root() function:

let state: OldState<S> = host.state().read_root()?;

so it requires to use trait bounds in migration function:

fn contract_migration<S: HasStateApi>

but it fails with such an error:

1216 |     let state: &OldState<S> = host.state().read_root()?;
     |                                            ^^^^^^^^^ the trait `Deserial` is not implemented for `&OldState<S>`

     = note: required for `&OldState<S>` to implement `concordium_std::DeserialWithState<concordium_std::ExternStateApi>`

But our OldState struct literally looks like:

#[derive(Debug, Serial, DeserialWithState)]
#[concordium(state_parameter = "S")]
pub struct OldState<S: HasStateApi> {

Is there any solutions for this?

1 Like

Hi Rocky_raccoon,
you can avoid using the trait bounds in the migration function as follows, I think:

/// The smart contract state.
#[derive(Debug, Serial, DeserialWithState)]
#[concordium(state_parameter = "S")]
pub struct State<S: HasStateApi = StateApi> {
    ...
}

/// The old smart contract state from `contract-version1`.
#[derive(Debug, Serial, DeserialWithState)]
#[concordium(state_parameter = "S")]
pub struct OldState<S: HasStateApi = StateApi> {
   ...
}

#[receive(
    contract = "smart_contract_upgrade",
    name = "migration",
    error = "CustomContractError",
    low_level
)]
fn contract_migration(ctx: &ReceiveContext, host: &mut LowLevelHost) -> ContractResult<()> {

    // Read the old top-level contract state.
    let state: OldState = host.state().read_root()?;

    ...

    host.state_mut().write_root(&new_state);
    host.commit_state();
    Ok(())
}
1 Like