Skip to content

Trouble with mutation #545

@msaaltink

Description

@msaaltink

Consider this program:

module update::update;

use sui::object_table::ObjectTable;
use prover::prover::{asserts, ensures, forall, requires};

public struct S has store, key {id: UID, x: u8, y: u8}

fun update_part(s: &mut S) { s.y = 0 }

#[spec(prove)]
fun update_part_spec(s: &mut S) {
    update_part(s);
}

#[spec(prove, focus)]
fun framing(i: ID, j: ID, t: &mut ObjectTable<ID, S>) {
    requires(t.contains(i));
    requires(t.contains(j));
    requires(i != j);
    let x0 = t[j].x;
    update_part(&mut t[i]);
    ensures(t[j].x == x0);
}

The sui-prover does not prove this:

error: prover::ensures does not hold
   ┌─ ./sources/update.move:22:5
   │
22 │     ensures(t[j].x == x0);
   │     ^^^^^^^^^^^^^^^^^^^^^
   │
   =     at ./sources/update.move:16: framing
   =         i = object.ID{bytes = 0x14}
   =         j = object.ID{bytes = 0x3e}
   =         t =
   =           object_table.ObjectTable{
   =             id = object.UID{id = <? Literal("33")>},
   =             size =
   =               <? List([Literal("Table_23490_49924"), List([Literal("_"), List([Literal("as-array")]), List([Literal("k!19")])]), List([Literal("_"), List([Literal("as-array")]), List([Literal("k!14")])]), Literal("1")])>}
   =     at ./sources/update.move:17: framing
   =         x0#1#0 = 0u8
   =     at ./sources/update.move:21: framing
   =         s =
   =           update.S{id = object.UID{id = <? Literal("24")>}, x = 0u8, y = 0u8}
   =     at ./sources/update.move:12: update_part_spec
   =         s =
   =           update.S{id = object.UID{id = <? Literal("23")>}, x = 1u8, y = 0u8}
   =     at ./sources/update.move:21: framing
   =         t =
   =           object_table.ObjectTable{
   =             id = object.UID{id = <? Literal("33")>},
   =             size =
   =               <? List([Literal("Table_23490_49924"), List([Literal("_"), List([Literal("as-array")]), List([Literal("k!15")])]), List([Literal("_"), List([Literal("as-array")]), List([Literal("k!14")])]), Literal("1")])>}
   =     at ./sources/update.move:22: framing

although it does prove it if the specification of update_part is removed. Comparing the BPL in those two cases, the only significant difference is in

procedure {:inline 1} $0_update_update_part(_$t0: $Mutation ($0_update_S)) returns ($ret0: $Mutation ($0_update_S))

which has the same signature in both cases.

With no spec:

$t2 := $ChildMutation($t0, 2, $Dereference($t0)->$y);
$t2 := $UpdateMutation($t2, 0);
$ret0 := $UpdateMutation($t0, $Update'$0_update_S'_y($Dereference($t0), $Dereference($t2)));

with specs:

$ret0 := $0_update_update_part$opaque($t0);

which returns an arbitrary $Mutation ($0_update_S)).

The caller uses that result as follows:

call $t12 := $0_update_update_part($t12);
// write_back[Reference($t2).size (u64)/[]]($t12) at ./sources/update.move:21:5+22
$t2 := $UpdateMutation($t2, (var $$sel0 := $Dereference($t2)->$contents; $Update'$2_object_table_ObjectTable'$2_object_ID_$0_update_S''_contents($Dereference($t2), UpdateTable($$sel0, ReadVec($t12->p, LenVec($t2->p) + 1), $Dereference($t12)))));

So I believe there is a problem here: $t12->p is used to update the table, but in the result of the call with a specification, that is completely undetermined (while with no specification, the path is retained from the input parameter). Shouldn't the opaque result be constrained to have the same path as the input?

Here's a simpler example (now that I think I understand the issue):

fun set(x: &mut u8) { *x = 0 }
#[spec(prove)]
fun set_spec(x: &mut u8) {
    set(x)
}

#[spec(prove, focus)]
fun frame(v: &mut vector<u8>, i: u64, j: u64) {
    requires(j < v.length());
    requires(i < j);
    let vj = v[j];
    set(&mut v[i]);
    ensures(v[j] == vj);
}

Again, this can be proved when the spec of set is removed, but the proof fails with a counterexample when the spec is in place.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions