New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ill-typed upgrades cause data-loss #2692
Comments
Hmm, for consistency, I wonder if we should just live with this but make the future static checker warn on lossy re-typing of stable vars. |
Ouch, yeah. It's really overdue that we implement this upgrade check! |
Yeah, but it's not entirely clear to me what to check.
I think 1) is probably the way to go, since we have most of the machinery already and just need to extend candid a bit. |
Another question is where to store this info. In a separate file, in a custom section or in the wasm binary as an additonal query method as Joachim hacked up for the (external) Candid interface. The latter actually has some appeal. |
Hi Claudio, has there been any progress on this issue? I recently lost some state due to this, would be good to prevent this from happening to others! |
Still no progress ? What do you suggest to prevent data loss while we wait for a clean solution ? |
PR #2887 (not yet merged) adds some support for manually checking compatibility of stable signatures using moc. Roughly,
You can use tool didc to check that the dids are compatible
The separate What remains is integrating this with the replica and dfx to prevent an unsafe ugrade, but that's still underway and may take a while. I'm also working on some informal examples to explain what is allowed and what isn't #2897. The basic rules for stable-compatible are that you can evolve
The Candid interfaces can evolve to a Candid subtype (note the inversion of the relation), so that old clients can use the new interface without breaking. In practice, with the current implementation, one can safely change the mutability of a stable variable in an upgrade and drop an existing stable variable, but we have decided to error on those cases for now (but might only warn in future). |
#2887 is merged. Shall we close this? |
The replica change is still not in production, but we can close this, as it's a motoko issue. |
Doing an ill-typed upgrade can cause stable data loss.
The problem is the recent change to candid to support defaulting of optional fields.
Motoko encodes stable variables in a record of options.
Doing an upgrade to an incompatible type will cause those optional fields to default to null, discarding any data those fields might have held (and just running the initializer instead).
A conformance check prior to upgrade could warn about this potential data loss, but absent tooling for that, we are in the situation where users can easily lose their data on upgrade by doing a simple, and natural, mistake like adding a field to stable variable of record type (or, more commonly, map thereof).
#2691 contains a repro of a sequence of ugrades that should fail but don't.
https://forum.dfinity.org/t/questions-about-data-structures-and-migrations/822/15 is a real world example of a user being tripped up by this, trying to "upgrade" a stable array of tuples containing records by adding a field.
Instead of failing the upgrade, the stable variable is regarded as uninitialized and initialized from this initializer expression (losing the data).
Solution: I briefly considered just changing the record of options encoding to a record of variants encoding for stable variables, which would be fine, but isn't backwards compatible with previously compiled code, so a non-starter.
I'll investigate whether we can just change the deserialization behaviour for "T.Memory" records to avoid the option defaulting instead.
@rossberg, @nomeata whaddya think?
Of course, we could say we really need the static check, but I think a defensive implementation is called for anyway.
The text was updated successfully, but these errors were encountered: